mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-14 00:52:04 +00:00
ENH: add prompt for incompatible filaments and nozzles
jira: STUDIO-12873 Signed-off-by: xun.zhang <xun.zhang@bambulab.com> Change-Id: Ieb79a35e0609e7687fdcf31742df3a08fedc925b (cherry picked from commit 1ef32833035629c1b3644d77fdc9c234992090f3)
This commit is contained in:
34
resources/info/nozzle_incompatibles.json
Normal file
34
resources/info/nozzle_incompatibles.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"incompatible_nozzles":{
|
||||
"Standard":{
|
||||
"0.2":[
|
||||
"Bambu PLA Marble",
|
||||
"Bambu PLA Sparkle",
|
||||
"Bambu PLA Wood",
|
||||
"Bambu PLA Galaxy",
|
||||
"Bambu PETG Translucent"
|
||||
],
|
||||
"0.4":[],
|
||||
"0.6":[
|
||||
"Bambu PLA Silk+",
|
||||
"Bambu PLA Silk",
|
||||
"Bambu PLA Aero",
|
||||
"Bambu ASA-Aero"
|
||||
],
|
||||
"0.8":[
|
||||
"Bambu PLA Silk+",
|
||||
"Bambu PLA Silk",
|
||||
"Bambu PLA Aero",
|
||||
"Bambu ASA-Aero"
|
||||
]
|
||||
},
|
||||
"High Flow":{
|
||||
"0.4":[
|
||||
"Bambu PLA-CF",
|
||||
"Bambu PETG-CF"
|
||||
],
|
||||
"0.6":[],
|
||||
"0.8":[]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2710,6 +2710,47 @@ int Print::get_hrc_by_nozzle_type(const NozzleType&type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<std::string> Print::get_incompatible_filaments_by_nozzle(const float nozzle_diameter, const std::optional<NozzleVolumeType> nozzle_volume_type)
|
||||
{
|
||||
static std::map<std::string, std::map<std::string, std::vector<std::string>>> incompatible_filaments;
|
||||
if(incompatible_filaments.empty()){
|
||||
fs::path file_path = fs::path(resources_dir()) / "info" / "nozzle_incompatibles.json";
|
||||
boost::nowide::ifstream in(file_path.string());
|
||||
json j;
|
||||
try {
|
||||
j = json::parse(in);
|
||||
for(auto& [volume_type, diameter_list] : j["incompatible_nozzles"].items()) {
|
||||
for(auto& [diameter, filaments]: diameter_list.items()){
|
||||
incompatible_filaments[volume_type][diameter] = filaments.get<std::vector<std::string>>();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(const json::parse_error& err){
|
||||
in.close();
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": parse " << file_path.string() << " got a nlohmann::detail::parse_error, reason = " << err.what();
|
||||
|
||||
incompatible_filaments[get_nozzle_volume_type_string(NozzleVolumeType::nvtHighFlow)] = {};
|
||||
incompatible_filaments[get_nozzle_volume_type_string(NozzleVolumeType::nvtStandard)] = {};
|
||||
}
|
||||
}
|
||||
std::ostringstream oss;
|
||||
oss << std::fixed << std::setprecision(1) << nozzle_diameter;
|
||||
std::string diameter_str = oss.str();
|
||||
|
||||
if(nozzle_volume_type.has_value()){
|
||||
return incompatible_filaments[get_nozzle_volume_type_string(nozzle_volume_type.value())][diameter_str];
|
||||
}
|
||||
|
||||
std::vector<std::string> incompatible_filaments_list;
|
||||
for(auto& [volume_type, diameter_list] : incompatible_filaments){
|
||||
auto iter = diameter_list.find(diameter_str);
|
||||
if(iter != diameter_list.end()){
|
||||
append(incompatible_filaments_list, iter->second);
|
||||
}
|
||||
}
|
||||
return incompatible_filaments_list;
|
||||
}
|
||||
|
||||
void Print::finalize_first_layer_convex_hull()
|
||||
{
|
||||
append(m_first_layer_convex_hull.points, m_skirt_convex_hull);
|
||||
|
||||
@@ -1080,6 +1080,7 @@ public:
|
||||
Vec2d translate_to_print_space(const Point &point) const;
|
||||
static FilamentTempType get_filament_temp_type(const std::string& filament_type);
|
||||
static int get_hrc_by_nozzle_type(const NozzleType& type);
|
||||
static std::vector<std::string> get_incompatible_filaments_by_nozzle(const float nozzle_diameter, const std::optional<NozzleVolumeType> nozzle_volume_type = std::nullopt);
|
||||
static FilamentCompatibilityType check_multi_filaments_compatibility(const std::vector<std::string>& filament_types);
|
||||
// similar to check_multi_filaments_compatibility, but the input is int, and may be negative (means unset)
|
||||
static bool is_filaments_compatible(const std::vector<int>& types);
|
||||
|
||||
@@ -137,6 +137,11 @@ std::string& get_right_extruder_unprintable_text() {
|
||||
return right_unprintable_text;
|
||||
}
|
||||
|
||||
std::string& get_nozzle_filament_incompatible_text() {
|
||||
static std::string nozzle_filament_incompatible_text;
|
||||
return nozzle_filament_incompatible_text;
|
||||
}
|
||||
|
||||
static std::string format_number(float value)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
@@ -3030,15 +3035,19 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||
//if (printer_technology != ptSLA || !contained_min_one)
|
||||
// _set_warning_notification(EWarning::SlaSupportsOutside, false);
|
||||
|
||||
bool tpu_valid = cur_plate->check_tpu_printable_status(wxGetApp().preset_bundle->full_config(), wxGetApp().preset_bundle->get_used_tpu_filaments(cur_plate->get_extruders(true)));
|
||||
auto full_config_temp = wxGetApp().preset_bundle->full_config();
|
||||
bool tpu_valid = cur_plate->check_tpu_printable_status(full_config_temp, wxGetApp().preset_bundle->get_used_tpu_filaments(cur_plate->get_extruders(true)));
|
||||
_set_warning_notification(EWarning::TPUPrintableError, !tpu_valid);
|
||||
|
||||
bool filament_printable = cur_plate->check_filament_printable(wxGetApp().preset_bundle->full_config(), filament_printable_error_msg);
|
||||
bool filament_printable = cur_plate->check_filament_printable(full_config_temp, filament_printable_error_msg);
|
||||
_set_warning_notification(EWarning::FilamentPrintableError, !filament_printable);
|
||||
|
||||
bool mix_pla_and_petg = cur_plate->check_mixture_of_pla_and_petg(wxGetApp().preset_bundle->full_config());
|
||||
bool mix_pla_and_petg = cur_plate->check_mixture_of_pla_and_petg(full_config_temp);
|
||||
_set_warning_notification(EWarning::MixUsePLAAndPETG, !mix_pla_and_petg);
|
||||
|
||||
bool filament_nozzle_compatible = cur_plate->check_compatible_of_nozzle_and_filament(full_config_temp, wxGetApp().preset_bundle->filament_presets, get_nozzle_filament_incompatible_text());
|
||||
_set_warning_notification(EWarning::NozzleFilamentIncompatible, !filament_nozzle_compatible);
|
||||
|
||||
bool model_fits = contained_min_one && !m_model->objects.empty() && !partlyOut && object_results.filaments.empty() && tpu_valid && filament_printable;
|
||||
post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, model_fits));
|
||||
ppl.get_curr_plate()->update_slice_ready_status(model_fits);
|
||||
@@ -3056,6 +3065,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||
_set_warning_notification(EWarning::PrimeTowerOutside, false);
|
||||
_set_warning_notification(EWarning::MultiExtruderPrintableError,false);
|
||||
_set_warning_notification(EWarning::MultiExtruderHeightOutside,false);
|
||||
_set_warning_notification(EWarning::NozzleFilamentIncompatible,false);
|
||||
|
||||
post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, false));
|
||||
}
|
||||
}
|
||||
@@ -10105,6 +10116,10 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
|
||||
case EWarning::PrimeTowerOutside:
|
||||
text = _u8L("The prime tower extends beyond the plate boundary.");
|
||||
break;
|
||||
case EWarning::NozzleFilamentIncompatible: {
|
||||
text = _u8L(get_nozzle_filament_incompatible_text());
|
||||
break;
|
||||
}
|
||||
}
|
||||
//BBS: this may happened when exit the app, plater is null
|
||||
if (!wxGetApp().plater())
|
||||
@@ -10129,6 +10144,14 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
|
||||
else
|
||||
notification_manager.close_slicing_customize_error_notification(NotificationType::BBLMixUsePLAAndPETG, NotificationLevel::WarningNotificationLevel);
|
||||
}
|
||||
else if (warning == EWarning::NozzleFilamentIncompatible){
|
||||
if(state){
|
||||
notification_manager.push_slicing_customize_error_notification(NotificationType::BBLNozzleFilamentIncompatible, NotificationLevel::WarningNotificationLevel, text);
|
||||
}
|
||||
else{
|
||||
notification_manager.close_slicing_customize_error_notification(NotificationType::BBLNozzleFilamentIncompatible, NotificationLevel::WarningNotificationLevel);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (state)
|
||||
notification_manager.push_plater_warning_notification(text);
|
||||
|
||||
@@ -393,6 +393,7 @@ class GLCanvas3D
|
||||
FilamentUnPrintableOnFirstLayer,
|
||||
MixUsePLAAndPETG,
|
||||
PrimeTowerOutside,
|
||||
NozzleFilamentIncompatible,
|
||||
};
|
||||
|
||||
class RenderStats
|
||||
|
||||
@@ -159,6 +159,7 @@ enum class NotificationType
|
||||
BBLSliceMultiExtruderHeightOutside,
|
||||
BBLBedFilamentIncompatible,
|
||||
BBLMixUsePLAAndPETG,
|
||||
BBLNozzleFilamentIncompatible,
|
||||
NotificationTypeCount
|
||||
|
||||
};
|
||||
|
||||
@@ -1787,6 +1787,85 @@ bool PartPlate::check_mixture_of_pla_and_petg(const DynamicPrintConfig &config)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PartPlate::check_compatible_of_nozzle_and_filament(const DynamicPrintConfig &config, const std::vector<std::string> &filament_presets, std::string &error_msg)
|
||||
{
|
||||
float nozzle_diameter = config.option<ConfigOptionFloatsNullable>("nozzle_diameter")->values[0];
|
||||
auto volume_type_opt = config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
|
||||
|
||||
auto get_filament_alias = [](std::string preset_name) -> std::string {
|
||||
size_t at_pos = preset_name.find('@');
|
||||
std::string alias = preset_name.substr(0, at_pos);
|
||||
size_t first = alias.find_first_not_of(' ');
|
||||
if (first == std::string::npos) return "";
|
||||
size_t last = alias.find_last_not_of(' ');
|
||||
return alias.substr(first, last - first + 1);
|
||||
};
|
||||
|
||||
bool with_same_volume_type = std::all_of(volume_type_opt->values.begin(), volume_type_opt->values.end(),
|
||||
[first_value = volume_type_opt->values[0]](int value) { return value == first_value; });
|
||||
|
||||
std::set<std::string> selected_filament_alias;
|
||||
for (auto &filament_preset : filament_presets) { selected_filament_alias.insert(get_filament_alias(filament_preset)); }
|
||||
|
||||
auto get_incompatible_selected = [&](const NozzleVolumeType volume_type) -> std::set<std::string> {
|
||||
std::vector<std::string> incompatible_filaments = Print::get_incompatible_filaments_by_nozzle(nozzle_diameter, volume_type);
|
||||
std::set<std::string> ret;
|
||||
for (auto &filament : selected_filament_alias) {
|
||||
if (std::find(incompatible_filaments.begin(), incompatible_filaments.end(), filament) != incompatible_filaments.end()) ret.insert(filament);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
auto get_nozzle_msg = [](const float nozzle_diameter, const NozzleVolumeType volume_type) -> std::string {
|
||||
std::ostringstream oss;
|
||||
oss << std::fixed << std::setprecision(1) << nozzle_diameter;
|
||||
std::string nozzle_msg = oss.str();
|
||||
((nozzle_msg += "mm ") += _u8L(get_nozzle_volume_type_string(volume_type))) += _u8L(" nozzle");
|
||||
return nozzle_msg;
|
||||
};
|
||||
|
||||
auto get_incompatible_filament_msg = [](const std::set<std::string> &incompatible_selected_filaments) -> std::string {
|
||||
std::string filament_str;
|
||||
size_t idx = 0;
|
||||
for (const auto &filament : incompatible_selected_filaments) {
|
||||
if (idx > 0) filament_str += ',';
|
||||
filament_str += filament;
|
||||
++idx;
|
||||
}
|
||||
return filament_str;
|
||||
};
|
||||
|
||||
error_msg.clear();
|
||||
|
||||
std::set<int> nozzle_volumes(volume_type_opt->values.begin(), volume_type_opt->values.end());
|
||||
std::map<NozzleVolumeType, std::set<std::string>> incompatible_selected_map;
|
||||
|
||||
for (auto volume_type_value : nozzle_volumes) {
|
||||
NozzleVolumeType volume_type = static_cast<NozzleVolumeType>(volume_type_value);
|
||||
auto incompatible_selected = get_incompatible_selected(volume_type);
|
||||
if (!incompatible_selected.empty()) incompatible_selected_map[volume_type] = incompatible_selected;
|
||||
}
|
||||
|
||||
if (incompatible_selected_map.empty()) return true;
|
||||
|
||||
if (incompatible_selected_map.size() == 1) {
|
||||
auto elem = incompatible_selected_map.begin();
|
||||
NozzleVolumeType volume_type = elem->first;
|
||||
auto incompatible_selected = elem->second;
|
||||
error_msg = GUI::format(_L("It is not recommended to print the following filament(s) with %1%: %2%\n"), get_nozzle_msg(nozzle_diameter, volume_type),
|
||||
get_incompatible_filament_msg(incompatible_selected));
|
||||
} else {
|
||||
std::string warning_msg = _u8L("It is not recommended to use the following nozzle and filament combinations:\n");
|
||||
for (auto &elem : incompatible_selected_map) {
|
||||
NozzleVolumeType volume_type = elem.first;
|
||||
auto incompatible_selected = elem.second;
|
||||
warning_msg += GUI::format(_L("%1% with %2%\n"),get_nozzle_msg(nozzle_diameter, volume_type), get_incompatible_filament_msg(incompatible_selected));
|
||||
}
|
||||
error_msg = warning_msg;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*Vec3d PartPlate::calculate_wipe_tower_size(const DynamicPrintConfig &config, const double w, const double wipe_volume, int plate_extruder_size, bool use_global_objects) const
|
||||
{
|
||||
Vec3d wipe_tower_size;
|
||||
|
||||
@@ -335,6 +335,7 @@ public:
|
||||
bool check_filament_printable(const DynamicPrintConfig & config, wxString& error_message);
|
||||
bool check_tpu_printable_status(const DynamicPrintConfig & config, const std::vector<int> &tpu_filaments);
|
||||
bool check_mixture_of_pla_and_petg(const DynamicPrintConfig & config);
|
||||
bool check_compatible_of_nozzle_and_filament(const DynamicPrintConfig & config, const std::vector<std::string>& filament_presets, std::string& error_msg);
|
||||
|
||||
/* instance related operations*/
|
||||
//judge whether instance is bound in plate or not
|
||||
|
||||
Reference in New Issue
Block a user