diff --git a/resources/wiki/filament_group_wiki_zh.html b/resources/wiki/filament_group_wiki_zh.html new file mode 100644 index 0000000000..be5cf83087 --- /dev/null +++ b/resources/wiki/filament_group_wiki_zh.html @@ -0,0 +1,599 @@ + + + + + + + +
+

1.背景

单挤出机(热端)打印机在切换不同耗材进行打印时,需要对耗材进行冲刷,用一定量的新耗材去冲刷掉热端中残留的旧耗材,避免打印混色。不同耗材间的冲刷量不一样,具体的值可以在Bambu Studio的冲刷页面查看。您可以参考wiki:减少多色打印时的耗材浪费

对于像H2D这种双挤出机(热端)的打印机来说,打印两种耗材时最优的方式就是用不同挤出机打印不同的耗材,因为这种情况下耗材之间的切换仅仅需要切换挤出机,而不需要用新耗材冲刷旧耗材。而打印超过两种耗材的情况,同样可以通过切换挤出机打印来减少耗材冲刷次数。本文将介绍针对双挤出机打印机的耗材分配策略,以实现最省料或最便捷的多耗材打印方式。

2.多色打印顺序

单层内,不同的颜色打印顺序会导致换料次序不同,从而导致换料产生的耗材总冲刷量也有差异。切片软件会根据耗材间彼此的冲刷量,计算出一个最优的打印顺序,使得模型冲刷的损耗量最低。比如,耗材丝打印顺序 1->2->3 的总冲刷量大于 1->3->2 的总冲刷量,就会使用后者作为该层的打印顺序。如果您想要手动调整打印排序,详细内容可以参考:设置不同层耗材打印顺序

img

img

imgimg

 

3.省料模式(可能需要调整AMS中的耗材摆放位置)

由于不同挤出机之间的耗材切换无需冲刷,所以整个模型的冲刷量都来自同一个挤出机的耗材间的切换。为了最小化换料时冲刷的耗材消耗,我们应该尽可能将两者间冲刷量较大的耗材放于不同挤出机,也就是将打印使用到的耗材按照两个挤出机进行分组。Bambu Studio中默认采用的耗材分配策略,就是省料模式。您可以在切片按钮的悬浮窗中看到共有3种模式,选择“省料模式”并点击切片,即可获得最省耗材耗材分配方案。下文将简要介绍该分配策略的逻辑。

img

由于挤出机的物理限制,不同挤出机有各自的可打印区域限制(H2D双喷嘴可打印范围介绍)。如下图所示,当模型内需要使用某耗材打印的部分,被放置到仅左喷嘴或仅右喷嘴可打印区域时,那么这个耗材只用对应的喷嘴打印。

img

当连接上打印机后,我们能够得知每个挤出机的连接的AMS数量。当无AMS连接打印机时,我们默认该挤出机可以通过外挂料盘放置一个耗材,这样就能够在切片时计算每个喷嘴可以分配的耗材数量上限。

img

在满足上述限制后,切片软件会计算出一个最佳的耗材分组,保证在这种分组下,按照计算出的打印顺序,能够获得最小的冲刷量损耗。原理是尽可能让共同出现的层数较多(需要来回切换的次数更多)、换料冲刷量较大的耗材分到不同的挤出机组中。

综上所述,省料模式的分组算法主要需要考虑以下几点,每个点的优先级按照次序降低:

  1. 挤出机的不可打印耗材限制;

  2. 挤出机可分配打印的耗材上限;

  3. 最小化耗材冲刷损耗;

  4. 最小化到打印机连接AMS中耗材的色彩差距;

由于该分组逻辑更倾向于减少耗材冲刷量而不是颜色最接近,故在切片后,用户需要根据“耗材摆放推荐”,检查是否把耗材丝都放入对应左右挤出机连接的AMS中,若耗材实际摆放位置与软件推荐的不同,需要适当调整。否则有可能会在发送打印任务的窗口中无法选择为挤出机自动分配的耗材丝。

如下动图所示,一旦切片的耗材丝被分配到了特定的挤出机中,则在发送任务时无法强行将其更改为另一个挤出机中的耗材,即使另一挤出机连接的AMS中有更接近颜色的耗材也无法手动匹配。所以只能先手动调整耗材在AMS中摆放的位置,来实现最省料的打印。

img

 

4.便捷模式(不需要调整AMS中的耗材)

不同于最省料的分组策略,便捷模式完全基于打印机中摆放的耗材进行分组规划,与模型无关。在这种策略下,会尽可能让耗材分配结果与AMS中摆放的耗材尽可能相匹配(颜色、类型等)。该选项更倾向于根据用户现有的耗材摆放方式,进行分组规划。故可能会浪费更多的耗材用于冲刷,但无需额外调整耗材的摆放顺序。适合用户不在打印机旁,远程发起多耗材打印的场景。我们建议您在使用该策略之前,先在耗材丝列表里重新同步一次AMS的耗材信息。你可以在切片按钮的悬浮窗里选择“便捷模式”,则会根据您当前AMS中实际摆放的耗材对切片耗材进行分组,然后再进行切片。切片后可以看到最优分组(最省料)方案与最便捷分组方案相比,多节省的耗材量和换料次数。

img

便捷模式的分组算法主要考虑以下几点,每个点的优先级按次序降低:

  1. 挤出机的不可打印耗材限制;

  2. 打印耗材类型一致性限制;

  3. 最小化到挤出机连接AMS中耗材的色彩差距;

 

5.手动模式

如果您对自动耗材分组策略不满意,可以在“耗材摆放推荐”中点击“耗材分组”,然后在“自定义”中手动调整左右挤出机中的耗材,再次切片后可以看到最优分组(最省料)方式与手动设置的耗材分组相比,多节省的耗材量和换料次数。注:最省料的分组策略仅考虑节省耗材,故有时候会出现更省料但换料次数比自定义的分组更多的情况,这是正常的现象。

img

你也可以直接在切片按钮的悬浮窗里选择“手动模式”,则在切片前会先让你自定义给左右挤出机分配切片的耗材,然后再进行切片。

img img
  

img

 

6.盘参数与全局参数

针对不同场景,耗材的分配策略分成了不同层级的参数:盘参数与全局参数。在实际切片时,若您为某个盘设置了耗材分配策略,那么盘参数会覆盖全局参数。

在每个打印盘的右侧,点击对应图标后会有个弹窗,可以看到当前盘使用的耗材分配策略。您可以为单盘设置耗材分配策略,包含上文中提到的自动(省料模式和便捷模式)、自定义(手动模式)和缺省(跟随全局设置)。

img

img

img

若你为某盘单独设置了耗材分配策略,则在切片单盘后,切片按钮处的浮窗与弹窗中会优先显示当前盘上的分组策略,不过会有个全局设置的图标放置在对应的模式后面,提醒用户全局切片用的是哪种耗材分组策略。若未为单盘单独设置模式,则浮窗与弹窗会优先显示全局的分组策略。

img

在切片所有盘时,总是显示全局的耗材分配策略,以方便为所有盘进行设置,不过为单盘设置的耗材分配方式依然生效。

img

在手动模式的耗材分配窗口中,切片单盘时仅显示当前盘里会用到的耗材,切片所有盘时才会显示该项目用到的所有耗材。

切片单盘切片所有盘
img img
+ + \ No newline at end of file diff --git a/src/slic3r/GUI/FilamentGroupPopup.cpp b/src/slic3r/GUI/FilamentGroupPopup.cpp index 387cddef1b..cec63ce4e8 100644 --- a/src/slic3r/GUI/FilamentGroupPopup.cpp +++ b/src/slic3r/GUI/FilamentGroupPopup.cpp @@ -51,13 +51,12 @@ FilamentGroupPopup::FilamentGroupPopup(wxWindow *parent) : PopupWindow(parent, w { const wxString AutoForFlushLabel = _L("Filament-Saving Mode"); const wxString AutoForMatchLabel = _L("Convenient Mode"); - const wxString ManualLabel = _L("Manual Mode"); + const wxString ManualLabel = _L("Custom Mode"); - const wxString AutoForFlushDetail = _L("Calculate the best filament arrangement " - "to minimize usage. Need to manually arrange filaments on the printer " + const wxString AutoForFlushDetail = _L("Calculate the best filament grouping " + "to minimize filament waste. Need to manually place filaments on the printer " "based on slicing results."); - const wxString AutoForMatchDetail = _L("Use AMS filaments to automatically assign filament " - "to the left or right nozzle."); + const wxString AutoForMatchDetail = _L("Calculate the filament grouping based on the printer's filaments, reducing the need for adjusting filaments at the printer."); const wxString ManualDetail = _L("Manually assign filament to the left or right nozzle."); const wxString AutoForFlushDesp = ""; //_L("(Post-slicing arrangement)"); @@ -145,13 +144,15 @@ FilamentGroupPopup::FilamentGroupPopup(wxWindow *parent) : PopupWindow(parent, w { wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL); + const std::string wiki_path = Slic3r::resources_dir() + "/wiki/filament_group_wiki_zh.html"; + auto* wiki_sizer = new wxBoxSizer(wxHORIZONTAL); wiki_link = new wxStaticText(this, wxID_ANY, _L("Learn more")); wiki_link->SetBackgroundColour(BackGroundColor); wiki_link->SetForegroundColour(GreenColor); wiki_link->SetFont(Label::Body_12.Underlined()); wiki_link->SetCursor(wxCursor(wxCURSOR_HAND)); - wiki_link->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent &) { wxLaunchDefaultBrowser("http//:example.com"); }); + wiki_link->Bind(wxEVT_LEFT_DOWN, [wiki_path](wxMouseEvent &) { wxLaunchDefaultBrowser(wxString(wiki_path.c_str())); }); wiki_sizer->Add(wiki_link, 0, wxALIGN_CENTER | wxALL, FromDIP(3)); button_sizer->Add(wiki_sizer, 0, wxLEFT, horizontal_margin); diff --git a/src/slic3r/GUI/FilamentMapDialog.cpp b/src/slic3r/GUI/FilamentMapDialog.cpp index 991ce1a460..31703642f5 100644 --- a/src/slic3r/GUI/FilamentMapDialog.cpp +++ b/src/slic3r/GUI/FilamentMapDialog.cpp @@ -116,7 +116,7 @@ FilamentMapDialog::FilamentMapDialog(wxWindow *parent, bool machine_synced, bool show_default, bool with_checkbox) - : wxDialog(parent, wxID_ANY, _L("Filament arrangement"), wxDefaultPosition, wxDefaultSize,wxDEFAULT_DIALOG_STYLE), m_filament_color(filament_color), m_filament_map(filament_map) + : wxDialog(parent, wxID_ANY, _L("Filament grouping"), wxDefaultPosition, wxDefaultSize,wxDEFAULT_DIALOG_STYLE), m_filament_color(filament_color), m_filament_map(filament_map) { SetBackgroundColour(*wxWHITE); diff --git a/src/slic3r/GUI/FilamentMapPanel.cpp b/src/slic3r/GUI/FilamentMapPanel.cpp index 33762bbf31..b16beaca8d 100644 --- a/src/slic3r/GUI/FilamentMapPanel.cpp +++ b/src/slic3r/GUI/FilamentMapPanel.cpp @@ -56,7 +56,7 @@ FilamentMapManualPanel::FilamentMapManualPanel(wxWindow *p top_sizer->Add(drag_sizer, 0, wxALIGN_CENTER | wxEXPAND); m_tips = new Label(this, _L("Tips: You can drag the filaments to reassign them to different nozzles.\n" - "But your filament arrangement may not be the most efficient for filament usage.")); + "But your filament grouping may not be the most efficient for filament usage.")); m_tips->SetFont(Label::Body_14); m_tips->SetForegroundColour(TextNormalGreyColor); top_sizer->AddSpacer(FromDIP(8)); @@ -273,11 +273,10 @@ void GUI::FilamentMapBtnPanel::Show() FilamentMapAutoPanel::FilamentMapAutoPanel(wxWindow *parent, FilamentMapMode mode, bool machine_synced) : wxPanel(parent) { - const wxString AutoForFlushDetail = _L("Calculate the best filament arrangement " - "to minimize usage. Need to manually arrange filaments on the printer " + const wxString AutoForFlushDetail = _L("Calculate the best filament grouping " + "to minimize filament waste. Need to manually place filaments on the printer " "based on slicing results."); - const wxString AutoForMatchDetail = _L("Use AMS filaments to automatically assign filament " - "to the left or right nozzle."); + const wxString AutoForMatchDetail = _L("Calculate the filament grouping based on the printer's filaments, reducing the need for adjusting filaments at the printer."); auto sizer = new wxBoxSizer(wxHORIZONTAL); m_flush_panel = new FilamentMapBtnPanel(this, _L("Filament-Saving Mode"), AutoForFlushDetail, "flush_mode_panel_icon"); @@ -345,7 +344,7 @@ FilamentMapDefaultPanel::FilamentMapDefaultPanel(wxWindow *parent) : wxPanel(par { auto sizer = new wxBoxSizer(wxHORIZONTAL); - m_label = new Label(this, _L("The filament arrangement for current plate follows the global settings.")); + m_label = new Label(this, _L("The filament grouping for current plate follows the global settings.")); m_label->SetFont(Label::Body_14); m_label->SetBackgroundColour(*wxWHITE); diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 66d9ee0b0c..bc0cf64210 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -4432,7 +4432,7 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding) // click behavior if (ImGui::IsMouseHoveringRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), true)) { if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { - MessageDialog msg_dlg(nullptr, _L("Automatically re-slice according to the optimal filament arrangement, and the arrangement results will be displayed after slicing."), wxEmptyString, wxOK | wxCANCEL); + MessageDialog msg_dlg(nullptr, _L("Automatically re-slice according to the optimal filament grouping, and the grouping results will be displayed after slicing."), wxEmptyString, wxOK | wxCANCEL); if (msg_dlg.ShowModal() == wxID_OK) { PartPlateList &partplate_list = wxGetApp().plater()->get_partplate_list(); PartPlate *plate = partplate_list.get_curr_plate(); @@ -4461,7 +4461,7 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding) int AMS_filament_max_num = std::max(m_left_extruder_filament.size(), m_right_extruder_filament.size()); float three_words_width = imgui.calc_text_size("ABC"sv).x; float ams_item_height = std::ceil(AMS_filament_max_num / 4.0f) * (three_words_width * 1.6f + line_height) + line_height * 2; - float AMS_container_height = ams_item_height + line_height * (has_tips ? 6 : 4); + float AMS_container_height = ams_item_height + line_height * (has_tips ? 7 : 5); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.f, 1.f, 1.f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(.15f, .18f, .19f, 1.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(window_padding * 3, 0)); @@ -4476,9 +4476,9 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding) ImGui::Dummy({window_padding, window_padding}); ImGui::PushStyleColor(ImGuiCol_Separator, ImVec4(.8f, .8f, .8f, 1.0f)); if (is_auto) - imgui.title(_u8L("Color Arrangement Recommendation")); + imgui.title(_u8L("Filament Grouping Recommendation")); else - imgui.title(_u8L("Color Arrangement")); + imgui.title(_u8L("Filament Grouping")); ImGui::PopStyleColor(); ImGui::Dummy({window_padding, window_padding}); @@ -4489,7 +4489,7 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding) child_begin_draw_list->AddRectFilled(cursor_pos, ImVec2(cursor_pos.x + half_width, cursor_pos.y + line_height), IM_COL32(0, 0, 0, 20)); ImGui::BeginChild("#LeftAMS", ImVec2(half_width, ams_item_height), false, ImGuiWindowFlags_AlwaysUseWindowPadding); { - imgui.text(_u8L("Left extruder")); + imgui.text(_u8L("Left nozzle")); ImGui::Dummy({window_padding, window_padding}); int index = 1; for (const auto &extruder_filament : m_left_extruder_filament) { @@ -4504,7 +4504,7 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding) child_begin_draw_list->AddRectFilled(cursor_pos, ImVec2(cursor_pos.x + half_width, cursor_pos.y + line_height), IM_COL32(0, 0, 0, 20)); ImGui::BeginChild("#RightAMS", ImVec2(half_width, ams_item_height), false, ImGuiWindowFlags_AlwaysUseWindowPadding); { - imgui.text(_u8L("Right extruder")); + imgui.text(_u8L("Right nozzle")); ImGui::Dummy({window_padding, window_padding}); int index = 1; for (const auto &extruder_filament : m_right_extruder_filament) { @@ -4532,8 +4532,8 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding) float saved_flush_weight = stats_by_extruder.stats_by_single_extruder.filament_flush_weight - stats_by_extruder.stats_by_multi_extruder_best.filament_flush_weight; int saved_filament_changed_time = stats_by_extruder.stats_by_single_extruder.filament_change_count - stats_by_extruder.stats_by_multi_extruder_best.filament_change_count; if (saved_flush_weight > EPSILON || saved_filament_changed_time > 0) { - imgui.text(_u8L("This arrangement would be optimal.")); - imgui.text_wrapped(from_u8((boost::format(_u8L("Save %1%g filament and %2% changes than one-extruder printer.")) % number_format(saved_flush_weight) % saved_filament_changed_time).str()), parent_width); + imgui.text(_u8L("Current grouping of slice result is optimal.")); + imgui.text_wrapped(from_u8((boost::format(_u8L("Save %1%g filament and %2% changes than one-nozzle printer.")) % number_format(saved_flush_weight) % saved_filament_changed_time).str()), parent_width); } } else if (filament_map_mode != fmmAutoForFlush) { float more_cost = stats_by_extruder.stats_by_multi_extruder_curr.filament_flush_weight - stats_by_extruder.stats_by_multi_extruder_best.filament_flush_weight; @@ -4543,19 +4543,21 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding) is_optimal_group = false; ImVec4 orangeColor = ImVec4(1.0f, 0.5f, 0.0f, 1.0f); ImGui::PushStyleColor(ImGuiCol_Text, orangeColor); - imgui.text(_u8L("This arrangement is not optimal.")); - imgui.text_wrapped(from_u8((boost::format(_u8L("Cost %1%g filament and %2% changes more than optimal arrangement.")) % number_format(more_cost) % more_time).str()), parent_width); + imgui.text(_u8L("Current grouping of slice result is not optimal.")); + imgui.text_wrapped(from_u8((boost::format(_u8L("Cost %1%g filament and %2% changes more than optimal grouping.")) % number_format(more_cost) % more_time).str()), parent_width); ImGui::PopStyleColor(1); } else { float saved_flush_weight = stats_by_extruder.stats_by_single_extruder.filament_flush_weight - stats_by_extruder.stats_by_multi_extruder_best.filament_flush_weight; int saved_filament_changed_time = stats_by_extruder.stats_by_single_extruder.filament_change_count - stats_by_extruder.stats_by_multi_extruder_best.filament_change_count; if (saved_flush_weight > EPSILON || saved_filament_changed_time > 0) { - imgui.text(_u8L("This arrangement would be optimal.")); - imgui.text_wrapped(from_u8((boost::format(_u8L("Save %1%g filament and %2% changes than one-extruder printer.")) % number_format(saved_flush_weight) % saved_filament_changed_time).str()), parent_width); + imgui.text(_u8L("Current grouping of slice result is optimal.")); + imgui.text_wrapped(from_u8((boost::format(_u8L("Save %1%g filament and %2% changes than one-nozzle printer.")) % number_format(saved_flush_weight) % saved_filament_changed_time).str()), parent_width); } } } + imgui.text_wrapped(from_u8(_u8L("Please place the filaments on the printer as recommended.")), parent_width); + ImGui::Dummy({window_padding, window_padding}); if (!is_optimal_group) { link_text_set_to_optional(_u8L("Set to Optimal")); @@ -4563,7 +4565,7 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding) ImGui::Dummy({window_padding, window_padding}); ImGui::SameLine(); } - link_text(_u8L("Rearrange filament")); + link_text(_u8L("Regroup filament")); ImGui::EndChild(); } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c1f1e2d075..5a7d5067c0 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1448,15 +1448,7 @@ static std::pair construct_extruder_unprintable_error(ObjectFilament model_prefix = (boost::format(_u8L("The model %s is")) % object_result.object_filaments.front().object->name).str(); tips[idx] += model_prefix; tips[idx] += (boost::format(_u8L(" located within the %s only area, making it impossible to print with the filaments assigned to %s.\n" - "Please move the model out of the %s only area or adjust the filament assignment.")) % opposite_nozzle_name % nozzle_name % opposite_nozzle_name).str(); - - if (object_result.object_filaments.size() > 1) { - for (ObjectFilamentInfo& object_filament : left_unprintable_objects) - { - tips[idx] += object_filament.object->name; - tips[idx] += "\n"; - } - } + "Please move the model out of the %s only area or adjust the filament assignment.\n")) % opposite_nozzle_name % nozzle_name % opposite_nozzle_name).str(); output_text = tips[idx]; } diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 85c88f1e2c..d16654ef13 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -1276,10 +1276,10 @@ wxWindow* PreferencesDialog::create_general_page() #endif #if 0 - auto title_filament_group = create_item_title(_L("Filament Arrange"), page, _L("Filament Arrange")); + auto title_filament_group = create_item_title(_L("Filament Grouping"), page, _L("Filament Grouping")); //temporarily disable it //auto item_ignore_ext_filament = create_item_checkbox(_L("Ignore ext filament when auto grouping"), page, _L("Ignore ext filament when auto grouping"), 50, "ignore_ext_filament_when_group"); - auto item_pop_up_filament_map_dialog = create_item_checkbox(_L("Pop up to select filament arrangement mode"), page, _L("Pop up to select filament arrangement mode"), 50, "pop_up_filament_map_dialog"); + auto item_pop_up_filament_map_dialog = create_item_checkbox(_L("Pop up to select filament grouping mode"), page, _L("Pop up to select filament grouping mode"), 50, "pop_up_filament_map_dialog"); #endif auto title_develop_mode = create_item_title(_L("Develop mode"), page, _L("Develop mode")); diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index f19fad716d..c7f6b8d105 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -532,7 +532,7 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) m_txt_mapping_sugs->SetMinSize(wxSize(FromDIP(580), -1)); m_txt_mapping_sugs->SetMaxSize(wxSize(FromDIP(580), -1)); m_txt_mapping_sugs->SetBackgroundColour(*wxWHITE); - m_txt_mapping_sugs->SetLabel(_L("Your filament arrangement method is not optimal.")); + m_txt_mapping_sugs->SetLabel(_L("Your filament grouping method is not optimal.")); m_mapping_sugs_sizer->Add(m_img_mapping_sugs, 0, wxALIGN_CENTER, 0); m_mapping_sugs_sizer->Add(m_txt_mapping_sugs, 0, wxALIGN_CENTER, 0);