#include #include #include "libslic3r/FlushVolCalc.hpp" #include "WipeTowerDialog.hpp" #include "GUI.hpp" #include "I18N.hpp" #include "GUI_App.hpp" #include "libslic3r/Config.hpp" using namespace Slic3r; using namespace Slic3r::GUI; static const float g_min_flush_multiplier = 0.f; static const float g_max_flush_multiplier = 3.f; 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; 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); 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(); for (const auto& vec : flush_matrixs) { obj["flush_volume_matrixs"].push_back(vec); } for (int idx = 0; idx < nozzle_num; ++idx) { obj["min_flush_volumes"].push_back(*min_element(m_extra_flush_volume[idx].begin(), m_extra_flush_volume[idx].end())); obj["max_flush_volumes"].push_back(m_max_flush_volume); } auto obj_str = obj.dump(); return obj_str; } wxString WipingDialog::BuildTextObjStr() { wxString auto_flush_tip = _L("Studio would re-calculate your flushing volumes everytime the filaments color changed or filaments changed. You could disable the auto-calculate in Bambu Studio > Preferences"); wxString volume_desp_panel = _L("Flushing volume (mm³) for each filament pair."); wxString volume_range_panel = wxString::Format(_L("Suggestion: Flushing Volume in range [%d, %d]"), 0, 700); wxString multiplier_range_panel = wxString::Format(_L("The multiplier should be in range [%.2f, %.2f]."), 0, 3); wxString calc_btn_panel = _L("Re-calculate"); wxString extruder_label_0 = _L("Left extruder"); wxString extruder_label_1 = _L("Right extruder"); wxString multiplier_label = _L("Multiplier"); wxString ok_btn_label = _L("OK"); wxString cancel_btn_label = _L("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 std::vector>& extra_flush_volume,const int max_flush_volume) : wxDialog(parent, wxID_ANY, _(L("Flushing volumes for filament change")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE ), m_extra_flush_volume(extra_flush_volume), m_max_flush_volume(max_flush_volume) { std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") % Slic3r::resources_dir()).str(); SetIcon(wxIcon(Slic3r::encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); this->SetSizer(main_sizer); 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); 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 = "file:///" + fn.GetFullPath(); m_webview->LoadURL(url); } else { BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< "WipingDialog.html not exist"; } main_sizer->SetSizeHints(this); main_sizer->Fit(this); CenterOnParent(); //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(); try { json j = json::parse(message); if (j["msg"].get() == "init") { 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); }); } 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>(); this->StoreFlushData(extruder_num, store_matrixs, store_multipliers); m_submit_flag = true; this->Close(); } else if (j["msg"].get() == "quit") { this->Close(); } } catch (...) { } }); } int WipingDialog::CalcFlushingVolume(const wxColour& from, const wxColour& to, int min_flush_volume) { Slic3r::FlushVolCalculator calculator(min_flush_volume, Slic3r::g_max_flush_volume); 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); // 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; 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, m_extra_flush_volume[extruder_id][from_idx]); 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; }