From 06acdf260954a4aa4f7947226325353c4837640d Mon Sep 17 00:00:00 2001 From: "weizhen.xie" Date: Thu, 24 Jul 2025 20:16:33 +0800 Subject: [PATCH] ENH:Give a warning when the flushing value changes or is zero. Jira: STUDIO-13175 Change-Id: Ibc5a912464322d2bc40514c310dfc4859bbd79b3 (cherry picked from commit 3fa4b149a0a529d8a2b1c6b6b80415161c13b2c3) (cherry picked from commit f6c03caaa744b774ffc9d6150b3691d232ced472) --- resources/web/flush/WipingDialog.html | 23 ++++++- src/slic3r/GUI/GLCanvas3D.cpp | 39 ++++++++++++ src/slic3r/GUI/GLCanvas3D.hpp | 2 + src/slic3r/GUI/GUI_App.cpp | 1 + src/slic3r/GUI/NotificationManager.cpp | 13 ++++ src/slic3r/GUI/NotificationManager.hpp | 4 ++ src/slic3r/GUI/Plater.cpp | 42 +++++-------- src/slic3r/GUI/Plater.hpp | 1 + src/slic3r/GUI/WipeTowerDialog.cpp | 85 ++++++++++++++++++++++++++ src/slic3r/GUI/WipeTowerDialog.hpp | 5 ++ 10 files changed, 185 insertions(+), 30 deletions(-) diff --git a/resources/web/flush/WipingDialog.html b/resources/web/flush/WipingDialog.html index 41d9e50ddb..d1e13a643f 100644 --- a/resources/web/flush/WipingDialog.html +++ b/resources/web/flush/WipingDialog.html @@ -388,6 +388,7 @@ let m_max_flush_volumes = [] let m_min_flush_multiplier = 0.50 let m_max_flush_multiplier = 3 + let m_default_matrix //系统默认矩阵 function storeData() { var data = JSON.stringify({ @@ -516,6 +517,9 @@ m_raw_matrix = data.flush_volume_matrixs.map(function(arr) { return arr.slice(); }); + m_default_matrix = data.default_matrixs.map(function (arr) { + return arr.slice(); + }); m_flush_multipiers = data.flush_multiplier.slice() m_max_flush_volumes = data.max_flush_volumes m_min_flush_volumes = data.min_flush_volumes @@ -641,6 +645,14 @@ function updateWarningTexts() { + let val = parseFloat(document.getElementById("multiplierInput").value); + const input = document.getElementById('multiplierInput'); + if (val !== 1.0) { + input.style.color = 'orange'; + } else { + input.style.color = 'black'; + } + let hasException = false; for (let i = 0; i < m_number_of_filaments; i++) { for (let j = 0; j < m_number_of_filaments; j++) { @@ -649,11 +661,18 @@ let val = parseInt(input.value, 10); if (isNaN(val)) val = 0; + var index = i * m_number_of_filaments + j; + let defaultVal = rawToDislay(m_default_matrix[m_curr_extruder_id][index], m_flush_multipiers[m_curr_extruder_id]) + if (val < m_min_flush_volumes[m_curr_extruder_id] || val > m_max_flush_volumes[m_curr_extruder_id]) { input.style.color = "red"; hasException = true; - } else { - input.style.removeProperty("color"); + } + else if (val != defaultVal) { + input.style.color = "orange"; + } + else { + input.style.removeProperty("color"); } } } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 86e29afb24..81b3b35047 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -23,6 +23,7 @@ #include "OpenGLManager.hpp" #include "Plater.hpp" #include "MainFrame.hpp" +#include "WipeTowerDialog.hpp" #include "GUI_App.hpp" #include "GUI_ObjectList.hpp" #include "GUI_Colors.hpp" @@ -3035,6 +3036,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re auto clash_flag = construct_error_string(object_results, get_object_clashed_text()); auto unprintable_flag= construct_extruder_unprintable_error(object_results, get_left_extruder_unprintable_text(), get_right_extruder_unprintable_text()); + bool is_flushing_volume_valid = is_flushing_matrix_error(); + _set_warning_notification(EWarning::FlushingVolumeZero, is_flushing_volume_valid); _set_warning_notification(EWarning::ObjectClashed, clash_flag); _set_warning_notification(EWarning::LeftExtruderPrintableError, unprintable_flag.first); _set_warning_notification(EWarning::RightExtruderPrintableError, unprintable_flag.second); @@ -3066,6 +3069,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re } else { _set_warning_notification(EWarning::ObjectOutside, false); + _set_warning_notification(EWarning::FlushingVolumeZero, false); _set_warning_notification(EWarning::ObjectClashed, false); _set_warning_notification(EWarning::LeftExtruderPrintableError, false); _set_warning_notification(EWarning::RightExtruderPrintableError, false); @@ -10167,6 +10171,10 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) text = _u8L(get_filament_mixture_warning_text()); break; } + case EWarning::FlushingVolumeZero: + text = _u8L("Partial flushing volume set to 0. Multi-color printing may cause color mixing in models. Please redjust flushing settings."); + error = ErrorType::SLICING_ERROR; + break; } //BBS: this may happened when exit the app, plater is null if (!wxGetApp().plater()) @@ -10270,6 +10278,19 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) else notification_manager.close_slicing_customize_error_notification(NotificationType::BBLFilamentPrintableError, NotificationLevel::ErrorNotificationLevel); } + else if (warning == EWarning::FlushingVolumeZero) { + if (state) { + auto callback = [](wxEvtHandler *) { + auto plater = wxGetApp().plater(); + auto flushing_volume_btn = wxGetApp().sidebar().get_flushing_volume_btn(); + const wxEventTypeTag EVT_SCHEDULE_BACKGROUND_PROCESS(wxNewEventType()); + open_flushing_dialog(flushing_volume_btn, plater, SimpleEvent(EVT_SCHEDULE_BACKGROUND_PROCESS, plater)); + return false; + }; + notification_manager.push_slicing_customize_error_notification(NotificationType::BBLFlushingVolumeZero, NotificationLevel::WarningNotificationLevel, text, _u8L("Flushing Volume"), callback); + } else + notification_manager.close_slicing_customize_error_notification(NotificationType::BBLFlushingVolumeZero, NotificationLevel::WarningNotificationLevel); + } else { if (state) notification_manager.push_slicing_error_notification(text, conflictObj ? std::vector{conflictObj} : std::vector{}); @@ -10294,6 +10315,24 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) } } +bool GLCanvas3D::is_flushing_matrix_error() { + + 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; + + int matrix_len = config_matrix.size() / config_multiplier.size(); + int row_len = std::sqrt(matrix_len); + for (int i = 0; i < config_matrix.size(); i++) + { + int relative_id = i % matrix_len; + int row_id = relative_id / row_len; + int col_id = relative_id % row_len; + if (row_id != col_id && config_matrix[i] == 0) return true; + } + return false; +} + bool GLCanvas3D::_is_any_volume_outside() const { for (const GLVolume* volume : m_volumes.volumes) { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 0c787ae729..473473ca15 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -395,6 +395,7 @@ class GLCanvas3D PrimeTowerOutside, NozzleFilamentIncompatible, MixtureFilamentIncompatible, + FlushingVolumeZero }; class RenderStats @@ -1292,6 +1293,7 @@ private: // generates a warning notification containing the given message void _set_warning_notification(EWarning warning, bool state); + bool is_flushing_matrix_error(); bool _is_any_volume_outside() const; // updates the selection from the content of m_hover_volume_idxs diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index c3c2ef4d65..972a7debce 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -7307,6 +7307,7 @@ bool is_soluble_filament(int extruder_id) bool has_filaments(const std::vector& model_filaments) { auto &filament_presets = Slic3r::GUI::wxGetApp().preset_bundle->filament_presets; + if (!Slic3r::GUI::wxGetApp().plater()) return false; auto model_objects = Slic3r::GUI::wxGetApp().plater()->model().objects; const Slic3r::DynamicPrintConfig &config = wxGetApp().preset_bundle->full_config(); Model::setExtruderParams(config, filament_presets.size()); diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 4c27531119..35318412c8 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -2002,6 +2002,19 @@ void NotificationManager::close_plater_warning_notification(const std::string& t } } +void NotificationManager::push_flushing_volume_error_notification(NotificationType type, NotificationLevel level, const std::string &text, const std::string &hypertext, std::function callback) +{ + set_all_slicing_errors_gray(false); + std::string prefix_msg = level == NotificationLevel::WarningNotificationLevel ? _u8L("Warning:") : _u8L("Error:"); + push_notification_data({type, level, 0, prefix_msg + "\n" + text, hypertext, callback}, 0); +} + +void NotificationManager::close_flushing_volume_error_notification(NotificationType type, NotificationLevel level) +{ + for (std::unique_ptr ¬ification : m_pop_notifications) { + if (notification->get_type() == type && notification->get_data().level == level) { notification->close(); } + } +} void NotificationManager::set_all_slicing_errors_gray(bool g) { diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 0da9314bb2..9abf49323a 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -150,6 +150,7 @@ enum class NotificationType BBLSeqPrintInfo, //BBL: plugin install hint BBLPluginInstallHint, + BBLFlushingVolumeZero, BBLPluginUpdateAvailable, BBLPreviewOnlyMode, BBLPrinterConfigUpdateAvailable, @@ -243,6 +244,9 @@ public: // Closes error or warning of the same text void close_plater_error_notification(const std::string& text); void close_plater_warning_notification(const std::string& text); + //The flushing volume matrix has zero values in its off-diagonal elements + void push_flushing_volume_error_notification(NotificationType type, NotificationLevel level, const std::string &text, const std::string &hypertext = "", std::function callback = std::function()); + void close_flushing_volume_error_notification(NotificationType type, NotificationLevel level); // GCode exceeds the printing range of the extruder void push_slicing_customize_error_notification(NotificationType type, NotificationLevel level, const std::string &text, const std::string &hypertext = "", std::function callback = std::function()); void close_slicing_customize_error_notification(NotificationType type, NotificationLevel level); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e3251641a6..9b295dddbb 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1870,35 +1870,17 @@ Sidebar::Sidebar(Plater *parent) p->m_flushing_volume_btn = new Button(p->m_panel_filament_title, _L("Flushing volumes")); p->m_flushing_volume_btn->SetStyle(ButtonStyle::Confirm, ButtonType::Compact); p->m_flushing_volume_btn->SetId(wxID_RESET); - p->m_flushing_volume_btn->Bind(wxEVT_BUTTON, ([parent](wxCommandEvent &e) - { - auto& project_config = wxGetApp().preset_bundle->project_config; - const std::vector& init_matrix = (project_config.option("flush_volumes_matrix"))->values; - const std::vector& init_extruders = (project_config.option("flush_volumes_vector"))->values; + auto has_modify = is_flush_config_modified(); + if (has_modify) { + p->m_flushing_volume_btn->SetBorderColor(wxColour(255, 111, 0)); + p->m_flushing_volume_btn->SetTextColor(wxColour(255, 111, 0)); + } else { + p->m_flushing_volume_btn->SetBorderColor(wxColour(172, 172, 172)); + p->m_flushing_volume_btn->SetTextColor(wxColour(172, 172, 172)); + } - const std::vector extruder_colours = wxGetApp().plater()->get_extruder_colors_from_plater_config(); - const auto& full_config = wxGetApp().preset_bundle->full_config(); - - size_t nozzle_nums = full_config.option("nozzle_diameter")->values.size(); - - std::vector> extra_flush_volumes; - extra_flush_volumes.resize(nozzle_nums, std::vector()); - for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) { - extra_flush_volumes[nozzle_id] = get_min_flush_volumes(full_config, nozzle_id); - } - - WipingDialog dlg(static_cast(wxGetApp().mainframe),extra_flush_volumes); - 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()); - wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config); - - wxGetApp().plater()->update_project_dirty_from_presets(); - wxPostEvent(parent, SimpleEvent(EVT_SCHEDULE_BACKGROUND_PROCESS, parent)); - } + p->m_flushing_volume_btn->Bind(wxEVT_BUTTON, ([parent, this](wxCommandEvent &e) { + open_flushing_dialog(p->m_flushing_volume_btn, parent, SimpleEvent(EVT_SCHEDULE_BACKGROUND_PROCESS, parent)); })); bSizer39->Add(p->m_flushing_volume_btn, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(4)); @@ -3375,6 +3357,10 @@ wxButton* Sidebar::get_wiping_dialog_button() return NULL; } +Button* Sidebar::get_flushing_volume_btn() { + return p->m_flushing_volume_btn; + } + void Sidebar::enable_buttons(bool enable) { #if 0 diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 412ad275c3..c0419881bc 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -212,6 +212,7 @@ public: ConfigOptionsGroup* og_freq_chng_params(const bool is_fff); wxButton* get_wiping_dialog_button(); + Button* get_flushing_volume_btn(); // BBS void enable_buttons(bool enable); diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp index 52b7a416f5..b61a3e9342 100644 --- a/src/slic3r/GUI/WipeTowerDialog.cpp +++ b/src/slic3r/GUI/WipeTowerDialog.cpp @@ -13,6 +13,7 @@ #include "Widgets/DialogButtons.hpp" #include "libslic3r/Config.hpp" #include "Widgets/Label.hpp" +#include "MainFrame.hpp" using namespace Slic3r; using namespace Slic3r::GUI; @@ -198,6 +199,81 @@ std::string RammingPanel::get_parameters() 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 auto &full_config = wxGetApp().preset_bundle->full_config(); + const std::vector &config_matrix = (project_config.option("flush_volumes_matrix"))->values; + const std::vector &config_multiplier = (project_config.option("flush_multiplier"))->values; + + size_t nozzle_nums = full_config.option("nozzle_diameter")->values.size(); + std::vector> extra_flush_volumes; + extra_flush_volumes.resize(nozzle_nums, std::vector()); + for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) { extra_flush_volumes[nozzle_id] = get_min_flush_volumes(full_config, nozzle_id); } + WipingDialog dlg(static_cast(wxGetApp().mainframe), extra_flush_volumes); + + 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 = dlg.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(Button *flushing_volume_btn, wxEvtHandler *parent, const wxEvent &event) +{ + auto &project_config = wxGetApp().preset_bundle->project_config; + const std::vector &init_matrix = (project_config.option("flush_volumes_matrix"))->values; + const std::vector &init_extruders = (project_config.option("flush_volumes_vector"))->values; + + const std::vector extruder_colours = wxGetApp().plater()->get_extruder_colors_from_plater_config(); + const auto &full_config = wxGetApp().preset_bundle->full_config(); + + size_t nozzle_nums = full_config.option("nozzle_diameter")->values.size(); + + std::vector> extra_flush_volumes; + extra_flush_volumes.resize(nozzle_nums, std::vector()); + for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) { extra_flush_volumes[nozzle_id] = get_min_flush_volumes(full_config, nozzle_id); } + + WipingDialog dlg(static_cast(wxGetApp().mainframe), extra_flush_volumes); + //WipingDialog dlg(wxGetApp().mainframe), extra_flush_volumes); + 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()); + auto has_modify = is_flush_config_modified(); + if (has_modify) { + flushing_volume_btn->SetBorderColor(wxColour(255, 111, 0)); + flushing_volume_btn->SetTextColor(wxColour(255, 111, 0)); + } else { + flushing_volume_btn->SetBorderColor(wxColour(172, 172, 172)); + flushing_volume_btn->SetTextColor(wxColour(172, 172, 172)); + } + + 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) { @@ -222,6 +298,11 @@ wxString WipingDialog::BuildTableObjStr() } 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; @@ -235,10 +316,14 @@ wxString WipingDialog::BuildTableObjStr() 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) { int min_flush_from_nozzle_volume = *min_element(m_extra_flush_volume[idx].begin(), m_extra_flush_volume[idx].end()); diff --git a/src/slic3r/GUI/WipeTowerDialog.hpp b/src/slic3r/GUI/WipeTowerDialog.hpp index 1647036b15..7444b64996 100644 --- a/src/slic3r/GUI/WipeTowerDialog.hpp +++ b/src/slic3r/GUI/WipeTowerDialog.hpp @@ -38,6 +38,11 @@ private: }; +class Button; + +bool is_flush_config_modified(); +void open_flushing_dialog(Button *flushing_volume_btn, wxEvtHandler *parent, const wxEvent &event); + class WipingDialog : public wxDialog { public: