diff --git a/resources/profiles/BBL.json b/resources/profiles/BBL.json index 7ba02f29c6..f822fe3145 100644 --- a/resources/profiles/BBL.json +++ b/resources/profiles/BBL.json @@ -1,7 +1,7 @@ { "name": "Bambulab", "url": "http://www.bambulab.com/Parameters/vendor/BBL.json", - "version": "02.00.00.12", + "version": "02.00.00.15", "force_update": "0", "description": "the initial version of BBL configurations", "machine_model_list": [ diff --git a/resources/profiles/BBL/machine/Bambu Lab H2D 0.4 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab H2D 0.4 nozzle.json index 955ad456ff..1b8715c6f6 100644 --- a/resources/profiles/BBL/machine/Bambu Lab H2D 0.4 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab H2D 0.4 nozzle.json @@ -28,6 +28,10 @@ "25x0,350x0,350x320,25x320" ], "machine_load_filament_time": "24", + "unprintable_filament_types" : [ + "TPU", + "PPS-CF,PPA-CF" + ], "machine_max_acceleration_x": [ "16000", "16000", diff --git a/resources/profiles/BBL/machine/fdm_bbl_3dp_001_common.json b/resources/profiles/BBL/machine/fdm_bbl_3dp_001_common.json index e4ef14e9ac..dfd139f20b 100644 --- a/resources/profiles/BBL/machine/fdm_bbl_3dp_001_common.json +++ b/resources/profiles/BBL/machine/fdm_bbl_3dp_001_common.json @@ -37,6 +37,7 @@ ], "extruder_printable_area": [], "extruder_printable_height": [], + "unprintable_filament_types" : [""], "extruder_type": [ "Direct Drive" ], diff --git a/resources/profiles/BBL/machine/fdm_bbl_3dp_002_common.json b/resources/profiles/BBL/machine/fdm_bbl_3dp_002_common.json index e382cee2f4..f18ab3958e 100644 --- a/resources/profiles/BBL/machine/fdm_bbl_3dp_002_common.json +++ b/resources/profiles/BBL/machine/fdm_bbl_3dp_002_common.json @@ -46,6 +46,10 @@ "320", "325" ], + "unprintable_filament_types" : [ + "", + "" + ], "extruder_type": [ "Direct Drive", "Direct Drive" diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index dab5de84d5..0772e65408 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -55,6 +55,26 @@ bool LayerTools::is_extruder_order(unsigned int a, unsigned int b) const return false; } +bool check_filament_printable_after_group(const std::vector &used_filaments, const std::vector &filament_maps, const PrintConfig *print_config) +{ + for (unsigned int filament_id : used_filaments) { + std::string filament_type = print_config->filament_type.get_at(filament_id); + for (size_t idx = 0; idx < print_config->unprintable_filament_types.values.size(); ++idx) { + if (filament_maps[filament_id] == idx) { + std::vector limit_types = split_string(print_config->unprintable_filament_types.get_at(idx), ','); + auto iter = std::find(limit_types.begin(), limit_types.end(), filament_type); + if (iter != limit_types.end()) { + std::string error_msg; + std::string extruder_name = idx == 0 ? "left" : "right"; + error_msg = "Grouping error: " + filament_type + " can not be placed in the " + extruder_name + " extruder"; + throw Slic3r::RuntimeError(error_msg); + } + } + } + } + return true; +} + // Return a zero based extruder from the region, or extruder_override if overriden. unsigned int LayerTools::wall_filament(const PrintRegion ®ion) const { @@ -1046,6 +1066,14 @@ std::vector ToolOrdering::get_recommended_filament_maps(const std::vector s_Preset_printer_options { "single_extruder_multi_material", "manual_filament_change", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "printing_by_object_gcode", "layer_change_gcode", "time_lapse_gcode", "change_filament_gcode", "change_extrusion_role_gcode", "printer_model", "printer_variant", "printer_extruder_id", "printer_extruder_variant", "extruder_variant_list", "default_nozzle_volume_type", "printable_height", "extruder_printable_height", "extruder_clearance_radius", "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod", - "nozzle_height", + "nozzle_height", "unprintable_filament_types", "default_print_profile", "inherits", "silent_mode", "scan_first_layer", "machine_load_filament_time", "machine_unload_filament_time", "machine_tool_change_time", "time_cost", "machine_pause_gcode", "template_custom_gcode", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 0b24c1c1f0..7ec6c1fba0 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -671,6 +671,12 @@ void PrintConfigDef::init_common_params() def->mode = comSimple; def->set_default_value(new ConfigOptionFloatsNullable{}); + def = this->add("unprintable_filament_types", coStrings); + def->label = L("Unprintable filament type"); + def->tooltip = L("Unprintable filament type"); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionStrings{""}); + def = this->add("preferred_orientation", coFloat); def->label = L("Preferred orientation"); def->tooltip = L("Automatically orient stls on the Z-axis upon initial import."); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 299893db4c..9aed054a6e 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1349,6 +1349,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionPoints, bed_exclude_area)) ((ConfigOptionPoints, head_wrap_detect_zone)) // BBS + ((ConfigOptionStrings, unprintable_filament_types)) ((ConfigOptionString, bed_custom_texture)) ((ConfigOptionString, bed_custom_model)) ((ConfigOptionEnum, curr_bed_type)) diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 1f252b2764..70be67e585 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -180,6 +180,7 @@ extern size_t get_utf8_sequence_length(const char *seq, size_t size); extern local_encoded_string encode_path(const char *src); extern std::string decode_path(const char *src); extern std::string normalize_utf8_nfc(const char *src); +extern std::vector split_string(const std::string &str, char delimiter); // Safely rename a file even if the target exists. // On Windows, the file explorer (or anti-virus or whatever else) often locks the file diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 744eb98311..d102dd9875 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -1126,6 +1126,18 @@ std::string normalize_utf8_nfc(const char *src) return boost::locale::normalize(src, boost::locale::norm_nfc, locale_utf8); } +std::vector split_string(const std::string &str, char delimiter) +{ + std::vector result; + std::stringstream ss(str); + std::string substr; + + while (std::getline(ss, substr, delimiter)) { + result.push_back(substr); + } + return result; +} + namespace PerlUtils { // Get a file name including the extension. std::string path_to_filename(const char *src) { return boost::filesystem::path(src).filename().string(); } diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 527f1d271c..2419fd4ff9 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -285,9 +285,23 @@ PrinterArch get_printer_arch_by_str(std::string arch_str) void check_filaments_for_vt_slot(const std::string &tag_vendor, const std::string &tag_type, int ams_id, bool &in_blacklist, std::string &ac, std::string &info) { + DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager(); + if (!dev) + return; + + MachineObject *obj = dev->get_selected_machine(); + if (obj == nullptr) + return; + if (tag_type == "TPU" && ams_id != VIRTUAL_TRAY_MAIN_ID) { + wxString extruder_name = _L("left"); + if (obj->is_main_extruder_on_left()) { + extruder_name = _L("right"); + } + wxString info_str = wxString::Format(_L("TPU is not supported by %s extruder for this printer."), extruder_name); + ac = "prohibition"; - info = wxString(_L("TPU is not supported by deputy extruder.")).ToUTF8().data(); + info = info_str.ToUTF8().data(); in_blacklist = true; } } @@ -7080,7 +7094,6 @@ void DeviceManager::load_last_machine() json DeviceManager::filaments_blacklist = json::object(); - std::string DeviceManager::parse_printer_type(std::string type_str) { return get_value_from_config(type_str, "printer_type"); @@ -7243,8 +7256,54 @@ bool DeviceManager::is_virtual_slot(int ams_id) return false; } +bool DeviceManager::check_filaments_printable(const std::string &tag_vendor, const std::string &tag_type, int ams_id, bool &in_blacklist, std::string &ac, std::string &info) +{ + DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager(); + if (!dev) { + return true; + } + + MachineObject *obj = dev->get_selected_machine(); + if (obj == nullptr || !obj->is_multi_extruders()) { + return true; + } + + Preset *printer_preset = GUI::get_printer_preset(obj); + if (!printer_preset) + return true; + + ConfigOptionStrings *unprintable_filament_types_op = dynamic_cast(printer_preset->config.option("unprintable_filament_types")); + if (!unprintable_filament_types_op) + return true; + + ConfigOptionInts *physical_extruder_map_op = dynamic_cast(printer_preset->config.option("physical_extruder_map")); + if (!physical_extruder_map_op) + return true; + + std::vector physical_extruder_maps = physical_extruder_map_op->values; + for (size_t idx = 0; idx < unprintable_filament_types_op->values.size(); ++idx) { + if (physical_extruder_maps[idx] == obj->get_extruder_id_by_ams_id(std::to_string(ams_id))) { + std::vector filament_types = split_string(unprintable_filament_types_op->values.at(idx), ','); + auto iter = std::find(filament_types.begin(), filament_types.end(), tag_type); + if (iter != filament_types.end()) { + wxString extruder_name = idx == 0 ? _L("left") : _L("right"); + ac = "prohibition"; + info = (wxString::Format(_L("%s is not supported by %s extruder."), tag_type, extruder_name)).ToUTF8().data(); + in_blacklist = true; + return false; + } + } + } + + return true; +} + void DeviceManager::check_filaments_in_blacklist(std::string tag_vendor, std::string tag_type, int ams_id, bool& in_blacklist, std::string& ac, std::string& info) { + if (!check_filaments_printable(tag_vendor, tag_type, ams_id, in_blacklist, ac, info)) { + return; + } + if (DeviceManager::is_virtual_slot(ams_id)) { check_filaments_for_vt_slot(tag_vendor, tag_type, ams_id, in_blacklist, ac, info); return; diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 71bbe99307..111d9cfa73 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -1302,6 +1302,7 @@ public: static bool key_field_only; static json function_table; static json filaments_blacklist; + static json filaments_printable_blacklist; template static T get_value_from_config(std::string type_str, std::string item){ @@ -1337,6 +1338,7 @@ public: static std::vector get_resolution_supported(std::string type_str); static std::vector get_compatible_machine(std::string type_str); static void check_filaments_in_blacklist(std::string tag_vendor, std::string tag_type, int ams_id, bool &in_blacklist, std::string &ac, std::string &info); + static bool check_filaments_printable(const std::string &tag_vendor, const std::string &tag_type, int ams_id, bool &in_blacklist, std::string &ac, std::string &info); static boost::bimaps::bimap get_all_model_id_with_name(); static std::string load_gcode(std::string type_str, std::string gcode_file); static bool is_virtual_slot(int ams_id); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a79e73c5bb..e8bfaa3079 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -118,6 +118,8 @@ std::string object_limited_text = _u8L("An object is laid on the left/right extr std::string object_clashed_text = _u8L("An object is laid over the boundary of plate or exceeds the height limit.\n" "Please solve the problem by moving it totally on or off the plate, and confirming that the height is within the build volume."); +wxString filament_printable_error_msg; + GLCanvas3D::LayersEditing::~LayersEditing() { if (m_z_texture_id != 0) { @@ -2922,6 +2924,9 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re 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))); _set_warning_notification(EWarning::TPUPrintableError, !tpu_valid); + bool filament_printable = cur_plate->check_filament_printable(wxGetApp().preset_bundle->full_config(), filament_printable_error_msg); + _set_warning_notification(EWarning::FilamentPrintableError, !filament_printable); + bool model_fits = contained_min_one && !m_model->objects.empty() && !partlyOut && object_results.filaments.empty() && tpu_valid; post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, model_fits)); ppl.get_curr_plate()->update_slice_ready_status(model_fits); @@ -2932,6 +2937,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re _set_warning_notification(EWarning::ObjectLimited, false); //_set_warning_notification(EWarning::SlaSupportsOutside, false); _set_warning_notification(EWarning::TPUPrintableError, false); + _set_warning_notification(EWarning::FilamentPrintableError, false); post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, false)); } } @@ -9834,6 +9840,11 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) error = ErrorType::SLICING_ERROR; break; } + case EWarning::FilamentPrintableError: { + text = filament_printable_error_msg.ToUTF8(); + error = ErrorType::SLICING_ERROR; + break; + } case EWarning::MultiExtruderPrintableError: { for (auto error_iter = m_gcode_viewer.m_gcode_check_result.print_area_error_infos.begin(); error_iter != m_gcode_viewer.m_gcode_check_result.print_area_error_infos.end(); ++error_iter) { if (error_iter != m_gcode_viewer.m_gcode_check_result.print_area_error_infos.begin()) { @@ -9990,10 +10001,18 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) notification_manager.close_slicing_serious_warning_notification(text); break; case SLICING_ERROR: - if (state) - notification_manager.push_slicing_error_notification(text, conflictObj ? std::vector{conflictObj} : std::vector{}); - else - notification_manager.close_slicing_error_notification(text); + if (warning == EWarning::FilamentPrintableError) { + if (state) + notification_manager.push_slicing_customize_error_notification(NotificationType::BBLFilamentPrintableError, NotificationManager::NotificationLevel::ErrorNotificationLevel, text); + else + notification_manager.close_slicing_customize_error_notification(NotificationType::BBLFilamentPrintableError, NotificationManager::NotificationLevel::ErrorNotificationLevel); + } + else { + if (state) + notification_manager.push_slicing_error_notification(text, conflictObj ? std::vector{conflictObj} : std::vector{}); + else + notification_manager.close_slicing_error_notification(text); + } break; case SLICING_LIMIT_ERROR: if (state) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 9861847e8d..42c9f012ec 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -385,6 +385,7 @@ class GLCanvas3D GCodeConflict, ToolHeightOutside, TPUPrintableError, + FilamentPrintableError, MultiExtruderPrintableError, // after slice MultiExtruderHeightOutside, // after slice FilamentUnPrintableOnFirstLayer diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index e3a2ad59e8..fa1727b3d0 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -152,6 +152,7 @@ enum class NotificationType BBLPreviewOnlyMode, BBLPrinterConfigUpdateAvailable, BBLUserPresetExceedLimit, + BBLFilamentPrintableError, BBLSliceLimitError, BBLSliceMultiExtruderHeightOutside, NotificationTypeCount diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 2db1e4423a..7f54d47440 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -1727,6 +1727,29 @@ std::vector PartPlate::get_used_filaments() return std::vector(used_extruders_set.begin(), used_extruders_set.end()); } +bool PartPlate::check_filament_printable(const DynamicPrintConfig &config, wxString& error_message) +{ + error_message.clear(); + std::vector used_filaments = get_extruders(true); // 1 base + if (!used_filaments.empty()) { + for (auto filament_idx : used_filaments) { + int filament_id = filament_idx - 1; + std::string filament_type = config.option("filament_type")->values.at(filament_id); + std::vector filament_map = get_real_filament_maps(config); + int extruder_idx = filament_map[filament_id] - 1; + std::string filament_types_str = config.option("unprintable_filament_types")->values.at(extruder_idx); + std::vector filament_types = split_string(filament_types_str, ','); + auto iter = std::find(filament_types.begin(), filament_types.end(), filament_type); + if (iter != filament_types.end()) { + wxString extruder_name = extruder_idx == 0 ? _L("left") : _L("right"); + error_message = wxString::Format(_L("Filament %s cannot be placed in the %s extruder for printing."), filament_type, extruder_name); + return false; + } + } + } + return true; +} + bool PartPlate::check_tpu_printable_status(const DynamicPrintConfig & config, const std::vector &tpu_filaments) { bool tpu_valid = true; diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index dfaa9cd4fa..e5e4b837e8 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -331,6 +331,7 @@ public: // get used filaments from gcode result, 1 based idx std::vector get_used_filaments(); int get_physical_extruder_by_filament_id(const DynamicConfig& g_config, int idx) const; + bool check_filament_printable(const DynamicPrintConfig & config, wxString& error_message); bool check_tpu_printable_status(const DynamicPrintConfig & config, const std::vector &tpu_filaments); /* instance related operations*/