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: