#include #include #include #include "libslic3r/FlushVolCalc.hpp" #include "WipeTowerDialog.hpp" #include "GUI.hpp" #include "I18N.hpp" #include "GUI_App.hpp" #include "MsgDialog.hpp" #include "format.hpp" #include "libslic3r/Color.hpp" #include "Widgets/StaticLine.hpp" #include "Widgets/DialogButtons.hpp" #include "libslic3r/Config.hpp" #include "Widgets/Label.hpp" #include "MainFrame.hpp" using namespace Slic3r; using namespace Slic3r::GUI; int scale(const int val) { return val * Slic3r::GUI::wxGetApp().em_unit() / 10; } static void update_ui(wxWindow* window) { Slic3r::GUI::wxGetApp().UpdateDarkUI(window); } RammingDialog::RammingDialog(wxWindow* parent,const std::string& parameters) : wxDialog(parent, wxID_ANY, _(L("Ramming customization")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/) { SetBackgroundColour(*wxWHITE); m_panel_ramming = new RammingPanel(this,parameters); m_panel_ramming->Show(true); auto main_sizer = new wxBoxSizer(wxVERTICAL); main_sizer->Add(m_panel_ramming, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5); auto dlg_btns = new DialogButtons(this, {"OK", "Cancel"}); main_sizer->Add(dlg_btns, 0, wxEXPAND); SetSizer(main_sizer); main_sizer->SetSizeHints(this); this->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { EndModal(wxCANCEL); }); this->Bind(wxEVT_BUTTON,[this](wxCommandEvent&) { m_output_data = m_panel_ramming->get_parameters(); EndModal(wxID_OK); },wxID_OK); wxGetApp().UpdateDlgDarkUI(this); this->Show(); Slic3r::GUI::MessageDialog dlg(this, _(L("Ramming denotes the rapid extrusion just before a tool change in a single-extruder MM printer. Its purpose is to " "properly shape the end of the unloaded filament so it does not prevent insertion of the new filament and can itself " "be reinserted later. This phase is important and different materials can require different extrusion speeds to get " "the good shape. For this reason, the extrusion rates during ramming are adjustable.\n\nThis is an expert-level " "setting, incorrect adjustment will likely lead to jams, extruder wheel grinding into filament etc.")), _(L("Warning")), wxOK | wxICON_EXCLAMATION);// .ShowModal(); dlg.ShowModal(); } #ifdef _WIN32 #define style wxSP_ARROW_KEYS | wxBORDER_SIMPLE #else #define style wxSP_ARROW_KEYS #endif RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize/*,wxPoint(50,50), wxSize(800,350),wxBORDER_RAISED*/) { SetBackgroundColour(*wxWHITE); update_ui(this); auto sizer_chart = new wxBoxSizer(wxVERTICAL); auto sizer_param = new wxBoxSizer(wxVERTICAL); std::stringstream stream{ parameters }; stream >> m_ramming_line_width_multiplicator >> m_ramming_step_multiplicator; int ramming_speed_size = 0; float dummy = 0.f; while (stream >> dummy) ++ramming_speed_size; stream.clear(); stream.get(); std::vector> buttons; float x = 0.f; float y = 0.f; while (stream >> x >> y) buttons.push_back(std::make_pair(x, y)); m_chart = new Chart(this, wxRect(scale(10),scale(10),scale(480),scale(360)), buttons, ramming_speed_size, 0.25f, scale(10)); update_ui(m_chart); sizer_chart->Add(m_chart, 0, wxALL, 5); // Create help text for constant flow rate dragging std::string ctrl_str = GUI::shortkey_ctrl_prefix(); if (!ctrl_str.empty() && ctrl_str.back() == '+') ctrl_str.pop_back(); // Remove trailing '+' wxString message = format_wxstr(_L("For constant flow rate, hold %1% while dragging."), ctrl_str); Label* label = new Label(this, wxEmptyString); wxClientDC dc(label); wxString multiline_message; label->SetFont(Label::Body_14); label->SetForegroundColour(StateColor::darkModeColorFor(wxColour("#363636"))); label->split_lines(dc, scale(470), message, multiline_message); label->SetLabel(multiline_message); sizer_chart->Add(label, 0, wxEXPAND | wxALL, 5); m_widget_time = new SpinInput(this, wxEmptyString, "ms" , wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 0 , 5000 , 3000, 250); m_widget_volume = new SpinInput(this, wxEmptyString, wxString::FromUTF8("mm³"), wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 0 , 10000, 0 ); m_widget_ramming_line_width_multiplicator = new SpinInput(this, wxEmptyString, "%" , wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 10, 300 , 100 ); m_widget_ramming_step_multiplicator = new SpinInput(this, wxEmptyString, "%" , wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 10, 300 , 100 ); auto add_title = [this, sizer_param](wxString label){ auto title = new StaticLine(this, 0, label); title->SetFont(Label::Head_14); title->SetForegroundColour(StateColor::darkModeColorFor(wxColour("#363636"))); sizer_param->Add(title, 0, wxEXPAND | wxBOTTOM, scale(8)); }; SetFont(Label::Body_14); wxSize col_size; for(auto label : {"Time", "Volume", "Width", "Spacing"}) col_size.IncTo(GetTextExtent(_L(label))); col_size = wxSize(col_size.x + scale(30) ,-1); auto add_spin = [this, sizer_param, col_size](wxString label, SpinInput* spin){ spin->Bind(wxEVT_KILL_FOCUS, [this](auto &e) { e.SetId(GetId()); ProcessEventLocally(e); e.Skip(); }); auto h_sizer = new wxBoxSizer(wxHORIZONTAL); auto text = new wxStaticText(this, wxID_ANY, label, wxDefaultPosition, col_size); text->SetForegroundColour(StateColor::darkModeColorFor(wxColour("#363636"))); h_sizer->Add(text, 0, wxALIGN_CENTER_VERTICAL); h_sizer->Add(spin); sizer_param->Add(h_sizer, 0, wxEXPAND | wxBOTTOM, scale(2)); }; add_title(_L("Total ramming")); add_spin( _L("Time") , m_widget_time ); add_spin( _L("Volume"), m_widget_volume); sizer_param->AddSpacer(10); add_title(_L("Ramming line")); add_spin( _L("Width") , m_widget_ramming_line_width_multiplicator); add_spin( _L("Spacing"), m_widget_ramming_step_multiplicator ); m_widget_time->SetValue(int(m_chart->get_time() * 1000)); m_widget_volume->SetValue(m_chart->get_volume()); m_widget_volume->Disable(); m_widget_ramming_line_width_multiplicator->SetValue(m_ramming_line_width_multiplicator); m_widget_ramming_step_multiplicator->SetValue(m_ramming_step_multiplicator); m_widget_ramming_step_multiplicator->Bind(wxEVT_SPINCTRL,[this](wxCommandEvent&) { line_parameters_changed(); }); m_widget_ramming_line_width_multiplicator->Bind(wxEVT_SPINCTRL,[this](wxCommandEvent&) { line_parameters_changed(); }); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(sizer_chart, 0, wxALL, 5); sizer->Add(sizer_param, 0, wxALL, 10); sizer->SetSizeHints(this); SetSizer(sizer); m_widget_time->Bind(wxEVT_SPINCTRL,[this](wxCommandEvent&) { m_chart->set_xy_range(m_widget_time->GetValue() * 0.001,-1); }); m_widget_time->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value m_widget_volume->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value Bind(EVT_WIPE_TOWER_CHART_CHANGED,[this](wxCommandEvent&) { m_widget_volume->SetValue(m_chart->get_volume()); m_widget_time->SetValue(m_chart->get_time() * 1000); }); Refresh(true); // erase background } void RammingPanel::line_parameters_changed() { m_ramming_line_width_multiplicator = m_widget_ramming_line_width_multiplicator->GetValue(); m_ramming_step_multiplicator = m_widget_ramming_step_multiplicator->GetValue(); } std::string RammingPanel::get_parameters() { std::vector speeds = m_chart->get_ramming_speed(0.25f); std::vector> buttons = m_chart->get_buttons(); std::stringstream stream; stream << m_ramming_line_width_multiplicator << " " << m_ramming_step_multiplicator; for (const float& speed_value : speeds) stream << " " << speed_value; stream << "|"; for (const auto& button : buttons) stream << " " << button.first << " " << button.second; return stream.str(); } static const float g_min_flush_multiplier = 0.f; static const float g_max_flush_multiplier = 3.f; bool is_flush_config_modified() { const auto &project_config = wxGetApp().preset_bundle->project_config; const std::vector &config_matrix = (project_config.option("flush_volumes_matrix"))->values; const std::vector &config_multiplier = (project_config.option("flush_multiplier"))->values; bool has_modify = false; for (int i = 0; i < config_multiplier.size(); i++) { if (config_multiplier[i] != 1) { has_modify = true; break; } std::vector> default_matrix = WipingDialog::CalcFlushingVolumes(i); int len = default_matrix.size(); for (int m = 0; m < len; m++) { for (int n = 0; n < len; n++) { int idx = i * len * len + m * len + n; if (config_matrix[idx] != default_matrix[m][n] * config_multiplier[i]) { has_modify = true; break; } } if (has_modify) break; } if (has_modify) break; } return has_modify; } void open_flushing_dialog(wxEvtHandler *parent, const wxEvent &event) { auto &project_config = wxGetApp().preset_bundle->project_config; WipingDialog dlg(static_cast(wxGetApp().mainframe)); dlg.ShowModal(); if (dlg.GetSubmitFlag()) { auto matrix = dlg.GetFlattenMatrix(); auto flush_multipliers = dlg.GetMultipliers(); (project_config.option("flush_volumes_matrix"))->values = std::vector(matrix.begin(), matrix.end()); (project_config.option("flush_multiplier"))->values = std::vector(flush_multipliers.begin(), flush_multipliers.end()); bool flushing_volume_modify = is_flush_config_modified(); wxGetApp().sidebar().set_flushing_volume_warning(flushing_volume_modify); wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config); wxGetApp().plater()->update_project_dirty_from_presets(); wxPostEvent(parent, event); } } static std::vector MatrixFlatten(const WipingDialog::VolumeMatrix& matrix) { std::vector vec; for (auto row_elems : matrix) { for (auto elem : row_elems) vec.emplace_back(elem); } return vec; } wxString WipingDialog::BuildTableObjStr() { auto full_config = wxGetApp().preset_bundle->full_config(); auto filament_colors = full_config.option("filament_colour")->values; auto flush_multiplier = full_config.option("flush_multiplier")->values; int nozzle_num = full_config.option("nozzle_diameter")->values.size(); auto raw_matrix_data = full_config.option("flush_volumes_matrix")->values; auto nozzle_flush_dataset = full_config.option("nozzle_flush_dataset")->values; std::vector> flush_matrixs; for (int idx = 0; idx < nozzle_num; ++idx) { flush_matrixs.emplace_back(get_flush_volumes_matrix(raw_matrix_data, idx, nozzle_num)); } flush_multiplier.resize(nozzle_num, 1); std::vector> default_matrixs; for (int idx = 0; idx < nozzle_num; ++idx) { default_matrixs.emplace_back(MatrixFlatten(CalcFlushingVolumes(idx))); } m_raw_matrixs = flush_matrixs; m_flush_multipliers = flush_multiplier; json obj; obj["flush_multiplier"] = flush_multiplier; obj["extruder_num"] = nozzle_num; obj["filament_colors"] = filament_colors; obj["flush_volume_matrixs"] = json::array(); obj["min_flush_volumes"] = json::array(); obj["max_flush_volumes"] = json::array(); obj["min_flush_multiplier"] = g_min_flush_multiplier; obj["max_flush_multiplier"] = g_max_flush_multiplier; obj["is_dark_mode"] = wxGetApp().dark_mode(); obj["default_matrixs"] = json::array(); for (const auto& vec : flush_matrixs) { obj["flush_volume_matrixs"].push_back(vec); } for (const auto &vec : default_matrixs) { obj["default_matrixs"].push_back(vec); } for (int idx = 0; idx < nozzle_num; ++idx) { const std::vector &min_flush_volumes = get_min_flush_volumes(full_config, idx); int min_flush_from_nozzle_volume = *min_element(min_flush_volumes.begin(), min_flush_volumes.end()); GenericFlushPredictor pd(nozzle_flush_dataset[idx]); int min_flush_from_flush_data = pd.get_min_flush_volume(); obj["min_flush_volumes"].push_back(std::min(min_flush_from_flush_data,min_flush_from_nozzle_volume)); obj["max_flush_volumes"].push_back(m_max_flush_volume); } auto obj_str = obj.dump(); return obj_str; } wxString WipingDialog::BuildTextObjStr(bool multi_language) { wxString auto_flush_tip; wxString volume_desp_panel; wxString volume_range_panel; wxString multiplier_range_panel; wxString calc_btn_panel; wxString extruder_label_0; wxString extruder_label_1; wxString multiplier_label; wxString ok_btn_label; wxString cancel_btn_label; if (multi_language) { auto_flush_tip = _L("Orca would re-calculate your flushing volumes everytime the filaments color changed or filaments changed. You could disable the auto-calculate in Orca Slicer > Preferences"); volume_desp_panel = _L("Flushing volume (mm³) for each filament pair."); volume_range_panel = wxString::Format(_L("Suggestion: Flushing Volume in range [%d, %d]"), 0, 700); multiplier_range_panel = wxString::Format(_L("The multiplier should be in range [%.2f, %.2f]."), 0, 3); calc_btn_panel = _L("Re-calculate"); extruder_label_0 = _L("Left extruder"); extruder_label_1 = _L("Right extruder"); multiplier_label = _L("Multiplier"); ok_btn_label = _L("OK"); cancel_btn_label = _L("Cancel"); } else { auto_flush_tip = "Orca would re-calculate your flushing volumes everytime the filaments color changed or filaments changed. You could disable the auto-calculate in Orca Slicer > Preferences"; volume_desp_panel = wxString::FromUTF8("Flushing volume (mm³) for each filament pair."); volume_range_panel = wxString::Format("Suggestion: Flushing Volume in range [%d, %d]", 0, 700); multiplier_range_panel = wxString::Format("The multiplier should be in range [%.2f, %.2f].", 0, 3); calc_btn_panel = "Re-calculate"; extruder_label_0 = "Left extruder"; extruder_label_1 = "Right extruder"; multiplier_label = "Multiplier"; ok_btn_label = "OK"; cancel_btn_label = "Cancel"; } wxString text_obj = "{"; text_obj += wxString::Format("\"volume_desp_panel\":\"%s\",", volume_desp_panel); text_obj += wxString::Format("\"volume_range_panel\":\"%s\",", volume_range_panel); text_obj += wxString::Format("\"multiplier_range_panel\":\"%s\",", multiplier_range_panel); text_obj += wxString::Format("\"calc_btn_panel\":\"%s\",", calc_btn_panel); text_obj += wxString::Format("\"extruder_label_0\":\"%s\",", extruder_label_0); text_obj += wxString::Format("\"extruder_label_1\":\"%s\",", extruder_label_1); text_obj += wxString::Format("\"multiplier_label\":\"%s\",", multiplier_label); text_obj += wxString::Format("\"ok_btn_label\":\"%s\",", ok_btn_label); text_obj += wxString::Format("\"cancel_btn_label\":\"%s\",", cancel_btn_label); text_obj += wxString::Format("\"auto_flush_tip\":\"%s\"", auto_flush_tip); text_obj += "}"; return text_obj; } WipingDialog::WipingDialog(wxWindow* parent, const int max_flush_volume) : wxDialog(parent, wxID_ANY, _(L("Flushing volumes for filament change")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE ), m_max_flush_volume(max_flush_volume) { wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); this->SetSizer(main_sizer); this->SetBackgroundColour(*wxWHITE); auto filament_count= wxGetApp().preset_bundle->project_config.option("filament_colour")->values.size(); wxSize extra_size = { FromDIP(100),FromDIP(235) }; if (filament_count <= 2) extra_size.y += FromDIP(16) * 3 + FromDIP(32); else if (filament_count == 3) extra_size.y += FromDIP(16) * 3; else if (4 <= filament_count && filament_count <= 8) extra_size.y += FromDIP(16) * 2; else extra_size.y += FromDIP(16); wxSize max_scroll_size = { FromDIP(1000),FromDIP(500) }; wxSize estimate_size = { (int)(filament_count + 1) * FromDIP(60),(int)(filament_count + 1) * FromDIP(30)+FromDIP(2)}; wxSize scroll_size ={ std::min(max_scroll_size.x,estimate_size.x),std::min(max_scroll_size.y,estimate_size.y) }; wxSize applied_size = scroll_size + extra_size; wxSize scaled_screen_size = wxGetDisplaySize(); double scale_factor = wxDisplay().GetScaleFactor(); scaled_screen_size = { (int)(scaled_screen_size.x / scale_factor),(int)(scaled_screen_size.y / scale_factor) }; applied_size = { std::min(applied_size.x,scaled_screen_size.x),std::min(applied_size.y,scaled_screen_size.y) }; m_webview = wxWebView::New(this, wxID_ANY, wxEmptyString, wxDefaultPosition, applied_size, wxWebViewBackendDefault, wxNO_BORDER); m_webview->AddScriptMessageHandler("wipingDialog"); main_sizer->Add(m_webview, 1, wxEXPAND); fs::path filepath = fs::path(resources_dir()) / "web/flush/WipingDialog.html"; wxString filepath_str = wxString::FromUTF8(filepath.string()); wxFileName fn(filepath_str); if(fn.FileExists()) { wxString url = wxFileSystem::FileNameToURL(fn); BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< "File exists and load url " << url.ToStdString(); m_webview->LoadURL(url); BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< "Successfully loaded url: " << url.ToStdString(); } else { BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< "WipingDialog.html not exist at path: " << filepath.string(); } main_sizer->SetSizeHints(this); main_sizer->Fit(this); CenterOnParent(); wxGetApp().UpdateDlgDarkUI(this); //m_webview->Bind(wxEVT_WEBVIEW_NAVIGATED, [this](auto& evt) { // auto table_obj_str = BuildTableObjStr(); // auto text_obj_str = BuildTextObjStr(); // CallAfter([table_obj_str, text_obj_str, this] { // wxString script = wxString::Format("buildTable(%s);buildText(%s)", table_obj_str, text_obj_str); // m_webview->RunScript(script); // }); // }); m_webview->Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, [this](wxWebViewEvent& evt) { std::string message = evt.GetString().ToStdString(); BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< "Received message: " << message; try { json j = json::parse(message); if (j["msg"].get() == "init") { auto table_obj_str = BuildTableObjStr(); auto text_obj_str = BuildTextObjStr(true); CallAfter([table_obj_str, text_obj_str, this] { wxString script1 = wxString::Format("buildTable(%s)", table_obj_str); m_webview->RunScript(script1); wxString script2 = wxString::Format("buildText(%s)", text_obj_str); bool result = m_webview->RunScript(script2); if (!result) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< "Failed to run buildText, retry without multi language"; wxString script3 = wxString::Format("buildText(%s)", BuildTextObjStr(false)); m_webview->RunScript(script3); } }); } else if (j["msg"].get() == "updateMatrix") { int extruder_id = j["extruder_id"].get(); auto new_matrix = CalcFlushingVolumes(extruder_id); json obj; obj["flush_volume_matrix"] = MatrixFlatten(new_matrix); obj["extruder_id"] = extruder_id; CallAfter([obj, this] { std::string flush_volume_matrix_str = obj["flush_volume_matrix"].dump(); std::string extruder_id_str = std::to_string(obj["extruder_id"].get()); wxString script = wxString::Format("updateTable(%s,%s)", flush_volume_matrix_str, extruder_id_str); m_webview->RunScript(script); }); } else if (j["msg"].get() == "storeData") { int extruder_num = j["number_of_extruders"].get(); std::vector> store_matrixs; for (auto iter = j["raw_matrix"].begin(); iter != j["raw_matrix"].end(); ++iter) { store_matrixs.emplace_back((*iter).get>()); } std::vectorstore_multipliers = j["flush_multiplier"].get>(); {// limit all matrix value before write to gcode, the limitation is depends on the multipliers size_t cols_temp_matrix = 0; if (!store_matrixs.empty()) { cols_temp_matrix = store_matrixs[0].size(); } if (store_multipliers.size() == store_matrixs.size() && cols_temp_matrix>0) // nuzzles==nuzzles { for (size_t idx = 0; idx < store_multipliers.size(); ++idx) { double m_max_flush_volume_t = (double)m_max_flush_volume, m_store_multipliers=store_multipliers[idx]; std::transform(store_matrixs[idx].begin(), store_matrixs[idx].end(), store_matrixs[idx].begin(), [m_max_flush_volume_t, m_store_multipliers](double inputx) { return std::clamp(inputx, 0.0, m_max_flush_volume_t / m_store_multipliers); }); } } } this->StoreFlushData(extruder_num, store_matrixs, store_multipliers); m_submit_flag = true; this->Close(); } else if (j["msg"].get() == "quit") { this->Close(); } } catch (...) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< "Failed to parse json message: " << message; } }); } int WipingDialog::CalcFlushingVolume(const wxColour& from, const wxColour& to, int min_flush_volume , int nozzle_flush_dataset) { Slic3r::FlushVolCalculator calculator(min_flush_volume, Slic3r::g_max_flush_volume, nozzle_flush_dataset); return calculator.calc_flush_vol(from.Alpha(), from.Red(), from.Green(), from.Blue(), to.Alpha(), to.Red(), to.Green(), to.Blue()); } WipingDialog::VolumeMatrix WipingDialog::CalcFlushingVolumes(int extruder_id) { auto& preset_bundle = wxGetApp().preset_bundle; auto full_config = preset_bundle->full_config(); auto& ams_multi_color_filament = preset_bundle->ams_multi_color_filment; std::vector filament_color_strs = full_config.option("filament_colour")->values; std::vector> multi_colors; std::vector filament_colors; for (auto color_str : filament_color_strs) filament_colors.emplace_back(color_str); int flush_dataset_value = full_config.option("nozzle_flush_dataset")->values[extruder_id]; // Support for multi-color filament for (int i = 0; i < filament_colors.size(); ++i) { std::vector single_filament; if (i < ams_multi_color_filament.size()) { if (!ams_multi_color_filament[i].empty()) { std::vector colors = ams_multi_color_filament[i]; for (int j = 0; j < colors.size(); ++j) { single_filament.push_back(wxColour(colors[j])); } multi_colors.push_back(single_filament); continue; } } single_filament.push_back(wxColour(filament_colors[i])); multi_colors.push_back(single_filament); } VolumeMatrix matrix; const std::vector min_flush_volumes = get_min_flush_volumes(full_config, extruder_id); for (int from_idx = 0; from_idx < multi_colors.size(); ++from_idx) { bool is_from_support = is_support_filament(from_idx); matrix.emplace_back(); for (int to_idx = 0; to_idx < multi_colors.size(); ++to_idx) { if (from_idx == to_idx) { matrix.back().emplace_back(0); continue; } bool is_to_support = is_support_filament(to_idx); int flushing_volume = 0; if (is_to_support) { flushing_volume = Slic3r::g_flush_volume_to_support; } else { for (int i = 0; i < multi_colors[from_idx].size(); ++i) { const wxColour& from = multi_colors[from_idx][i]; for (int j = 0; j < multi_colors[to_idx].size(); ++j) { const wxColour& to = multi_colors[to_idx][j]; int volume = CalcFlushingVolume(from, to, min_flush_volumes[from_idx], flush_dataset_value); flushing_volume = std::max(flushing_volume, volume); } } if (is_from_support) { flushing_volume = std::max(Slic3r::g_min_flush_volume_from_support, flushing_volume); } } matrix.back().emplace_back(flushing_volume); } } return matrix; } void WipingDialog::StoreFlushData(int extruder_num, const std::vector>& flush_volume_vecs, const std::vector&flush_multipliers) { m_flush_multipliers = flush_multipliers; m_raw_matrixs = flush_volume_vecs; } std::vector WipingDialog::GetFlattenMatrix()const { std::vector ret; for (auto& matrix : m_raw_matrixs) { ret.insert(ret.end(), matrix.begin(), matrix.end()); } return ret; } std::vector WipingDialog::GetMultipliers()const { return m_flush_multipliers; }