From 0c415708d74b70aa7763c3a85c0ab58258440830 Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Sat, 2 May 2026 14:11:34 +0300 Subject: [PATCH 01/44] PR #12525 follow-up (#13440) Decouple chamber temperature - make chamber_temperature variable always accessible --- src/slic3r/GUI/Tab.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 868b537879..2066de7e65 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4267,14 +4267,7 @@ void TabFilament::toggle_options() toggle_line("pellet_flow_coefficient", is_pellet_printer); toggle_line("filament_diameter", !is_pellet_printer); - bool support_chamber_temp_control = printer_cfg.opt_bool("support_chamber_temp_control"); - toggle_line("activate_chamber_temp_control", support_chamber_temp_control); - toggle_line("chamber_temperature", support_chamber_temp_control); - - if (support_chamber_temp_control) { - bool activate_chamber_temp_control = m_config->opt_bool("activate_chamber_temp_control", 0); - toggle_option("chamber_temperature", activate_chamber_temp_control); - } + toggle_line("activate_chamber_temp_control", printer_cfg.opt_bool("support_chamber_temp_control")); std::string volumetric_speed_cos = m_config->opt_string("volumetric_speed_coefficients", 0u); bool enable_fit = volumetric_speed_cos != "0 0 0 0 0 0"; From 0ee62a966268e8dcbabce75afa63a7feb473618b Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Sun, 3 May 2026 00:24:09 +0300 Subject: [PATCH 02/44] Fix role-based fan speeds being lost on layer change (#13390) --- src/libslic3r/GCode.cpp | 7 ++++++- src/libslic3r/GCode.hpp | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 35af30514a..f601504687 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2419,6 +2419,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato m_max_layer_z = 0.f; m_last_width = 0.f; m_is_role_based_fan_on.fill(false); + m_role_based_fan_marker_layer.fill(-1); m_fan_mover.release(); @@ -6746,11 +6747,14 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, assert(m_enable_cooling_markers); if (fan_on) { - if (!m_is_role_based_fan_on[role]) { + // Orca: CoolingBuffer consumes role fan markers per layer, so continuing + // role-based fan regions need a fresh START marker on each new layer. + if (!m_is_role_based_fan_on[role] || m_role_based_fan_marker_layer[role] != m_layer_index) { gcode += ";"; gcode += marker_prefix; gcode += "_FAN_START\n"; m_is_role_based_fan_on[role] = true; + m_role_based_fan_marker_layer[role] = m_layer_index; } } else { if (m_is_role_based_fan_on[role]) { @@ -6758,6 +6762,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, gcode += marker_prefix; gcode += "_FAN_END\n"; m_is_role_based_fan_on[role] = false; + m_role_based_fan_marker_layer[role] = -1; } } }; diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index fb2a546890..03e76a1eff 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -559,6 +559,7 @@ private: std::string _encode_label_ids_to_base64(std::vector ids); // ORCA: Add support for role based fan speed control std::array m_is_role_based_fan_on; + std::array m_role_based_fan_marker_layer; // Markers for the Pressure Equalizer to recognize the extrusion type. // The Pressure Equalizer removes the markers from the final G-code. bool m_enable_extrusion_role_markers; From 6fd4984cad4fb913ef46050cf5983260d21e2229 Mon Sep 17 00:00:00 2001 From: Valerii Bokhan <80919135+valerii-bokhan@users.noreply.github.com> Date: Sat, 2 May 2026 23:35:15 +0200 Subject: [PATCH 03/44] Fix: Fixing the range check in ZAA code (#13452) --- src/libslic3r/PrintObjectSlice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index abeb420e00..1e59b44e30 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -48,7 +48,7 @@ LayerPtrs new_layers( } if (zaa_active) { slice_z = lo + z_offset; - if (slice_z < lo || slice_z > hi) { + if ((slice_z < lo && !is_approx(slice_z, lo)) || (slice_z > hi && !is_approx(slice_z, hi))) { throw RuntimeError("Bad min Z value"); } } From 66b3d5e26305d6ca993035329adf2d867369c7e9 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sun, 3 May 2026 15:42:45 +0800 Subject: [PATCH 04/44] Fix/fixed unicode preset name issue (#13458) * fixed an issue for unicode preset name --- src/slic3r/GUI/PresetComboBoxes.cpp | 10 +++++----- src/slic3r/GUI/Tab.cpp | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 0fd7374f3c..93a67601a7 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -1175,8 +1175,8 @@ void PlaterPresetComboBox::update() } bool single_bar = false; - wxString name = preset.name; - preset_aliases[name] = get_preset_name(preset).ToStdString(); // ORCA + wxString name = from_u8(preset.name); + preset_aliases[name] = get_preset_name(preset).utf8_string(); // ORCA // Track bundle names for bundled presets if (preset.is_from_bundle()) { @@ -1232,7 +1232,7 @@ void PlaterPresetComboBox::update() name = from_u8(is_selected && preset.is_dirty ? Preset::suffix_modified() + printer_model : printer_model); if (system_printer_models.count(printer_model) == 0) { - preset_aliases[name] = name.ToStdString(); // ORCA + preset_aliases[name] = name.utf8_string(); // ORCA system_presets.emplace(name, bmp); system_printer_models.insert(printer_model); } @@ -1676,8 +1676,8 @@ void TabPresetComboBox::update() wxBitmap* bmp = get_bmp(preset); assert(bmp); - const wxString name = preset.name; - preset_aliases[name] = get_preset_name(preset).ToStdString(); + const wxString name = from_u8(preset.name); + preset_aliases[name] = get_preset_name(preset).utf8_string(); if (preset.is_system) preset_descriptions.emplace(name, from_u8(preset.description)); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 2066de7e65..c9c5bbe4c9 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -6808,10 +6808,10 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep // Collect and set indices of depending_presets marked as compatible. wxArrayInt selections; auto *compatible_printers = dynamic_cast(m_config->option(deps.key_list)); - if (compatible_printers != nullptr || !compatible_printers->values.empty()) + if (compatible_printers != nullptr && !compatible_printers->values.empty()) for (auto preset_name : compatible_printers->values) for (size_t idx = 0; idx < presets.GetCount(); ++idx) - if (presets[idx] == preset_name) { + if (presets[idx] == from_u8(preset_name)) { selections.Add(idx); break; } From 522343a193ccf9a86d901a12913334e196b6116a Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sun, 3 May 2026 16:04:22 +0800 Subject: [PATCH 05/44] make the uuid generation more robust --- src/slic3r/Utils/OrcaCloudServiceAgent.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/slic3r/Utils/OrcaCloudServiceAgent.cpp b/src/slic3r/Utils/OrcaCloudServiceAgent.cpp index f8a242f7ae..abbebef42c 100644 --- a/src/slic3r/Utils/OrcaCloudServiceAgent.cpp +++ b/src/slic3r/Utils/OrcaCloudServiceAgent.cpp @@ -74,19 +74,21 @@ constexpr const char* SECRET_STORE_SERVICE = "OrcaSlicer/Auth"; constexpr const char* SECRET_STORE_USER = "orca_refresh_token"; constexpr std::chrono::seconds TOKEN_REFRESH_SKEW{900}; // 15 minutes -std::string generate_uuid_for_setting_id(const std::string& name = "") +std::string generate_uuid_for_setting_id(const std::string& name, const std::string& user_id = "") { if (name.empty()) { return ""; } - // Use a fixed namespace UUID for OrcaSlicer profiles - // This ensures the same name always generates the same UUID + // Mix user_id into the hashed input so two different users generating a setting_id + // for an identically-named preset get distinct UUIDs. Without this, the cloud's ID + // space collides across accounts and the second user's create gets HTTP 409 with + // server_profile=null on every sync (the foreign owner's record is not exposed). static const boost::uuids::uuid orca_namespace = boost::uuids::string_generator()("f47ac10b-58cc-4372-a567-0e02b2c3d479"); boost::uuids::name_generator_sha1 gen(orca_namespace); - boost::uuids::uuid id = gen(name); + boost::uuids::uuid id = user_id.empty() ? gen(name) : gen(user_id + "/" + name); return boost::uuids::to_string(id); } @@ -904,7 +906,7 @@ int OrcaCloudServiceAgent::get_user_presets(std::map* values_map, unsigned int* http_code) { - std::string new_id = generate_uuid_for_setting_id(name); + std::string new_id = generate_uuid_for_setting_id(name, get_user_id()); if (new_id.empty()) { BOOST_LOG_TRIVIAL(error) << "OrcaCloudServiceAgent: request_setting_id failed - name is empty"; return ""; From 84d896bbd378215af7480dd43653c8c86bde3879 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sun, 3 May 2026 16:59:30 +0800 Subject: [PATCH 06/44] fixes an issue that devmgr ping cloud server every second Co-authored-by: Copilot --- src/slic3r/GUI/DeviceCore/DevManager.cpp | 5 +++-- src/slic3r/GUI/DeviceCore/DevManager.h | 2 +- src/slic3r/Utils/NetworkAgent.cpp | 12 ++++++++++-- src/slic3r/Utils/NetworkAgent.hpp | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/DeviceCore/DevManager.cpp b/src/slic3r/GUI/DeviceCore/DevManager.cpp index 5535f8b696..0e197a236b 100644 --- a/src/slic3r/GUI/DeviceCore/DevManager.cpp +++ b/src/slic3r/GUI/DeviceCore/DevManager.cpp @@ -913,12 +913,13 @@ namespace Slic3r } // do some refresh - if (Slic3r::GUI::wxGetApp().is_user_login(Slic3r::GUI::wxGetApp().get_printer_cloud_provider())) + const auto cloud_provider = Slic3r::GUI::wxGetApp().get_printer_cloud_provider(); + if (Slic3r::GUI::wxGetApp().is_user_login(cloud_provider)) { m_manager->check_pushing(); try { - agent->refresh_connection(); + agent->refresh_connection(cloud_provider); } catch (...) { diff --git a/src/slic3r/GUI/DeviceCore/DevManager.h b/src/slic3r/GUI/DeviceCore/DevManager.h index 095d9ea779..087e3312c9 100644 --- a/src/slic3r/GUI/DeviceCore/DevManager.h +++ b/src/slic3r/GUI/DeviceCore/DevManager.h @@ -116,7 +116,7 @@ public: class DeviceManagerRefresher : public wxObject { wxTimer* m_timer{ nullptr }; - int m_timer_interval_msec = 1000; + int m_timer_interval_msec = 5000; DeviceManager* m_manager{ nullptr }; diff --git a/src/slic3r/Utils/NetworkAgent.cpp b/src/slic3r/Utils/NetworkAgent.cpp index 32da6f0b3c..03e677b636 100644 --- a/src/slic3r/Utils/NetworkAgent.cpp +++ b/src/slic3r/Utils/NetworkAgent.cpp @@ -340,9 +340,17 @@ bool NetworkAgent::is_server_connected(const std::string& provider) return false; } -int NetworkAgent::refresh_connection() +int NetworkAgent::refresh_connection(const std::string& provider) { - return invoke_on_all_cloud_agents(m_cloud_agents, [](ICloudServiceAgent& cloud_agent) { return cloud_agent.refresh_connection(); }); + if(provider.empty()) + return invoke_on_all_cloud_agents(m_cloud_agents, [](ICloudServiceAgent& cloud_agent) { return cloud_agent.refresh_connection(); }); + else { + const auto cloud_agent = get_cloud_agent(provider); + if (cloud_agent) + return cloud_agent->refresh_connection(); + return -1; + } + } void NetworkAgent::enable_multi_machine(bool enable, const std::string& provider) diff --git a/src/slic3r/Utils/NetworkAgent.hpp b/src/slic3r/Utils/NetworkAgent.hpp index 74fb839aa4..e069066b58 100644 --- a/src/slic3r/Utils/NetworkAgent.hpp +++ b/src/slic3r/Utils/NetworkAgent.hpp @@ -71,7 +71,7 @@ public: int set_on_http_error_fn(AppOnHttpErrorFn fn); int set_get_country_code_fn(GetCountryCodeFn fn); int connect_server(); - int refresh_connection(); + int refresh_connection(const std::string& provider = ""); int change_user(std::string user_info, const std::string& provider = ORCA_CLOUD_PROVIDER); bool is_user_login(const std::string& provider = ORCA_CLOUD_PROVIDER); From d7955cad16cb95a001f5fe818b61f77f9b0a7d5d Mon Sep 17 00:00:00 2001 From: Ian Bassi Date: Sun, 3 May 2026 11:51:42 -0300 Subject: [PATCH 07/44] ZAA Wiki redirection + tooltip (#13446) * ZAA Wiki redirection + puntutation * Clarify tooltip text for Z parameters --- src/libslic3r/PrintConfig.cpp | 12 +++++++----- src/slic3r/GUI/Tab.cpp | 8 ++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index a2b54b5465..926439535c 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4124,15 +4124,16 @@ void PrintConfigDef::init_fff_params() def = this->add("zaa_enabled", coBool); def->label = L("Z contouring enabled"); def->category = L("Quality"); - def->tooltip = L("Enable Z-layer contouring (aka Z-layer anti-aliasing)"); + def->tooltip = L("Enable Z-layer contouring (aka Z-layer anti-aliasing)."); def->mode = comExpert; def->set_default_value(new ConfigOptionBool(false)); def = this->add("zaa_minimize_perimeter_height", coFloat); def->label = L("Minimize wall height angle"); def->category = L("Quality"); - def->tooltip = L("Reduce height of top surface perimeters to match height of model edge. " - "Effects perimeters whose slope is less than this angle in degrees. Reasonable value is 35. Set 0 to disable."); + def->tooltip = L("Reduce the height of top-surface perimeters to match the model edge height.\n" + "Affects perimeters with a slope less than this angle (degrees).\n" + "A reasonable value is 35. Set to 0 to disable."); def->sidetext = L("°"); def->min = 0; def->max = 90; @@ -4142,14 +4143,15 @@ void PrintConfigDef::init_fff_params() def = this->add("zaa_dont_alternate_fill_direction", coBool); def->label = L("Don't alternate fill direction"); def->category = L("Quality"); - def->tooltip = L("Disable alternating fill direction when using Z contouring"); + def->tooltip = L("Disable alternating fill direction when using Z contouring."); def->mode = comExpert; def->set_default_value(new ConfigOptionBool(false)); def = this->add("zaa_min_z", coFloat); def->label = L("Minimum z height"); def->category = L("Quality"); - def->tooltip = L("Minimum z layer height. Also controls slicing plane"); + def->tooltip = L("Minimum Z-layer height.\n" + "Also controls the slicing plane."); def->sidetext = L("mm"); def->min = 0; def->max = 100; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index c9c5bbe4c9..2b7ef7ce0f 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2321,10 +2321,10 @@ void TabPrint::build() optgroup->append_single_option_line("ironing_angle_fixed", "quality_settings_ironing#fixed-angle"); optgroup = page->new_optgroup("Z Contouring", L"param_advanced"); - optgroup->append_single_option_line("zaa_enabled"); - optgroup->append_single_option_line("zaa_minimize_perimeter_height"); - optgroup->append_single_option_line("zaa_min_z"); - optgroup->append_single_option_line("zaa_dont_alternate_fill_direction"); + optgroup->append_single_option_line("zaa_enabled", "quality_settings_z_contouring"); + optgroup->append_single_option_line("zaa_minimize_perimeter_height", "quality_settings_z_contouring#minimize-wall-height-angle"); + optgroup->append_single_option_line("zaa_min_z", "quality_settings_z_contouring#minimum-z-height"); + optgroup->append_single_option_line("zaa_dont_alternate_fill_direction", "quality_settings_z_contouring#dont-alternate-fill-direction"); // Orca: it's not used yet, so hide it in UI for now // optgroup->append_single_option_line("ironing_expansion"); From a3f229f4061718581c8faf8577e55683757d6581 Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Sun, 3 May 2026 18:36:02 +0300 Subject: [PATCH 08/44] Fix extrusion of some support layers at wrong Z height (again) (#13460) Fix extrusion of some support layers at wrong Z height Fixes the issue that PR #12736 (github.com/OrcaSlicer/OrcaSlicer/pull/12736) reverted the changes of PR #13327 (github.com/OrcaSlicer/OrcaSlicer/pull/13327) --- src/libslic3r/GCode.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index f601504687..8a04640cbb 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -6232,7 +6232,6 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, gcode += this->travel_to(first_point, path.role(), "move to first " + description + " point", z); - m_need_change_layer_lift_z = false; // Orca: ensure Z matches planned layer height if (!slope_need_z_travel && (_last_pos_undefined || m_need_change_layer_lift_z)) { const std::string z_sync_comment = _last_pos_undefined ? From 1d4c7c56a2bccd73f8330ff3978c70e5fb9824f9 Mon Sep 17 00:00:00 2001 From: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> Date: Mon, 4 May 2026 04:52:34 -0300 Subject: [PATCH 09/44] Fix crash ZAA (#13450) fix crash zaa Co-authored-by: SoftFever --- src/libslic3r/ExtrusionEntity.hpp | 6 +++++- src/libslic3r/Polygon.cpp | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index ce74d93e9e..b8251bf3d0 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -491,7 +491,11 @@ public: { Polygons out; this->polygons_covered_by_spacing(out, scaled_epsilon); return out; } // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm. double min_mm3_per_mm() const override; - Polyline as_polyline() const override { return this->polygon().split_at_first_point(); } + Polyline as_polyline() const override { + if (this->paths.empty() || this->length() <= 0.) + return Polyline(); + return this->polygon().split_at_first_point(); + } void collect_polylines(Polylines &dst) const override { Polyline pl = this->as_polyline(); if (! pl.empty()) dst.emplace_back(std::move(pl)); } void collect_points(Points &dst) const override { size_t n = std::accumulate(paths.begin(), paths.end(), 0, [](const size_t n, const ExtrusionPath &p){ return n + p.polyline.size(); }); diff --git a/src/libslic3r/Polygon.cpp b/src/libslic3r/Polygon.cpp index 9ecc2630d4..32b4d062f1 100644 --- a/src/libslic3r/Polygon.cpp +++ b/src/libslic3r/Polygon.cpp @@ -38,6 +38,9 @@ Polyline Polygon::split_at_vertex(const Point &point) const Polyline Polygon::split_at_index(int index) const { Polyline polyline; + if (this->points.empty()) + return polyline; + polyline.points.reserve(this->points.size() + 1); for (Points::const_iterator it = this->points.begin() + index; it != this->points.end(); ++it) polyline.points.push_back(*it); From 988b500f33bd5d1e78cb9d9808c53d08e437182d Mon Sep 17 00:00:00 2001 From: yw4z Date: Mon, 4 May 2026 10:54:17 +0300 Subject: [PATCH 10/44] [Linux] Fix Black borders on checkbox and switch button (#13362) init --- src/slic3r/GUI/GUI_Utils.cpp | 58 +++++++++++++++++++++++++ src/slic3r/GUI/GUI_Utils.hpp | 4 ++ src/slic3r/GUI/Widgets/CheckBox.cpp | 27 +++++------- src/slic3r/GUI/Widgets/SwitchButton.cpp | 9 ++++ 4 files changed, 81 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/GUI_Utils.cpp b/src/slic3r/GUI/GUI_Utils.cpp index 3f60f4a409..a16d9916a6 100644 --- a/src/slic3r/GUI/GUI_Utils.cpp +++ b/src/slic3r/GUI/GUI_Utils.cpp @@ -13,6 +13,10 @@ #include #endif // _WIN32 +#ifdef __WXGTK__ +#include +#endif + #include #include #include @@ -496,6 +500,60 @@ void fit_in_display(wxTopLevelWindow& window, wxSize desired_size) window.SetSize(desired_size); } +#ifdef __WXGTK__ +void RemoveButtonBorder(wxWindow* win) +{ + GtkWidget* widget = win->GetHandle(); + if (!widget) return; + +#if GTK_CHECK_VERSION(3, 0, 0) + // GTK3+: use CSS provider + GtkCssProvider* provider = gtk_css_provider_new(); + + const char* css = + "button {" + " border: none;" + " outline: none;" + " box-shadow: none;" + " padding: 0px;" + " margin: 0px;" + " min-height: 0px;" + " min-width: 0px;" + " background: none;" + "}"; + +#if GTK_CHECK_VERSION(4, 0, 0) + // GTK4: no GError argument + gtk_css_provider_load_from_data(provider, css, -1); +#else + // GTK3: has GError argument + gtk_css_provider_load_from_data(provider, css, -1, nullptr); +#endif + + GtkStyleContext* ctx = gtk_widget_get_style_context(widget); + gtk_style_context_add_provider( + ctx, + GTK_STYLE_PROVIDER(provider), + GTK_STYLE_PROVIDER_PRIORITY_USER + ); + g_object_unref(provider); + +#else + // GTK2: use rc string, no CSS + gtk_rc_parse_string( + "style \"no-border\" {" + " GtkButton::inner-border = { 0, 0, 0, 0 }" + " GtkWidget::focus-line-width = 0" + " GtkWidget::focus-padding = 0" + " xthickness = 0" + " ythickness = 0" + "}" + "widget \"*.GtkBitmapToggleButton\" style \"no-border\"" + ); +#endif +} +#endif // __WXGTK__ + #ifdef __linux__ // Detect if the application is running inside a debugger. // https://stackoverflow.com/a/69842462/3289421 diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index 7e62d00c23..e50c9254a9 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -461,6 +461,10 @@ void dataview_remove_insets(wxDataViewCtrl* dv); void staticbox_remove_margin(wxStaticBox* sb); #endif +#ifdef __WXGTK3__ +void RemoveButtonBorder(wxWindow* win); +#endif + #if defined(__WXOSX__) || defined(__linux__) bool is_debugger_present(); #endif diff --git a/src/slic3r/GUI/Widgets/CheckBox.cpp b/src/slic3r/GUI/Widgets/CheckBox.cpp index 4e03f42187..54e98887e7 100644 --- a/src/slic3r/GUI/Widgets/CheckBox.cpp +++ b/src/slic3r/GUI/Widgets/CheckBox.cpp @@ -2,6 +2,10 @@ #include "../wxExtensions.hpp" +#ifdef __WXGTK3__ +#include "../GUI_Utils.hpp" +#endif + CheckBox::CheckBox(wxWindow *parent, int id) : wxBitmapToggleButton(parent, id, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE) , m_on(this, "check_on", 18) @@ -24,16 +28,12 @@ CheckBox::CheckBox(wxWindow *parent, int id) Bind(wxEVT_ENTER_WINDOW, &CheckBox::updateBitmap, this); Bind(wxEVT_LEAVE_WINDOW, &CheckBox::updateBitmap, this); #endif - update(); -#ifdef __WXGTK__ - wxSize bestSize = GetBestSize(); - bestSize.IncTo(m_on.GetBmpSize()); - SetSize(bestSize); - SetMinSize(bestSize); -#else - SetSize(m_on.GetBmpSize()); - SetMinSize(m_on.GetBmpSize()); + +#ifdef __WXGTK3__ + Slic3r::GUI::RemoveButtonBorder(this); #endif + + Rescale(); } void CheckBox::SetValue(bool value) @@ -61,16 +61,9 @@ void CheckBox::Rescale() m_on_focused.msw_rescale(); m_half_focused.msw_rescale(); m_off_focused.msw_rescale(); - update(); -#ifdef __WXGTK__ - wxSize bestSize = GetBestSize(); - bestSize.IncTo(m_on.GetBmpSize()); - SetSize(bestSize); - SetMinSize(bestSize); -#else SetSize(m_on.GetBmpSize()); SetMinSize(m_on.GetBmpSize()); -#endif + update(); } void CheckBox::update() diff --git a/src/slic3r/GUI/Widgets/SwitchButton.cpp b/src/slic3r/GUI/Widgets/SwitchButton.cpp index aedd868f8f..3b7664683c 100644 --- a/src/slic3r/GUI/Widgets/SwitchButton.cpp +++ b/src/slic3r/GUI/Widgets/SwitchButton.cpp @@ -11,6 +11,10 @@ #include "libslic3r/MacUtils.hpp" #endif +#ifdef __WXGTK3__ +#include "../GUI_Utils.hpp" +#endif + #include #include #include @@ -28,6 +32,11 @@ SwitchButton::SwitchButton(wxWindow* parent, wxWindowID id) SetBackgroundColour(StaticBox::GetParentBackgroundColor(parent)); Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { update(); e.Skip(); }); SetFont(Label::Body_12); + +#ifdef __WXGTK3__ + Slic3r::GUI::RemoveButtonBorder(this); +#endif + Rescale(); } From 84ccee7fe6568210fa0b11056af6a00af6cd2c8b Mon Sep 17 00:00:00 2001 From: Ian Bassi Date: Mon, 4 May 2026 04:57:50 -0300 Subject: [PATCH 11/44] Add indentation check to profile workflow (#13417) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce an 'indentation_check' job step to .github/workflows/check_profiles.yml that validates profile JSON files under resources/profiles use tab-only indentation (1 tab per level). The step runs an inline Python check, emits a log (indentation_check.log) with errors and a fix tip, and exits non‑zero on violations. Workflow conditionals for preparing the PR comment artifact, uploading the artifact, and failing the job were updated to include the new step so indentation failures are reported alongside other profile validation failures. --- .github/workflows/check_profiles.yml | 55 ++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check_profiles.yml b/.github/workflows/check_profiles.yml index 35592ec5a4..d24e27ac89 100644 --- a/.github/workflows/check_profiles.yml +++ b/.github/workflows/check_profiles.yml @@ -34,6 +34,46 @@ jobs: python3 ./scripts/orca_extra_profile_check.py 2>&1 | tee ${{ runner.temp }}/extra_json_check.log exit ${PIPESTATUS[0]} + - name: Check profile indentation + id: indentation_check + continue-on-error: true + run: | + set +e + python3 - <<'PY' 2>&1 | tee ${{ runner.temp }}/indentation_check.log + import re + from pathlib import Path + import sys + + profiles_root = Path("resources/profiles") + invalid_files = [] + + for file_path in sorted(profiles_root.rglob("*.json")): + try: + for line_number, line in enumerate(file_path.read_text(encoding="utf-8").splitlines(), start=1): + if not line.strip(): + continue + leading_ws = re.match(r"^[ \t]*", line).group(0) + if " " in leading_ws: + invalid_files.append((file_path, line_number)) + break + except Exception as exc: + print(f"[ERROR] Unable to read {file_path}: {exc}") + invalid_files.append((file_path, 0)) + + if invalid_files: + for path, line in invalid_files: + if line > 0: + print(f"[ERROR] Space indentation found in {path}:{line}") + else: + print(f"[ERROR] Could not validate indentation in {path}") + print("Use tab indentation in profile JSON files (1 tab per indentation level).") + print("Tip: run python3 ./scripts/orca_filament_lib.py --fix --force to normalize formatting.") + sys.exit(1) + + print("All profile JSON files use tab-only indentation.") + PY + exit ${PIPESTATUS[0]} + # download - name: Download working-directory: ${{ github.workspace }} @@ -62,7 +102,7 @@ jobs: exit ${PIPESTATUS[0]} - name: Prepare comment artifact - if: ${{ always() && github.event_name == 'pull_request' && (steps.extra_json_check.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }} + if: ${{ always() && github.event_name == 'pull_request' && (steps.extra_json_check.outcome == 'failure' || steps.indentation_check.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }} run: | mkdir -p ${{ runner.temp }}/profile-check-results @@ -79,6 +119,15 @@ jobs: echo "" fi + if [ "${{ steps.indentation_check.outcome }}" = "failure" ]; then + echo "### Indentation Check Failed" + echo "" + echo '```' + head -c 30000 ${{ runner.temp }}/indentation_check.log || echo "No output captured" + echo '```' + echo "" + fi + if [ "${{ steps.validate_system.outcome }}" = "failure" ]; then echo "### System Profile Validation Failed" echo "" @@ -104,7 +153,7 @@ jobs: echo "${{ github.event.pull_request.number }}" > ${{ runner.temp }}/profile-check-results/pr_number.txt - name: Upload comment artifact - if: ${{ always() && github.event_name == 'pull_request' && (steps.extra_json_check.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }} + if: ${{ always() && github.event_name == 'pull_request' && (steps.extra_json_check.outcome == 'failure' || steps.indentation_check.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }} uses: actions/upload-artifact@v7 with: name: profile-check-results @@ -112,7 +161,7 @@ jobs: retention-days: 1 - name: Fail if any check failed - if: ${{ always() && (steps.extra_json_check.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }} + if: ${{ always() && (steps.extra_json_check.outcome == 'failure' || steps.indentation_check.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }} run: | echo "One or more profile checks failed. See above for details." exit 1 From 8e9906f747d31fcfc92c967cb2fb0d570838b31b Mon Sep 17 00:00:00 2001 From: Dennis Klappe <35347995+dennisklappe@users.noreply.github.com> Date: Mon, 4 May 2026 11:41:07 +0200 Subject: [PATCH 12/44] Fix Ender-3 V3 KE nozzle switching (#13438) Fix Ender-3 V3 KE nozzle switching by adding printer_variant The four Creality Ender-3 V3 KE 0.X nozzle profiles were missing the printer_variant key, so OrcaSlicer could not map a UI nozzle selection to a specific profile and reverted every choice to 0.2mm. Add the matching printer_variant to each, following the CR-10 SE / K1C pattern. --- resources/profiles/Creality.json | 2 +- .../Creality/machine/Creality Ender-3 V3 KE 0.2 nozzle.json | 1 + .../Creality/machine/Creality Ender-3 V3 KE 0.4 nozzle.json | 1 + .../Creality/machine/Creality Ender-3 V3 KE 0.6 nozzle.json | 1 + .../Creality/machine/Creality Ender-3 V3 KE 0.8 nozzle.json | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/resources/profiles/Creality.json b/resources/profiles/Creality.json index 2616d6696c..b95688e15d 100644 --- a/resources/profiles/Creality.json +++ b/resources/profiles/Creality.json @@ -1,6 +1,6 @@ { "name": "Creality", - "version": "02.03.02.70", + "version": "02.03.02.71", "force_update": "0", "description": "Creality configurations", "machine_model_list": [ diff --git a/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.2 nozzle.json b/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.2 nozzle.json index 2d55ee3dcf..44754ead86 100644 --- a/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.2 nozzle.json +++ b/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.2 nozzle.json @@ -5,6 +5,7 @@ "from": "system", "setting_id": "GM001", "instantiation": "true", + "printer_variant": "0.2", "printer_settings_id": "Creality", "printer_model": "Creality Ender-3 V3 KE", "gcode_flavor": "klipper", diff --git a/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.4 nozzle.json b/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.4 nozzle.json index 5052015ad0..8d1269dc4a 100644 --- a/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.4 nozzle.json +++ b/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.4 nozzle.json @@ -5,6 +5,7 @@ "from": "system", "setting_id": "GM001", "instantiation": "true", + "printer_variant": "0.4", "printer_settings_id": "Creality", "printer_model": "Creality Ender-3 V3 KE", "gcode_flavor": "klipper", diff --git a/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.6 nozzle.json b/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.6 nozzle.json index 5a26353c84..36e61d6229 100644 --- a/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.6 nozzle.json +++ b/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.6 nozzle.json @@ -5,6 +5,7 @@ "from": "system", "setting_id": "GM001", "instantiation": "true", + "printer_variant": "0.6", "printer_settings_id": "Creality", "printer_model": "Creality Ender-3 V3 KE", "gcode_flavor": "klipper", diff --git a/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.8 nozzle.json b/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.8 nozzle.json index 4f1ca62247..863d20c3fb 100644 --- a/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.8 nozzle.json +++ b/resources/profiles/Creality/machine/Creality Ender-3 V3 KE 0.8 nozzle.json @@ -5,6 +5,7 @@ "from": "system", "setting_id": "GM001", "instantiation": "true", + "printer_variant": "0.8", "printer_settings_id": "Creality", "printer_model": "Creality Ender-3 V3 KE", "gcode_flavor": "klipper", From a943252b6aceaaaae71951c26c8c424c93c2f6b9 Mon Sep 17 00:00:00 2001 From: Ian Bassi Date: Mon, 4 May 2026 11:19:21 -0300 Subject: [PATCH 13/44] Wiki redirections (#13474) --- src/libslic3r/PrintConfig.cpp | 4 +++- src/slic3r/GUI/Tab.cpp | 22 +++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 926439535c..b812515d89 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2191,6 +2191,7 @@ void PrintConfigDef::init_fff_params() "This setting changes all extrusion flow of this filament in G-code proportionally. " "The recommended value range is between 0.95 and 1.05. " "You may be able to tune this value to get a nice flat surface if there is slight overflow or underflow."); + def->min = 0; def->max = 2; def->mode = comAdvanced; def->nullable = true; @@ -5239,7 +5240,8 @@ void PrintConfigDef::init_fff_params() def->label = L("Scarf joint flow ratio"); def->category = L("Quality"); def->tooltip = L("This factor affects the amount of material for scarf joints."); - def->mode = comDevelop; + def->mode = comExpert; + def->min = 0; def->max = 2; def->set_default_value(new ConfigOptionFloat(1)); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 2b7ef7ce0f..e757fea5a6 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2303,7 +2303,7 @@ void TabPrint::build() optgroup->append_single_option_line("xy_hole_compensation", "quality_settings_precision#x-y-compensation"); optgroup->append_single_option_line("xy_contour_compensation", "quality_settings_precision#x-y-compensation"); optgroup->append_single_option_line("elefant_foot_compensation", "quality_settings_precision#elephant-foot-compensation"); - optgroup->append_single_option_line("elefant_foot_layers_density", "quality_settings_precision#elephant-foot-compensation"); + optgroup->append_single_option_line("elefant_foot_layers_density", "quality_settings_precision#elephant-foot-compensation-density"); optgroup->append_single_option_line("elefant_foot_compensation_layers", "quality_settings_precision#elephant-foot-compensation"); optgroup->append_single_option_line("precise_outer_wall", "quality_settings_precision#precise-wall"); optgroup->append_single_option_line("precise_z_height", "quality_settings_precision#precise-z-height"); @@ -2330,16 +2330,16 @@ void TabPrint::build() optgroup = page->new_optgroup(L("Wall generator"), L"param_wall_generator"); optgroup->append_single_option_line("wall_generator", "quality_settings_wall_generator"); - optgroup->append_single_option_line("wall_transition_angle", "quality_settings_wall_generator#arachne"); - optgroup->append_single_option_line("wall_transition_filter_deviation", "quality_settings_wall_generator#arachne"); - optgroup->append_single_option_line("wall_transition_length", "quality_settings_wall_generator#arachne"); - optgroup->append_single_option_line("wall_distribution_count", "quality_settings_wall_generator#arachne"); - optgroup->append_single_option_line("initial_layer_min_bead_width", "quality_settings_wall_generator#arachne"); - optgroup->append_single_option_line("min_bead_width", "quality_settings_wall_generator#arachne"); - optgroup->append_single_option_line("min_feature_size", "quality_settings_wall_generator#arachne"); - optgroup->append_single_option_line("min_length_factor", "quality_settings_wall_generator#arachne"); - optgroup->append_single_option_line("wall_maximum_resolution", "quality_settings_wall_generator#arachne"); - optgroup->append_single_option_line("wall_maximum_deviation", "quality_settings_wall_generator#arachne"); + optgroup->append_single_option_line("wall_transition_angle", "quality_settings_wall_generator#wall-transitioning-threshhold-angle"); + optgroup->append_single_option_line("wall_transition_filter_deviation", "quality_settings_wall_generator#wall-transitioning-filter-margin"); + optgroup->append_single_option_line("wall_transition_length", "quality_settings_wall_generator#wall-transitioning-length"); + optgroup->append_single_option_line("wall_distribution_count", "quality_settings_wall_generator#wall-distribution-count"); + optgroup->append_single_option_line("initial_layer_min_bead_width", "quality_settings_wall_generator#first-layer-minimum-wall-width"); + optgroup->append_single_option_line("min_bead_width", "quality_settings_wall_generator#minimum-wall-width"); + optgroup->append_single_option_line("min_feature_size", "quality_settings_wall_generator#minimum-feature-size"); + optgroup->append_single_option_line("min_length_factor", "quality_settings_wall_generator#minimum-wall-length"); + optgroup->append_single_option_line("wall_maximum_resolution", "quality_settings_wall_generator#maximum-wall-resolution"); + optgroup->append_single_option_line("wall_maximum_deviation", "quality_settings_wall_generator#maximum-wall-deviation"); optgroup = page->new_optgroup(L("Walls and surfaces"), L"param_wall_surface"); optgroup->append_single_option_line("wall_sequence", "quality_settings_wall_and_surfaces#walls-printing-order"); From 62ccd979c6f442a974d512fa17e15beaad01a70a Mon Sep 17 00:00:00 2001 From: Ian Bassi Date: Mon, 4 May 2026 12:37:54 -0300 Subject: [PATCH 14/44] EFC Density description (#13476) --- src/libslic3r/PrintConfig.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index b812515d89..f2aad27895 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -696,11 +696,11 @@ void PrintConfigDef::init_common_params() def->set_default_value(new ConfigOptionInt(1)); def = this->add("elefant_foot_layers_density", coPercent); - def->label = L("Elefant foot layers density"); + def->label = L("Elephant foot layers density"); def->category = L("Quality"); - def->tooltip = L("Density of internal solid infill for elefant foot layers compensation. " - "The initial value for the second layer is set. " - "Subsequent layers become linearly denser by the height specified in elefant_foot_compensation_layers. "); + def->tooltip = L("Density of internal solid infill for Elephant foot layers compensation.\n" + "The initial value for the second layer is set.\n" + "Subsequent layers become linearly denser by the height specified in elefant_foot_compensation_layers."); def->sidetext = "%"; def->min = 50; def->max = 100; From 7ecf2225a49213d3b91b96848c604abfbe5da5ca Mon Sep 17 00:00:00 2001 From: Jakub Hencl Date: Tue, 5 May 2026 00:12:34 +0200 Subject: [PATCH 15/44] Update Czech translations in OrcaSlicer_cs.po (#13465) --- localization/i18n/cs/OrcaSlicer_cs.po | 80 +++++++++++++-------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/localization/i18n/cs/OrcaSlicer_cs.po b/localization/i18n/cs/OrcaSlicer_cs.po index 2ce84a0cde..719189a6fd 100644 --- a/localization/i18n/cs/OrcaSlicer_cs.po +++ b/localization/i18n/cs/OrcaSlicer_cs.po @@ -11072,7 +11072,7 @@ msgid "Gizmo assemble" msgstr "Gizmo sestavit" msgid "Gizmo brim ears" -msgstr "Gizmo přídavky okraje (uši)" +msgstr "Gizmo ouška lemu" msgid "Zoom in" msgstr "Přiblížit" @@ -12583,13 +12583,13 @@ msgstr "" "průtokovým poměrem filamentu a případně průtokovým poměrem objektu." msgid "Set other flow ratios" -msgstr "Set other flow ratios" +msgstr "Nastavit další poměry průtoku" msgid "Change flow ratios for other extrusion path types." -msgstr "Change flow ratios for other extrusion path types." +msgstr "Změnit poměry průtoku pro další typy extruzních drah." msgid "First layer flow ratio" -msgstr "First layer flow ratio" +msgstr "Poměr průtoku první vrstvy" msgid "" "This factor affects the amount of material on the first layer for the " @@ -12598,14 +12598,14 @@ msgid "" "For the first layer, the actual flow ratio for each path role (does not " "affect brims and skirts) will be multiplied by this value." msgstr "" -"This factor affects the amount of material on the first layer for the " -"extrusion path roles listed in this section.\n" +"Tento faktor ovlivňuje množství materiálu na první vrstvě pro role extruzních " +"drah uvedené v této sekci.\n" "\n" -"For the first layer, the actual flow ratio for each path role (does not " -"affect brims and skirts) will be multiplied by this value." +"Pro první vrstvu bude skutečný poměr průtoku pro každou roli dráhy (neovlivňuje " +"lem a sukni) vynásoben touto hodnotou." msgid "Outer wall flow ratio" -msgstr "Outer wall flow ratio" +msgstr "Poměr průtoku vnější stěny" msgid "" "This factor affects the amount of material for outer walls.\n" @@ -12613,13 +12613,13 @@ msgid "" "The actual outer wall flow used is calculated by multiplying this value by " "the filament flow ratio, and if set, the object's flow ratio." msgstr "" -"This factor affects the amount of material for outer walls.\n" +"Tento faktor ovlivňuje množství materiálu pro vnější stěny.\n" "\n" -"The actual outer wall flow used is calculated by multiplying this value by " -"the filament flow ratio, and if set, the object's flow ratio." +"Skutečný průtok pro vnější stěny se vypočítá vynásobením této hodnoty " +"poměrem průtoku filamentu a případně také poměrem průtoku objektu." msgid "Inner wall flow ratio" -msgstr "Inner wall flow ratio" +msgstr "Poměr průtoku vnitřní stěny" msgid "" "This factor affects the amount of material for inner walls.\n" @@ -12627,13 +12627,13 @@ msgid "" "The actual inner wall flow used is calculated by multiplying this value by " "the filament flow ratio, and if set, the object's flow ratio." msgstr "" -"This factor affects the amount of material for inner walls.\n" +"Tento faktor ovlivňuje množství materiálu pro vnitřní stěny.\n" "\n" -"The actual inner wall flow used is calculated by multiplying this value by " -"the filament flow ratio, and if set, the object's flow ratio." +"Skutečný průtok pro vnitřní stěny se vypočítá vynásobením této hodnoty " +"poměrem průtoku filamentu a případně také poměrem průtoku objektu." msgid "Overhang flow ratio" -msgstr "Overhang flow ratio" +msgstr "Poměr průtoku převisů" msgid "" "This factor affects the amount of material for overhangs.\n" @@ -12641,13 +12641,13 @@ msgid "" "The actual overhang flow used is calculated by multiplying this value by the " "filament flow ratio, and if set, the object's flow ratio." msgstr "" -"This factor affects the amount of material for overhangs.\n" +"Tento faktor ovlivňuje množství materiálu pro převisy.\n" "\n" -"The actual overhang flow used is calculated by multiplying this value by the " -"filament flow ratio, and if set, the object's flow ratio." +"Skutečný průtok pro převisy se vypočítá vynásobením této hodnoty " +"poměrem průtoku filamentu a případně také poměrem průtoku objektu." msgid "Sparse infill flow ratio" -msgstr "Sparse infill flow ratio" +msgstr "Poměr průtoku řídké výplně" msgid "" "This factor affects the amount of material for sparse infill.\n" @@ -12655,13 +12655,13 @@ msgid "" "The actual sparse infill flow used is calculated by multiplying this value " "by the filament flow ratio, and if set, the object's flow ratio." msgstr "" -"This factor affects the amount of material for sparse infill.\n" +"Tento faktor ovlivňuje množství materiálu pro řídkou výplň.\n" "\n" -"The actual sparse infill flow used is calculated by multiplying this value " -"by the filament flow ratio, and if set, the object's flow ratio." +"Skutečný průtok pro řídkou výplň se vypočítá vynásobením této hodnoty " +"poměrem průtoku filamentu a případně také poměrem průtoku objektu." msgid "Internal solid infill flow ratio" -msgstr "Internal solid infill flow ratio" +msgstr "Poměr průtoku vnitřní plné výplně" msgid "" "This factor affects the amount of material for internal solid infill.\n" @@ -12669,13 +12669,13 @@ msgid "" "The actual internal solid infill flow used is calculated by multiplying this " "value by the filament flow ratio, and if set, the object's flow ratio." msgstr "" -"This factor affects the amount of material for internal solid infill.\n" +"Tento faktor ovlivňuje množství materiálu pro vnitřní plnou výplň.\n" "\n" -"The actual internal solid infill flow used is calculated by multiplying this " -"value by the filament flow ratio, and if set, the object's flow ratio." +"Skutečný průtok pro vnitřní plnou výplň se vypočítá vynásobením této hodnoty " +"poměrem průtoku filamentu a případně také poměrem průtoku objektu." msgid "Gap fill flow ratio" -msgstr "Gap fill flow ratio" +msgstr "Poměr průtoku vyplnění mezer" msgid "" "This factor affects the amount of material for filling the gaps.\n" @@ -12683,13 +12683,13 @@ msgid "" "The actual gap filling flow used is calculated by multiplying this value by " "the filament flow ratio, and if set, the object's flow ratio." msgstr "" -"This factor affects the amount of material for filling the gaps.\n" +"Tento faktor ovlivňuje množství materiálu pro vyplnění mezer.\n" "\n" -"The actual gap filling flow used is calculated by multiplying this value by " -"the filament flow ratio, and if set, the object's flow ratio." +"Skutečný průtok pro vyplnění mezer se vypočítá vynásobením této hodnoty " +"poměrem průtoku filamentu a případně také poměrem průtoku objektu." msgid "Support flow ratio" -msgstr "Support flow ratio" +msgstr "Poměr průtoku podpěr" msgid "" "This factor affects the amount of material for support.\n" @@ -12697,13 +12697,13 @@ msgid "" "The actual support flow used is calculated by multiplying this value by the " "filament flow ratio, and if set, the object's flow ratio." msgstr "" -"This factor affects the amount of material for support.\n" +"Tento faktor ovlivňuje množství materiálu pro podpěry.\n" "\n" -"The actual support flow used is calculated by multiplying this value by the " -"filament flow ratio, and if set, the object's flow ratio." +"Skutečný průtok pro podpěry se vypočítá vynásobením této hodnoty " +"poměrem průtoku filamentu a případně také poměrem průtoku objektu." msgid "Support interface flow ratio" -msgstr "Support interface flow ratio" +msgstr "Poměr průtoku rozhraní podpěr" msgid "" "This factor affects the amount of material for the support interface.\n" @@ -12711,10 +12711,10 @@ msgid "" "The actual support interface flow used is calculated by multiplying this " "value by the filament flow ratio, and if set, the object's flow ratio." msgstr "" -"This factor affects the amount of material for the support interface.\n" +"Tento faktor ovlivňuje množství materiálu pro rozhraní podpěr.\n" "\n" -"The actual support interface flow used is calculated by multiplying this " -"value by the filament flow ratio, and if set, the object's flow ratio." +"Skutečný průtok pro rozhraní podpěr se vypočítá vynásobením této hodnoty " +"poměrem průtoku filamentu a případně také poměrem průtoku objektu." msgid "Precise wall" msgstr "Přesná stěna" From aa35d3ae179ad467b592046de2e564e19fcdef8d Mon Sep 17 00:00:00 2001 From: SoftFever Date: Tue, 5 May 2026 14:58:26 +0800 Subject: [PATCH 16/44] preserve a single trailing newline when reformatting JSON files --- scripts/orca_filament_lib.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/orca_filament_lib.py b/scripts/orca_filament_lib.py index 92f6d1dc55..65f037e3f3 100644 --- a/scripts/orca_filament_lib.py +++ b/scripts/orca_filament_lib.py @@ -132,6 +132,7 @@ def update_profile_library(vendor="",profile_type="filament"): library[profile_section] = sorted_profiles f.seek(0) json.dump(library, f, indent="\t", ensure_ascii=False) + f.write('\n') f.truncate() print(f"Profile library for {vendor} updated successfully!") @@ -230,6 +231,7 @@ def clean_up_profile(vendor="", profile_type="", force=False): f.seek(0) ordered_profile = create_ordered_profile(_profile, ['type', 'name', 'renamed_from', 'inherits', 'from', 'setting_id', 'filament_id', 'instantiation']) json.dump(ordered_profile, f, indent="\t", ensure_ascii=False) + f.write('\n') f.truncate() print(f"Updated profile: {full_path}") except Exception as e: @@ -274,6 +276,7 @@ def rename_filament_system(vendor="OrcaFilamentLibrary"): if modified: with open(full_path, 'w', encoding='utf-8') as f: json.dump(data, f, indent="\t", ensure_ascii=False) + f.write('\n') print(f"Updated {full_path}") except Exception as e: From b3482265e0dde1d908739589f9376bad688cfaa1 Mon Sep 17 00:00:00 2001 From: yw4z Date: Tue, 5 May 2026 15:34:10 +0300 Subject: [PATCH 17/44] Simplify drawing splash screen using wxPaintDC and Fix scaling & blank rendering issues (#12586) * Update GUI_App.cpp * Update GUI_App.cpp * make splash screen parentless --- src/slic3r/GUI/GUI_App.cpp | 191 +++++++++---------------------------- 1 file changed, 44 insertions(+), 147 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index a3cdb0f069..24271d51fa 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -276,8 +276,8 @@ bool is_associate_files(std::wstring extend) class SplashScreen : public wxSplashScreen { public: - SplashScreen(const wxBitmap& bitmap, long splashStyle, int milliseconds, wxPoint pos = wxDefaultPosition) - : wxSplashScreen(bitmap, splashStyle, milliseconds, static_cast(wxGetApp().mainframe), wxID_ANY, wxDefaultPosition, wxDefaultSize, + SplashScreen(wxPoint pos = wxDefaultPosition) + : wxSplashScreen(wxBitmap(FromDIP(wxSize(480,480),nullptr)), wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_TIMEOUT, 1500, nullptr, wxID_ANY, wxDefaultPosition, wxDefaultSize, #ifdef __APPLE__ wxBORDER_NONE | wxFRAME_NO_TASKBAR | wxSTAY_ON_TOP #else @@ -285,51 +285,53 @@ public: #endif // !__APPLE__ ) { - int init_dpi = get_dpi_for_window(this); this->SetPosition(pos); this->CenterOnScreen(); - int new_dpi = get_dpi_for_window(this); - m_scale = (float)(new_dpi) / (float)(init_dpi); + scale_font(m_font_version, 1.65f); // only scale this one since it hasnt a preloaded font like Label::Body_24; - m_main_bitmap = bitmap; + m_bg_color = StateColor::darkModeColorFor(wxColour("#FFFFFF")); + m_fg_color = StateColor::darkModeColorFor(wxColour("#6B6A6A")); + bool dark_mode = m_fg_color != wxColour("#6B6A6A"); + wxSize sz = m_window->GetClientSize(); + BitmapCache bmp_cache; + m_logo_bmp = *bmp_cache.load_svg(dark_mode ? "splash_logo_dark" : "splash_logo", sz.GetWidth(), sz.GetHeight()); - scale_bitmap(m_main_bitmap, m_scale); + m_window->Bind(wxEVT_PAINT, &SplashScreen::OnPaint, this); + m_window->Refresh(); + m_window->Update(); + } - // init constant texts and scale fonts - m_constant_text.init(Label::Body_16); + void OnPaint(wxPaintEvent& evt) + { + wxPaintDC dc(m_window); + wxSize c_sz = m_window->GetClientSize(); - // ORCA scale all fonts with monitor scale - scale_font(m_constant_text.version_font, m_scale * 2); - scale_font(m_constant_text.based_on_font, m_scale * 1.5f); - scale_font(m_constant_text.credits_font, m_scale * 2); + dc.SetBackground(wxBrush(m_bg_color)); + dc.Clear(); + if (m_logo_bmp.IsOk()) + dc.DrawBitmap(m_logo_bmp, 0, 0, true); - // this font will be used for the action string - m_action_font = m_constant_text.credits_font; + wxRect rc = wxRect(0, 0, c_sz.GetWidth(), 0); + dc.SetTextForeground(m_fg_color); - // draw logo and constant info text - Decorate(m_main_bitmap); - wxGetApp().UpdateFrameDarkUI(this); + dc.SetFont(m_font_version); + rc.y = c_sz.GetHeight() * 0.72; + rc.height = dc.GetTextExtent(m_text_version).GetHeight(); + dc.DrawLabel(m_text_version, rc, wxALIGN_CENTER); + + dc.SetFont(m_font_action); + rc.y = c_sz.GetHeight() * 0.88; + rc.height = dc.GetTextExtent(m_text_action).GetHeight(); + dc.DrawLabel(m_text_action, rc, wxALIGN_CENTER); } void SetText(const wxString& text) { - set_bitmap(m_main_bitmap); if (!text.empty()) { - wxBitmap bitmap(m_main_bitmap); - - wxMemoryDC memDC; - memDC.SelectObject(bitmap); - memDC.SetFont(m_action_font); - memDC.SetTextForeground(StateColor::darkModeColorFor(wxColour(144, 144, 144))); - int width = bitmap.GetWidth(); - int text_height = memDC.GetTextExtent(text).GetHeight(); - int text_width = memDC.GetTextExtent(text).GetWidth(); - wxRect text_rect(wxPoint(0, m_action_line_y_position), wxPoint(width, m_action_line_y_position + text_height)); - memDC.DrawLabel(text, text_rect, wxALIGN_CENTER); - - memDC.SelectObject(wxNullBitmap); - set_bitmap(bitmap); + m_text_action = text; + m_window->Refresh(); + m_window->Update(); #ifdef __WXOSX__ // without this code splash screen wouldn't be updated under OSX wxYield(); @@ -337,77 +339,6 @@ public: } } - void Decorate(wxBitmap& bmp) - { - if (!bmp.IsOk()) - return; - - bool is_dark = wxGetApp().app_config->get("dark_color_mode") == "1"; - - // use a memory DC to draw directly onto the bitmap - wxMemoryDC memDc(bmp); - - int width = bmp.GetWidth(); - int height = bmp.GetHeight(); - - // Logo - BitmapCache bmp_cache; - wxBitmap logo_bmp = *bmp_cache.load_svg(is_dark ? "splash_logo_dark" : "splash_logo", width, height); // use with full width & height - memDc.DrawBitmap(logo_bmp, 0, 0, true); - - // Version - memDc.SetFont(m_constant_text.version_font); - memDc.SetTextForeground(StateColor::darkModeColorFor(wxColor(134, 134, 134))); - wxSize version_ext = memDc.GetTextExtent(m_constant_text.version); - wxRect version_rect( - wxPoint(0, int(height * 0.70)), - wxPoint(width, int(height * 0.70) + version_ext.GetHeight()) - ); - memDc.DrawLabel(m_constant_text.version, version_rect, wxALIGN_CENTER); - - // Dynamic Text - m_action_line_y_position = int(height * 0.83); - } - - static wxBitmap MakeBitmap() - { - int width = FromDIP(480, nullptr); - int height = FromDIP(480, nullptr); - - wxImage image(width, height); - wxBitmap new_bmp(image); - - wxMemoryDC memDC; - memDC.SelectObject(new_bmp); - memDC.SetBrush(StateColor::darkModeColorFor(*wxWHITE)); - memDC.DrawRectangle(-1, -1, width + 2, height + 2); - memDC.DrawBitmap(new_bmp, 0, 0, true); - return new_bmp; - } - - void set_bitmap(wxBitmap& bmp) - { - m_window->SetBitmap(bmp); - m_window->Refresh(); - m_window->Update(); - } - - void scale_bitmap(wxBitmap& bmp, float scale) - { - if (scale == 1.0) - return; - - wxImage image = bmp.ConvertToImage(); - if (!image.IsOk() || image.GetWidth() == 0 || image.GetHeight() == 0) - return; - - int width = int(scale * image.GetWidth()); - int height = int(scale * image.GetHeight()); - image.Rescale(width, height, wxIMAGE_QUALITY_BILINEAR); - - bmp = wxBitmap(std::move(image)); - } - void scale_font(wxFont& font, float scale) { #ifdef __WXMSW__ @@ -425,47 +356,16 @@ public: #endif //__WXMSW__ } - private: - wxStaticText* m_staticText_slicer_name; - wxStaticText* m_staticText_slicer_version; - wxStaticBitmap* m_bitmap; - wxStaticText* m_staticText_loading; + wxBitmap m_logo_bmp; + wxColour m_fg_color; + wxColour m_bg_color; - wxBitmap m_main_bitmap; - wxFont m_action_font; - int m_action_line_y_position; - float m_scale {1.0}; + wxString m_text_version = GUI_App::format_display_version(); + wxString m_text_action = _L("Loading configuration") + dots; - struct ConstantText - { - wxString title; - wxString version; - wxString credits; - - wxFont title_font; - wxFont version_font; - wxFont credits_font; - wxFont based_on_font; - - void init(wxFont init_font) - { - // title - //title = wxGetApp().is_editor() ? SLIC3R_APP_FULL_NAME : GCODEVIEWER_APP_NAME; - - // dynamically get the version to display - version = GUI_App::format_display_version(); - - // credits infornation - credits = ""; - - //title_font = Label::Head_16; - version_font = Label::Body_13; - based_on_font = Label::Body_8; - credits_font = Label::Body_8; - } - } - m_constant_text; + wxFont m_font_version = Label::Body_16; + wxFont m_font_action = Label::Body_16; }; #ifdef __linux__ @@ -2844,9 +2744,6 @@ bool GUI_App::on_init_inner() SplashScreen * scrn = nullptr; if (app_config->get("show_splash_screen") == "true") { - // make a bitmap with dark grey banner on the left side - //BBS make BBL splash screen bitmap - wxBitmap bmp = SplashScreen::MakeBitmap(); // Detect position (display) to show the splash screen // Now this position is equal to the mainframe position wxPoint splashscreen_pos = wxDefaultPosition; @@ -2858,9 +2755,9 @@ bool GUI_App::on_init_inner() BOOST_LOG_TRIVIAL(info) << "begin to show the splash screen..."; //BBS use BBL splashScreen - scrn = new SplashScreen(bmp, wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_TIMEOUT, 1500, splashscreen_pos); + scrn = new SplashScreen(splashscreen_pos); wxYield(); - scrn->SetText(_L("Loading configuration")+ dots); + //scrn->SetText(_L("Loading configuration")+ dots); } BOOST_LOG_TRIVIAL(info) << "loading systen presets..."; From 1433521f98ff35fd2817fa72a85a5fe8254cddf5 Mon Sep 17 00:00:00 2001 From: yw4z Date: Tue, 5 May 2026 15:35:31 +0300 Subject: [PATCH 18/44] Improvements for Color paint widget (#13421) * init * fix build error * Update GLGizmoMmuSegmentation.cpp * Update GLGizmoMmuSegmentation.cpp * Update GLGizmoMmuSegmentation.cpp * fix popup positioning and add tooltip for remap info --- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 384 +++++++----------- .../GUI/Gizmos/GLGizmoMmuSegmentation.hpp | 6 +- 2 files changed, 144 insertions(+), 246 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index e3fbfe0726..de27cd6bc7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -115,9 +115,9 @@ bool GLGizmoMmuSegmentation::on_init() m_desc["smart_fill_angle"] = _L("Smart fill angle"); m_desc["height_range"] = _L("Height range"); m_desc["toggle_wireframe"] = _L("Toggle Wireframe"); - m_desc["perform_remap"] = _L("Remap filaments"); + m_desc["perform_remap"] = _u8L("Remap filaments"); m_desc["remap"] = _L("Remap"); - m_desc["cancel_remap"] = _L("Cancel"); + m_desc["remap_reset"] = _L("Reset"); std::pair paint_shortcut = {_L("Left mouse button"), m_desc["paint"]}; std::pair erase_shortcut = {shift + _L("Left mouse button"), m_desc["erase"]}; @@ -304,10 +304,56 @@ void GLGizmoMmuSegmentation::render_tooltip_button(float x, float y) GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, get_shortcuts(), x, y); } +// ORCA +bool GLGizmoMmuSegmentation::draw_color_button(int idx, std::string id_str, const ColorRGBA& color, ColorRGBA& map_color, bool active, float scale) +{ + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + std::string label_id = std::to_string(idx) + id_str + std::to_string(idx); + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImVec2 size = ImVec2(27.f * scale, 27.f * scale); + ImVec4 color_vec = ImGuiWrapper::to_ImVec4(color); + ImU32 br_color = ImGui::ColorConvertFloat4ToU32(active ? ImGuiWrapper::COL_ORCA : m_is_dark_mode ? ImVec4(.35f, .35f, .35f, 1) : ImVec4(.85f, .85f, .85f, 1)); + bool dark_tone = (0.299f * color.r() + 0.587f * color.g() + 0.114f * color.b()) < 0.51f; // matching values used by wxWidgets with clr.GetLuminance() < 0.51 + + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding , 7.f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding , ImVec2(0, 0)); + ImGui::PushStyleColor(ImGuiCol_Text , dark_tone ? ImVec4(1,1,1,1) : ImVec4(0,0,0,1)); + ImGui::PushStyleColor(ImGuiCol_Button , color_vec); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, color_vec); + ImGui::PushStyleColor(ImGuiCol_ButtonActive , color_vec); + bool clicked = ImGui::Button(label_id.c_str(), size); + ImGui::PopStyleVar(3); + ImGui::PopStyleColor(4); + + auto drawBorder = [&](float d, float r, float t, ImU32 col) { + draw_list->AddRect({pos.x + d * scale, pos.y + d * scale}, {pos.x + size.x - d * scale , pos.y + size.y - d * scale}, col, r * scale, 0, t * scale); + }; + drawBorder(1.5f, 3.f, 4.f, ImGui::ColorConvertFloat4ToU32(ImGui::GetStyleColorVec4(ImGuiCol_WindowBg))); + if(active) + drawBorder(.5f, 4.f , 2.f, br_color); + else + drawBorder(3.f, 2.5f, 1.f, br_color); + + if (color != map_color){ // show mapped color as bubble if mapped + ImVec2 center = {pos.x + size.x - 3.f * scale, pos.y + 3.f * scale}; + draw_list->AddCircleFilled(center, 6.f * scale, br_color, 16); // outer border for better visibility + draw_list->AddCircleFilled(center, 5.f * scale, ImGuiWrapper::to_ImU32(map_color), 16); + } + + return clicked; +}; + void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bottom_limit) { if (!m_c->selection_info()->model_object()) return; + float scale = m_parent.get_scale(); + #ifdef WIN32 + int dpi = get_dpi_for_window(wxGetApp().GetTopWindow()); + scale *= (float) dpi / (float) DPI_DEFAULT; + #endif // WIN32 + const float approx_height = m_imgui->scaled(22.0f); y = std::min(y, bottom_limit - approx_height); GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always); @@ -363,69 +409,67 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott const float drag_left_width = ImGui::GetStyle().WindowPadding.x + sliders_width - space_size; const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; - ImDrawList * draw_list = ImGui::GetWindowDrawList(); - ImVec2 pos = ImGui::GetCursorScreenPos(); - static float color_button_high = 25.0; - draw_list->AddRectFilled({pos.x - 10.0f, pos.y - 7.0f}, {pos.x + window_width + ImGui::GetFrameHeight(), pos.y + color_button_high}, ImGui::GetColorU32(ImGuiCol_FrameBgActive, 1.0f), 5.0f); - - float color_button = ImGui::GetCursorPos().y; m_imgui->text(m_desc.at("filaments")); - float start_pos_x = ImGui::GetCursorPos().x; - const ImVec2 max_label_size = ImGui::CalcTextSize("99", NULL, true); - const float item_spacing = m_imgui->scaled(0.8f); size_t n_extruder_colors = std::min((size_t)EnforcerBlockerType::ExtruderMax, m_extruders_colors.size()); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(7.f * scale, 7.f * scale)); + ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0); // removes extra space on tree node indentation for (int extruder_idx = 0; extruder_idx < n_extruder_colors; extruder_idx++) { - const ColorRGBA &extruder_color = m_extruders_colors[extruder_idx]; - ImVec4 color_vec = ImGuiWrapper::to_ImVec4(extruder_color); - std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx); - std::string item_text = std::to_string(extruder_idx + 1); - const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); - const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f),0.f); + if (extruder_idx % max_filament_items_per_line != 0) + ImGui::SameLine(); - float button_offset = start_pos_x; - if (extruder_idx % max_filament_items_per_line != 0) { - button_offset += filament_item_width * (extruder_idx % max_filament_items_per_line); - ImGui::SameLine(button_offset); + if (draw_color_button( + extruder_idx + 1, // idx + "###extruder_color_", // button_id + m_extruders_colors[extruder_idx], // color + m_extruders_colors[extruder_idx], // mapped_color (not used in here) + m_selected_extruder_idx == extruder_idx, // is_active + scale + )){ + m_selected_extruder_idx = extruder_idx; } - // draw filament background - ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; - if (m_selected_extruder_idx != extruder_idx) flags |= ImGuiColorEditFlags_NoBorder; - #ifdef __APPLE__ - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); // ORCA use orca color for selected filament border - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0); - bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); - #else - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); // ORCA use orca color for selected filament border - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0); - bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); - #endif - color_button_high = ImGui::GetCursorPos().y - color_button - 2.0; - if (color_picked) { m_selected_extruder_idx = extruder_idx; } - if (extruder_idx < 16 && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width); - - // draw filament id - float gray = 0.299 * extruder_color.r() + 0.587 * extruder_color.g() + 0.114 * extruder_color.b(); - ImGui::SameLine(button_offset + (button_size.x - label_size.x) / 2.f); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {10.0,15.0}); - if (gray * 255.f < 80.f) - ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), "%s", item_text.c_str()); - else - ImGui::TextColored(ImVec4(0.0f, 0.0f, 0.0f, 1.0f), "%s", item_text.c_str()); - - ImGui::PopStyleVar(); } - //ImGui::NewLine(); + // ORCA: Remap filaments section (Border only, Title in border). + // Styled as a panel for visual grouping. + if (ImGui::TreeNodeEx(m_desc.at("perform_remap").c_str(), ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_FramePadding)){ + render_filament_remap_ui(window_width, max_tooltip_width, scale); + + bool has_mapping = false; + for (size_t i = 0; i < m_extruder_remap.size(); ++i){ + if(m_extruder_remap[i] != i){ + has_mapping = true; + break; + } + } + + ImGui::Dummy(ImVec2(0,0)); + + // ORCA: Add Remap and Cancel buttons (outside the panel) + m_imgui->disabled_begin(!has_mapping); // disable when no mapping + if (m_imgui->button(m_desc.at("remap"))) { + this->remap_filament_assignments(); + // Reset mapping to identity after apply + for (size_t i = 0; i < m_extruder_remap.size(); ++i) m_extruder_remap[i] = i; + } + m_imgui->disabled_end(/*m_is_unknown_font*/); + + if (has_mapping){ // show only when it has mapping + ImGui::SameLine(); + if (m_imgui->button(m_desc.at("remap_reset"))) { + // Reset mapping to identity + for (size_t i = 0; i < m_extruder_remap.size(); ++i) m_extruder_remap[i] = i; + } + } + + //ImGui::Dummy(ImVec2(0.0f, 3.f * scale)); + ImGui::TreePop(); + } + ImGui::PopStyleVar(2); // IndentSpacing ItemSpacing + ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.1)); m_imgui->text(m_desc.at("tool_type")); @@ -598,60 +642,6 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott m_c->object_clipper()->set_position_by_ratio(clp_dist, true); } - ImGui::Separator(); - // ORCA: Remap filaments section (Border only, Title in border). - // Styled as a panel for visual grouping. - if (m_imgui->button(m_desc.at("perform_remap"))) { - m_show_remap_panel = !m_show_remap_panel; - } - - if (m_show_remap_panel) - { - ImGui::Spacing(); - - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - std::string title = into_u8(m_desc.at("perform_remap")); - float available_width = ImGui::GetContentRegionAvail().x; - - // ORCA: Draw Background filled (consistent with Filaments section) - // Use static to remember height from previous frame so we can draw it behind. - static float remap_panel_high = 40.0f; - ImVec2 p_bg_min = ImGui::GetCursorScreenPos(); - // Adjust background position: slight negative offset to align with padding, width fills available - // height from static variable. - draw_list->AddRectFilled({p_bg_min.x - 10.0f, p_bg_min.y - 7.0f}, {p_bg_min.x + available_width + ImGui::GetFrameHeight(), p_bg_min.y + remap_panel_high}, ImGui::GetColorU32(ImGuiCol_FrameBgActive, 1.0f), 5.0f); - - float start_y = ImGui::GetCursorPos().y; - - // ORCA: Title as simple text - Removed as per request (redundant with button) - // m_imgui->text(title); - - ImGui::BeginGroup(); - // ORCA: Reduce vertical spacing within this group - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(m_imgui->scaled(0.4f), m_imgui->scaled(0.2f))); - - render_filament_remap_ui(window_width, max_tooltip_width); - - ImGui::PopStyleVar(); - ImGui::EndGroup(); - - // ORCA: Update height for next frame fill - remap_panel_high = ImGui::GetCursorPos().y - start_y; - - // ORCA: Add Remap and Cancel buttons (outside the panel) - ImGui::Spacing(); - if (m_imgui->button(m_desc.at("remap"))) { - this->remap_filament_assignments(); - // Reset mapping to identity after apply - for (size_t i = 0; i < m_extruder_remap.size(); ++i) m_extruder_remap[i] = i; - } - ImGui::SameLine(); - if (m_imgui->button(m_desc.at("cancel_remap"))) { - // Reset mapping to identity - for (size_t i = 0; i < m_extruder_remap.size(); ++i) m_extruder_remap[i] = i; - } - } - ImGui::Separator(); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f)); @@ -1000,180 +990,85 @@ void GLGizmoMmuSegmentation::update_used_filaments() } } -void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float max_tooltip_width) +void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float max_tooltip_width, float scale) { size_t n_extr = std::min((size_t)EnforcerBlockerType::ExtruderMax, m_extruders_colors.size()); - const ImVec2 max_label_size = ImGui::CalcTextSize("99", NULL, true); - const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f), 0.f); - int displayed_count = 0; const int max_per_line = 8; // ORCA: Use m_used_filaments to show only relevant source filaments + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(7.f * scale, 7.f * scale)); for (size_t src : m_used_filaments) { if (src >= n_extr) continue; - const ColorRGBA &src_col = m_extruders_colors[src]; // keep for text contrast - const ColorRGBA &dst_col = m_extruders_colors[m_extruder_remap[src]]; - - // ORCA: Button now shows the SOURCE color (per maintainer request) - // This keeps the UI stable until "Remap" is clicked. - ImVec4 col_vec = ImGuiWrapper::to_ImVec4(src_col); - if (displayed_count > 0 && (displayed_count % max_per_line != 0)) ImGui::SameLine(); - std::string btn_id = "##remap_src_" + std::to_string(src); std::string pop_id = "popup_" + std::to_string(src); - - ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | - ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoPicker | - ImGuiColorEditFlags_NoTooltip; - - // ORCA: Show border ONLY if the popup is open (visual feedback for active selection) - // Decoupled from m_selected_extruder_idx to prevent unwanted selection highlights. - if (!ImGui::IsPopupOpen(pop_id.c_str())) - flags |= ImGuiColorEditFlags_NoBorder; - - #ifdef __APPLE__ - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0); - bool clicked = ImGui::ColorButton(btn_id.c_str(), col_vec, flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); - #else - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0); - bool clicked = ImGui::ColorButton(btn_id.c_str(), col_vec, flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); - #endif - // overlay destination number with proper contrast calculation - // ORCA: Text still shows DESTINATION index, but contrast is against SOURCE color now. - std::string dst_txt = std::to_string(m_extruder_remap[src] + 1); - float gray = 0.299f * src_col.r() + 0.587f * src_col.g() + 0.114f * src_col.b(); - ImVec2 txt_sz = ImGui::CalcTextSize(dst_txt.c_str()); - ImVec2 pos = ImGui::GetItemRectMin(); - ImVec2 size = ImGui::GetItemRectSize(); - - if (gray * 255.f < 80.f) - ImGui::GetWindowDrawList()->AddText( - ImVec2(pos.x + (size.x - txt_sz.x) * 0.5f, pos.y + (size.y - txt_sz.y) * 0.5f), - IM_COL32(255,255,255,255), dst_txt.c_str()); - else - ImGui::GetWindowDrawList()->AddText( - ImVec2(pos.x + (size.x - txt_sz.x) * 0.5f, pos.y + (size.y - txt_sz.y) * 0.5f), - IM_COL32(0,0,0,255), dst_txt.c_str()); + bool src_clicked = draw_color_button( + (int)src + 1, // idx + "###remap_src_", // button_id + m_extruders_colors[src], // color + m_extruders_colors[m_extruder_remap[src]], // mapped_color (shows bubble if not matches with Color) + ImGui::IsPopupOpen(pop_id.c_str()), // is_active + scale + ); - // ORCA: Show NEW color as a small triangle in the corner if remapped - if (src != m_extruder_remap[src]) { - float s = m_imgui->scaled(0.55f); - float offset = m_imgui->scaled(0.15f); // Inset to avoid rounded corner clipping - ImVec2 p = ImVec2(pos.x + offset, pos.y + offset); - - // Contrast outline: White for dark backgrounds, Black for light backgrounds - // Use dst_col (new color) for outline contrast check? Or src_col? - // Usually outline is around the triangle (dst_col). - float dst_gray = 0.299f * dst_col.r() + 0.587f * dst_col.g() + 0.114f * dst_col.b(); - ImU32 outline_col = (dst_gray * 255.f < 80.f) ? IM_COL32(255, 255, 255, 180) : IM_COL32(0, 0, 0, 180); - - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - draw_list->AddTriangleFilled( - p, - ImVec2(p.x + s, p.y), - ImVec2(p.x, p.y + s), - ImGuiWrapper::to_ImU32(dst_col)); - - // ORCA: Add a thin outline for better contrast when colors are similar - draw_list->AddTriangle( - p, - ImVec2(p.x + s, p.y), - ImVec2(p.x, p.y + s), - outline_col, - 0.5f); - } - - // popup with possible destinations - if (clicked) { + if (src_clicked) { // Calculate popup position centered below the current button ImVec2 button_pos = ImGui::GetItemRectMin(); ImVec2 button_size = ImGui::GetItemRectSize(); - ImVec2 popup_pos(button_pos.x + button_size.x * 0.5f, button_pos.y + button_size.y); - - // Set popup styling BEFORE opening popup + + // Ensure popup is within the main viewport bounds + int dst_count = (int)std::min(n_extr, (size_t)max_per_line); + float est_popup_w = button_size.x * dst_count + + ImGui::GetStyle().ItemSpacing.x * (dst_count - 1) + + ImGui::GetStyle().WindowPadding.x * 2.f; + + ImGuiViewport* vp = ImGui::GetMainViewport(); + float right_limit = vp->WorkPos.x + vp->WorkSize.x - est_popup_w * 0.5f; // pivot is 0.5 so subtract half + float centered_x = button_pos.x + button_size.x * 0.5f; // pivot 0.5 just needs center x + + ImVec2 popup_pos(std::min(centered_x, right_limit), button_pos.y + button_size.y); + ImGui::SetNextWindowPos(popup_pos, ImGuiCond_Appearing, ImVec2(0.5f, -0.1f)); ImGui::SetNextWindowBgAlpha(1.0f); // Ensure full opacity ImGui::OpenPopup(pop_id.c_str()); } + + if (ImGui::IsItemHovered() && src != m_extruder_remap[src]) // show tooltip if it has mapping info + m_imgui->tooltip(std::to_string(src + 1) + " >> " + std::to_string(m_extruder_remap[src] + 1), max_tooltip_width); // Apply popup styling before BeginPopup using standard Orca colors - ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding, 4.0f); - ImGui::PushStyleVar(ImGuiStyleVar_PopupBorderSize, 1.0f); - // ORCA: Use FrameBgActive for consistency and to ensure visibility of white filaments - ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBgActive)); - ImGui::PushStyleColor(ImGuiCol_Border, m_is_dark_mode ? ImVec4(0.5f, 0.5f, 0.5f, 1.0f) : ImVec4(0.6f, 0.6f, 0.6f, 1.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding , 8.0f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_PopupBorderSize, 2.0f * scale); // thicker & colored border to prevent mixing with main window. Current ImGui version not supports shadows + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg)); + ImGui::PushStyleColor(ImGuiCol_Border , ImGui::ColorConvertFloat4ToU32(ImGuiWrapper::COL_ORCA)); if (ImGui::BeginPopup(pop_id.c_str())) { m_imgui->text(_L("To:")); for (int dst = 0; dst < (int)n_extr; ++dst) { - const ColorRGBA &dst_col_popup = m_extruders_colors[dst]; - ImVec4 dst_vec = ImGuiWrapper::to_ImVec4(dst_col_popup); if (dst > 0 && (dst % max_per_line != 0)) ImGui::SameLine(); - std::string dst_btn = "##dst_" + std::to_string(src) + "_" + std::to_string(dst); - - // Apply same styling to destination buttons - ImGuiColorEditFlags dst_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | - ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoPicker | - ImGuiColorEditFlags_NoTooltip; - // Show border for currently selected destination filament - if (m_extruder_remap[src] != dst) dst_flags |= ImGuiColorEditFlags_NoBorder; - - #ifdef __APPLE__ - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0); - bool dst_clicked = ImGui::ColorButton(dst_btn.c_str(), dst_vec, dst_flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); - #else - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0); - bool dst_clicked = ImGui::ColorButton(dst_btn.c_str(), dst_vec, dst_flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); - #endif - - // overlay destination number on popup buttons - std::string dst_num_txt = std::to_string(dst + 1); - float dst_gray = 0.299f * dst_col_popup.r() + 0.587f * dst_col_popup.g() + 0.114f * dst_col_popup.b(); - ImVec2 dst_txt_sz = ImGui::CalcTextSize(dst_num_txt.c_str()); - ImVec2 dst_pos = ImGui::GetItemRectMin(); - ImVec2 dst_size = ImGui::GetItemRectSize(); - - if (dst_gray * 255.f < 80.f) - ImGui::GetWindowDrawList()->AddText( - ImVec2(dst_pos.x + (dst_size.x - dst_txt_sz.x) * 0.5f, dst_pos.y + (dst_size.y - dst_txt_sz.y) * 0.5f), - IM_COL32(255,255,255,255), dst_num_txt.c_str()); - else - ImGui::GetWindowDrawList()->AddText( - ImVec2(dst_pos.x + (dst_size.x - dst_txt_sz.x) * 0.5f, dst_pos.y + (dst_size.y - dst_txt_sz.y) * 0.5f), - IM_COL32(0,0,0,255), dst_num_txt.c_str()); - - if (dst_clicked) - { + bool dst_clicked = draw_color_button( + dst + 1, // idx + "###remap_dst_", // button_id + m_extruders_colors[dst], // color + m_extruders_colors[dst], // mapped_color (non fuctional in here) + m_extruder_remap[src] == dst, // is_active + scale + ); + if (dst_clicked) { m_extruder_remap[src] = dst; // update the source button color immediately ImGui::CloseCurrentPopup(); } } + ImGui::Dummy(ImVec2(0.0f, 2.f * scale)); ImGui::EndPopup(); } @@ -1183,6 +1078,7 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float displayed_count++; } + ImGui::PopStyleVar(1); // ItemSpacing } void GLGizmoMmuSegmentation::remap_filament_assignments() diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp index 756ada7670..eb8473aea6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp @@ -114,7 +114,6 @@ protected: bool m_detect_geometry_edge = true; // Filament remap feature - bool m_show_remap_panel = false; std::vector m_extruder_remap; // index → target extruder index // ORCA: Cache used filaments to filter UI std::set m_used_filaments; // Set of used filament indices (cached) @@ -136,13 +135,16 @@ private: void init_model_triangle_selectors(); + // ORCA + bool draw_color_button(int idx, std::string id_str, const ColorRGBA& color, ColorRGBA& map_color, bool active, float scale); + // BBS void update_triangle_selectors_colors(); void init_extruders_data(); // Filament remapping methods void remap_filament_assignments(); - void render_filament_remap_ui(float window_width, float max_tooltip_width); + void render_filament_remap_ui(float window_width, float max_tooltip_width, float scale); // ORCA: Helper to update the cache of used filaments void update_used_filaments(); From c2ac0baa0525808cbca4a015ca2afd5d6dcffb1a Mon Sep 17 00:00:00 2001 From: yw4z Date: Tue, 5 May 2026 19:07:15 +0300 Subject: [PATCH 19/44] Fix iconic button sizes on widgets (paint modes and gcode viewer buttons) (#13365) * init * update --- src/slic3r/GUI/GCodeViewer.cpp | 28 +++++------ src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 42 ++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoFuzzySkin.cpp | 43 +++++++++-------- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 37 +++++++------- src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 44 +++++++++-------- src/slic3r/GUI/ImGuiWrapper.cpp | 48 +++++++++++++++++++ src/slic3r/GUI/ImGuiWrapper.hpp | 1 + 7 files changed, 145 insertions(+), 98 deletions(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 678a99deb5..b1792c6966 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -516,13 +516,15 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode } ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding , 3.f * m_scale); - ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(.5f, .5f)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding , ImVec2(2.f, 2.f) * m_scale); ImGui::PushStyleColor(ImGuiCol_Button , ImVec4(0, 0, 0, 0)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered , ImVec4(84 / 255.f, 84 / 255.f, 90 / 255.f, 1.f)); ImGui::PushStyleColor(ImGuiCol_ButtonActive , ImVec4(84 / 255.f, 84 / 255.f, 90 / 255.f, 1.f)); const float main_wnd_height = ImGui::GetWindowHeight(); - if (ImGui::Button(into_u8(properties_shown ? ImGui::UnfoldButtonIcon : ImGui::FoldButtonIcon).c_str(), ImVec2(24.f, 24.f) * m_scale)) { + // ORCA use glyph based button for fixing button sizes changing depends on used font size on platform + const wchar_t foldIcon = properties_shown ? ImGui::UnfoldButtonIcon : ImGui::FoldButtonIcon; + if (imgui.glyph_button(foldIcon, ImVec2(16.f, 16.f) * m_scale)) { properties_shown = !properties_shown; static float main_wnd_height_temp = ImGui::GetWindowHeight(); static float first_click = true; @@ -537,7 +539,8 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode ImGui::SameLine(); - ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetStyle().FramePadding.y); // aligns button with next group + if(!properties_shown) + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetStyle().FramePadding.y); // aligns button with next group ImGui::BeginGroup(); // group contents to make information area more compact @@ -3327,29 +3330,26 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ImGui::Dummy({ window_padding, window_padding }); ImGui::Dummy({ window_padding, window_padding }); ImGui::SameLine(window_padding * 2); // ORCA Ignores item spacing to get perfect window margins since since this part uses dummies for window padding - std::wstring btn_name; - if (m_fold) - btn_name = ImGui::UnfoldButtonIcon; - else - btn_name = ImGui::FoldButtonIcon; + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(84 / 255.f, 84 / 255.f, 90 / 255.f, 1.f)); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(84 / 255.f, 84 / 255.f, 90 / 255.f, 1.f)); - float calc_padding = (ImGui::GetFrameHeight() - 16 * m_scale) / 2; // ORCA calculated padding for 16x16 icon - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(calc_padding, calc_padding)); // ORCA Center icon with frame padding - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f * m_scale); // ORCA Match button style with combo box + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding , ImVec2(2.f, 2.f) * m_scale); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f * m_scale); // ORCA Match button style with combo box - float button_width = 16 * m_scale + calc_padding * 2; // ORCA match buttons height with combo box - if (ImGui::Button(into_u8(btn_name).c_str(), ImVec2(button_width, button_width))) { + // ORCA use glyph based button for fixing button sizes changing depends on used font size on platform + const wchar_t foldIcon = m_fold ? ImGui::UnfoldButtonIcon : ImGui::FoldButtonIcon; + if (imgui.glyph_button(foldIcon, ImVec2(16.f, 16.f) * m_scale)) { m_fold = !m_fold; } ImGui::SameLine(); const wchar_t gCodeToggle = ImGui::gCodeButtonIcon; - if (ImGui::Button(into_u8(gCodeToggle).c_str(), ImVec2(button_width, button_width))) { + if (imgui.glyph_button(gCodeToggle, ImVec2(16.f, 16.f) * m_scale)) { wxGetApp().toggle_show_gcode_window(); wxGetApp().plater()->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); } + ImGui::PopStyleColor(3); ImGui::PopStyleVar(2); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 7aa347b9c2..7af55915d5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -191,6 +191,12 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l if (! m_c->selection_info()->model_object()) return; + float scale = m_parent.get_scale(); + #ifdef WIN32 + int dpi = get_dpi_for_window(wxGetApp().GetTopWindow()); + scale *= (float) dpi / (float) DPI_DEFAULT; + #endif // WIN32 + // BBS wchar_t old_tool = m_current_tool; @@ -258,30 +264,24 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l std::array tool_tips = { _L("Circle"), _L("Sphere"), _L("Fill"), _L("Gap Fill") }; for (int i = 0; i < tool_ids.size(); i++) { - std::string str_label = std::string("##"); - std::wstring btn_name = icons[i] + boost::nowide::widen(str_label); + //std::string str_label = std::string("##"); + //std::wstring btn_name = icons[i] + boost::nowide::widen(str_label); if (i != 0) ImGui::SameLine((empty_button_width + m_imgui->scaled(1.75f)) * i + m_imgui->scaled(1.3f)); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.f, 0.f, 0.f)); // ORCA Removes button background on dark mode - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f)); // ORCA: Fixes icon rendered without colors while using Light theme - if (m_current_tool == tool_ids[i]) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.f, 0.59f, 0.53f, 0.30f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_Border, ImGuiWrapper::COL_ORCA); // ORCA use orca color for border on selected tool / brush - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0); - } - bool btn_clicked = ImGui::Button(into_u8(btn_name).c_str()); - if (m_current_tool == tool_ids[i]) - { - ImGui::PopStyleColor(4); - ImGui::PopStyleVar(2); - } - ImGui::PopStyleColor(2); - ImGui::PopStyleVar(1); + bool is_active = m_current_tool == tool_ids[i]; + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding , 3.f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding , ImVec2(4.f * scale, 4.f * scale)); + ImGui::PushStyleColor(ImGuiCol_Text , ImVec4(1,1,1,1)); // ORCA Fixes icon rendered without colors while using Light theme + ImGui::PushStyleColor(ImGuiCol_Button , is_active ? ImVec4(0.f, .59f, .53f, .25f) : ImVec4(0,0,0,0)); // ORCA + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, is_active ? ImVec4(0.f, .59f, .53f, .25f) : ImVec4(.6f,.6f,.6f,.2f)); // ORCA + ImGui::PushStyleColor(ImGuiCol_ButtonActive , is_active ? ImVec4(0.f, .59f, .53f, .30f) : ImVec4(0,0,0,0)); // ORCA + ImGui::PushStyleColor(ImGuiCol_Border , is_active ? ImGuiWrapper::COL_ORCA : ImVec4(0,0,0,0)); // ORCA + ImGui::PushStyleColor(ImGuiCol_BorderActive , is_active ? ImGuiWrapper::COL_ORCA : ImVec4(0,0,0,0)); // ORCA matched color for fixing flicker on click + bool btn_clicked = m_imgui->glyph_button(icons[i], ImVec2(16.f * scale, 16.f * scale)); // ORCA glyph_button for fixing unequal paddings + ImGui::PopStyleColor(6); + ImGui::PopStyleVar(3); if (btn_clicked && m_current_tool != tool_ids[i]) { m_current_tool = tool_ids[i]; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFuzzySkin.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFuzzySkin.cpp index 80470de7ad..d80687544e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFuzzySkin.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFuzzySkin.cpp @@ -117,6 +117,12 @@ void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_lim if (!mo) return; + float scale = m_parent.get_scale(); + #ifdef WIN32 + int dpi = get_dpi_for_window(wxGetApp().GetTopWindow()); + scale *= (float) dpi / (float) DPI_DEFAULT; + #endif // WIN32 + const DynamicPrintConfig &obj_cfg = mo->config.get(); const float approx_height = m_imgui->scaled(22.f); @@ -192,29 +198,24 @@ void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_lim icons = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::TriangleButtonIcon, ImGui::FillButtonIcon }; std::array tool_tips = { _L("Circle"), _L("Sphere"), _L("Triangle"), _L("Fill") }; for (int i = 0; i < tool_ids.size(); i++) { - std::string str_label = std::string(""); - std::wstring btn_name = icons[i] + boost::nowide::widen(str_label); + //std::string str_label = std::string(""); + //std::wstring btn_name = icons[i] + boost::nowide::widen(str_label); if (i != 0) ImGui::SameLine((empty_button_width + m_imgui->scaled(1.75f)) * i + m_imgui->scaled(1.5f)); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.f, 0.f, 0.f)); // ORCA Removes button background on dark mode - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f)); // ORCA Fixes icon rendered without colors while using Light theme - if (m_current_tool == tool_ids[i]) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.f, 0.59f, 0.53f, 0.30f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_Border, ImGuiWrapper::COL_ORCA); // ORCA use orca color for border on selected tool / brush - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0); - } - bool btn_clicked = ImGui::Button(into_u8(btn_name).c_str()); - if (m_current_tool == tool_ids[i]) - { - ImGui::PopStyleColor(4); - ImGui::PopStyleVar(2); - } - ImGui::PopStyleColor(2); - ImGui::PopStyleVar(1); + + bool is_active = m_current_tool == tool_ids[i]; + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding , 3.f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding , ImVec2(4.f * scale, 4.f * scale)); + ImGui::PushStyleColor(ImGuiCol_Text , ImVec4(1,1,1,1)); // ORCA Fixes icon rendered without colors while using Light theme + ImGui::PushStyleColor(ImGuiCol_Button , is_active ? ImVec4(0.f, .59f, .53f, .25f) : ImVec4(0,0,0,0)); // ORCA + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, is_active ? ImVec4(0.f, .59f, .53f, .25f) : ImVec4(.6f,.6f,.6f,.2f)); // ORCA + ImGui::PushStyleColor(ImGuiCol_ButtonActive , is_active ? ImVec4(0.f, .59f, .53f, .30f) : ImVec4(0,0,0,0)); // ORCA + ImGui::PushStyleColor(ImGuiCol_Border , is_active ? ImGuiWrapper::COL_ORCA : ImVec4(0,0,0,0)); // ORCA + ImGui::PushStyleColor(ImGuiCol_BorderActive , is_active ? ImGuiWrapper::COL_ORCA : ImVec4(0,0,0,0)); // ORCA matched color for fixing flicker on click + bool btn_clicked = m_imgui->glyph_button(icons[i], ImVec2(16.f * scale, 16.f * scale)); // ORCA glyph_button for fixing unequal paddings + ImGui::PopStyleColor(6); + ImGui::PopStyleVar(3); if (btn_clicked && m_current_tool != tool_ids[i]) { m_current_tool = tool_ids[i]; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index de27cd6bc7..72e880f85d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -483,29 +483,24 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott icons = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::TriangleButtonIcon, ImGui::HeightRangeIcon, ImGui::FillButtonIcon, ImGui::GapFillIcon }; std::array tool_tips = { _L("Circle"), _L("Sphere"), _L("Triangle"), _L("Height Range"), _L("Fill"), _L("Gap Fill") }; for (int i = 0; i < tool_ids.size(); i++) { - std::string str_label = std::string(""); - std::wstring btn_name = icons[i] + boost::nowide::widen(str_label); + //std::string str_label = std::string(""); + //std::wstring btn_name = icons[i] + boost::nowide::widen(str_label); if (i != 0) ImGui::SameLine((empty_button_width + m_imgui->scaled(1.75f)) * i + m_imgui->scaled(1.5f)); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.f, 0.f, 0.f)); // ORCA Removes button background on dark mode - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f)); // ORCA Fixes icon rendered without colors while using Light theme - if (m_current_tool == tool_ids[i]) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.f, 0.59f, 0.53f, 0.30f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_Border, ImGuiWrapper::COL_ORCA); // ORCA use orca color for border on selected tool / brush - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0); - } - bool btn_clicked = ImGui::Button(into_u8(btn_name).c_str()); - if (m_current_tool == tool_ids[i]) - { - ImGui::PopStyleColor(4); - ImGui::PopStyleVar(2); - } - ImGui::PopStyleColor(2); - ImGui::PopStyleVar(1); + + bool is_active = m_current_tool == tool_ids[i]; + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding , 3.f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding , ImVec2(4.f * scale, 4.f * scale)); + ImGui::PushStyleColor(ImGuiCol_Text , ImVec4(1,1,1,1)); // ORCA Fixes icon rendered without colors while using Light theme + ImGui::PushStyleColor(ImGuiCol_Button , is_active ? ImVec4(0.f, .59f, .53f, .25f) : ImVec4(0,0,0,0)); // ORCA + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, is_active ? ImVec4(0.f, .59f, .53f, .25f) : ImVec4(.6f,.6f,.6f,.2f)); // ORCA + ImGui::PushStyleColor(ImGuiCol_ButtonActive , is_active ? ImVec4(0.f, .59f, .53f, .30f) : ImVec4(0,0,0,0)); // ORCA + ImGui::PushStyleColor(ImGuiCol_Border , is_active ? ImGuiWrapper::COL_ORCA : ImVec4(0,0,0,0)); // ORCA + ImGui::PushStyleColor(ImGuiCol_BorderActive , is_active ? ImGuiWrapper::COL_ORCA : ImVec4(0,0,0,0)); // ORCA matched color for fixing flicker on click + bool btn_clicked = m_imgui->glyph_button(icons[i], ImVec2(16.f * scale, 16.f * scale)); // ORCA glyph_button for fixing unequal paddings + ImGui::PopStyleColor(6); + ImGui::PopStyleVar(3); if (btn_clicked && m_current_tool != tool_ids[i]) { m_current_tool = tool_ids[i]; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 8790fd430d..1051c5ab3c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -121,6 +121,12 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) if (! m_c->selection_info()->model_object()) return; + float scale = m_parent.get_scale(); + #ifdef WIN32 + int dpi = get_dpi_for_window(wxGetApp().GetTopWindow()); + scale *= (float) dpi / (float) DPI_DEFAULT; + #endif // WIN32 + const float approx_height = m_imgui->scaled(12.5f); y = std::min(y, bottom_limit - approx_height); //BBS: GUI refactor: move gizmo to the right @@ -170,29 +176,25 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) icons = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon }; std::array tool_tips = { _L("Circle"), _L("Sphere")}; for (int i = 0; i < tool_ids.size(); i++) { - std::string str_label = std::string("##"); - std::wstring btn_name = icons[i] + boost::nowide::widen(str_label); + //std::string str_label = std::string("##"); + //std::wstring btn_name = icons[i] + boost::nowide::widen(str_label); if (i != 0) ImGui::SameLine((empty_button_width + m_imgui->scaled(1.75f)) * i + m_imgui->scaled(1.3f)); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.f, 0.f, 0.f)); // ORCA Removes button background on dark mode - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f)); // ORCA: Fixes icon rendered without colors while using Light theme - if (m_current_tool == tool_ids[i]) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.f, 0.59f, 0.53f, 0.30f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_Border, ImGuiWrapper::COL_ORCA); // ORCA use orca color for border on selected tool / brush - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0); - } - bool btn_clicked = ImGui::Button(into_u8(btn_name).c_str()); - if (m_current_tool == tool_ids[i]) - { - ImGui::PopStyleColor(4); - ImGui::PopStyleVar(2); - } - ImGui::PopStyleColor(2); - ImGui::PopStyleVar(1); + + bool is_active = m_current_tool == tool_ids[i]; + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding , 3.f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding , ImVec2(4.f * scale, 4.f * scale)); + ImGui::PushStyleColor(ImGuiCol_Text , ImVec4(1,1,1,1)); // ORCA Fixes icon rendered without colors while using Light theme + ImGui::PushStyleColor(ImGuiCol_Button , is_active ? ImVec4(0.f, .59f, .53f, .25f) : ImVec4(0,0,0,0)); // ORCA + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, is_active ? ImVec4(0.f, .59f, .53f, .25f) : ImVec4(.6f,.6f,.6f,.2f)); // ORCA + ImGui::PushStyleColor(ImGuiCol_ButtonActive , is_active ? ImVec4(0.f, .59f, .53f, .30f) : ImVec4(0,0,0,0)); // ORCA + ImGui::PushStyleColor(ImGuiCol_Border , is_active ? ImGuiWrapper::COL_ORCA : ImVec4(0,0,0,0)); // ORCA + ImGui::PushStyleColor(ImGuiCol_BorderActive , is_active ? ImGuiWrapper::COL_ORCA : ImVec4(0,0,0,0)); // ORCA matched color for fixing flicker on click + bool btn_clicked = m_imgui->glyph_button(icons[i], ImVec2(16.f * scale, 16.f * scale)); // ORCA glyph_button for fixing unequal paddings + ImGui::PopStyleColor(6); + ImGui::PopStyleVar(3); + if (btn_clicked && m_current_tool != tool_ids[i]) { m_current_tool = tool_ids[i]; for (auto& triangle_selector : m_triangle_selectors) { diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 67f33ce851..85f59d31e5 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -908,6 +908,54 @@ bool ImGuiWrapper::button(const wxString& label, const ImVec2 &size, bool enable return (enable) ? res : false; } +// ORCA Glyph based button for correctly rendering icon size based Glyph +// excludes spacings after Glyph and centers icon properly +// compared to image_button this supports styling +bool ImGuiWrapper::glyph_button(wchar_t icon_char, ImVec2 icon_size) +{ + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + ImFont* font = ImGui::GetFont(); + ImGuiStyle& style = ImGui::GetStyle(); + ImVec2 padding = style.FramePadding; + float border_w = style.FrameBorderSize; + float rounding = style.FrameRounding; + std::string icon_str = into_u8(icon_char); + const char* icon = icon_str.c_str(); + + float width = icon_size.x + (padding.x + border_w) * 2.f; + float height = icon_size.y + (padding.y + border_w) * 2.f; + ImVec2 rc_min = ImGui::GetCursorScreenPos(); + ImVec2 rc_max = ImVec2(rc_min.x + width, rc_min.y + height); + + ImGui::Dummy(ImVec2(width, height)); + + ImGuiCol bg_color = ImGuiCol_Button; + ImGuiCol border_color = ImGuiCol_Border; + bool clicked = false; + + if (ImGui::IsMouseHoveringRect(rc_min, rc_max)) { + bg_color = ImGuiCol_ButtonHovered; + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { + bg_color = ImGuiCol_ButtonActive; + border_color = ImGuiCol_BorderShadow; + clicked = true; + } + } + + draw_list->AddRectFilled(rc_min, rc_max, ImGui::GetColorU32(bg_color), rounding); + + if (border_w > 0.f) + draw_list->AddRect(rc_min, rc_max, ImGui::GetColorU32(border_color), rounding, 0, border_w); + + ImVec2 text_pos = ImVec2( + rc_min.x + (width - font->FontSize) * .5f, + rc_min.y + (height - font->FontSize) * .5f + ); + draw_list->AddText(font, font->FontSize, text_pos, ImGui::GetColorU32(ImGuiCol_Text), icon); + + return clicked; +} + bool ImGuiWrapper::radio_button(const wxString &label, bool active) { auto label_utf8 = into_u8(label); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 21ca91013b..a2b8476c71 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -133,6 +133,7 @@ public: bool bbl_button(const wxString &label, const wxString& tooltip = {}); bool button(const wxString& label, float width, float height); bool button(const wxString& label, const ImVec2 &size, bool enable); // default size = ImVec2(0.f, 0.f) + bool glyph_button(wchar_t icon_char, ImVec2 icon_size); // ORCA bool radio_button(const wxString &label, bool active); static ImVec4 to_ImVec4(const ColorRGB &color); bool input_double(const std::string &label, const double &value, const std::string &format = "%.3f"); From 57cee529b47ae442e3b115a1a75095d5f74d858f Mon Sep 17 00:00:00 2001 From: LH <42773937+lhndo@users.noreply.github.com> Date: Tue, 5 May 2026 17:33:30 +0000 Subject: [PATCH 20/44] Add LH Stinger printer profiles (#13410) --- resources/profiles/LH.json | 159 ++++++++ .../profiles/LH/LH Stinger MMU_cover.png | Bin 0 -> 65635 bytes resources/profiles/LH/LH Stinger_cover.png | Bin 0 -> 66382 bytes .../LH/LH_Stinger_MMU_buildplate_texture.png | Bin 0 -> 19546 bytes .../LH/LH_Stinger_buildplate_model.stl | Bin 0 -> 186634 bytes .../LH/LH_Stinger_buildplate_texture.png | Bin 0 -> 17742 bytes resources/profiles/LH/filament/LHS ABS.json | 355 ++++++++++++++++++ resources/profiles/LH/filament/LHS ASA.json | 352 +++++++++++++++++ resources/profiles/LH/filament/LHS PC CF.json | 122 ++++++ resources/profiles/LH/filament/LHS PCTG.json | 352 +++++++++++++++++ resources/profiles/LH/filament/LHS PETG.json | 352 +++++++++++++++++ resources/profiles/LH/filament/LHS PLA.json | 352 +++++++++++++++++ .../LH/filament/LHS TPU Foamy 78A.json | 352 +++++++++++++++++ resources/profiles/LH/filament/LHS TPU.json | 352 +++++++++++++++++ .../LH/filament/fdm_filament_abs.json | 88 +++++ .../LH/filament/fdm_filament_asa.json | 88 +++++ .../LH/filament/fdm_filament_common.json | 141 +++++++ .../profiles/LH/filament/fdm_filament_pc.json | 88 +++++ .../LH/filament/fdm_filament_pet.json | 82 ++++ .../LH/filament/fdm_filament_pla.json | 94 +++++ .../LH/filament/fdm_filament_tpu.json | 88 +++++ .../LH/machine/LH Stinger 0.4 nozzle.json | 16 + .../LH/machine/LH Stinger MMU 0.4 nozzle.json | 16 + .../profiles/LH/machine/LH Stinger MMU.json | 12 + resources/profiles/LH/machine/LH Stinger.json | 12 + .../profiles/LH/machine/fdm_lh_common.json | 157 ++++++++ .../LH/machine/fdm_lh_mmu_common.json | 21 ++ .../LH/machine/fdm_machine_common.json | 119 ++++++ .../process/0.10mm HueForge @LH Stinger.json | 42 +++ .../LH/process/0.14mm Detail @LH Stinger.json | 54 +++ .../0.14mm Detail Strength @LH Stinger.json | 67 ++++ .../LH/process/0.20mm Daily @LH Stinger.json | 12 + .../LH/process/0.20mm MMU @LH Stinger.json | 48 +++ .../LH/process/0.20mm PETG @LH Stinger.json | 74 ++++ .../LH/process/0.20mm Quiet @LH Stinger.json | 53 +++ .../LH/process/0.20mm Solid @LH Stinger.json | 64 ++++ .../LH/process/0.20mm Speed @LH Stinger.json | 43 +++ .../process/0.20mm Strength @LH Stinger.json | 66 ++++ .../LH/process/0.20mm TPU @LH Stinger.json | 82 ++++ .../process/0.25mm Vase Mode @LH Stinger.json | 70 ++++ .../LH/process/fdm_process_common.json | 108 ++++++ .../LH/process/fdm_process_lh_common.json | 109 ++++++ 42 files changed, 4662 insertions(+) create mode 100644 resources/profiles/LH.json create mode 100644 resources/profiles/LH/LH Stinger MMU_cover.png create mode 100644 resources/profiles/LH/LH Stinger_cover.png create mode 100644 resources/profiles/LH/LH_Stinger_MMU_buildplate_texture.png create mode 100644 resources/profiles/LH/LH_Stinger_buildplate_model.stl create mode 100644 resources/profiles/LH/LH_Stinger_buildplate_texture.png create mode 100644 resources/profiles/LH/filament/LHS ABS.json create mode 100644 resources/profiles/LH/filament/LHS ASA.json create mode 100644 resources/profiles/LH/filament/LHS PC CF.json create mode 100644 resources/profiles/LH/filament/LHS PCTG.json create mode 100644 resources/profiles/LH/filament/LHS PETG.json create mode 100644 resources/profiles/LH/filament/LHS PLA.json create mode 100644 resources/profiles/LH/filament/LHS TPU Foamy 78A.json create mode 100644 resources/profiles/LH/filament/LHS TPU.json create mode 100644 resources/profiles/LH/filament/fdm_filament_abs.json create mode 100644 resources/profiles/LH/filament/fdm_filament_asa.json create mode 100644 resources/profiles/LH/filament/fdm_filament_common.json create mode 100644 resources/profiles/LH/filament/fdm_filament_pc.json create mode 100644 resources/profiles/LH/filament/fdm_filament_pet.json create mode 100644 resources/profiles/LH/filament/fdm_filament_pla.json create mode 100644 resources/profiles/LH/filament/fdm_filament_tpu.json create mode 100644 resources/profiles/LH/machine/LH Stinger 0.4 nozzle.json create mode 100644 resources/profiles/LH/machine/LH Stinger MMU 0.4 nozzle.json create mode 100644 resources/profiles/LH/machine/LH Stinger MMU.json create mode 100644 resources/profiles/LH/machine/LH Stinger.json create mode 100644 resources/profiles/LH/machine/fdm_lh_common.json create mode 100644 resources/profiles/LH/machine/fdm_lh_mmu_common.json create mode 100644 resources/profiles/LH/machine/fdm_machine_common.json create mode 100644 resources/profiles/LH/process/0.10mm HueForge @LH Stinger.json create mode 100644 resources/profiles/LH/process/0.14mm Detail @LH Stinger.json create mode 100644 resources/profiles/LH/process/0.14mm Detail Strength @LH Stinger.json create mode 100644 resources/profiles/LH/process/0.20mm Daily @LH Stinger.json create mode 100644 resources/profiles/LH/process/0.20mm MMU @LH Stinger.json create mode 100644 resources/profiles/LH/process/0.20mm PETG @LH Stinger.json create mode 100644 resources/profiles/LH/process/0.20mm Quiet @LH Stinger.json create mode 100644 resources/profiles/LH/process/0.20mm Solid @LH Stinger.json create mode 100644 resources/profiles/LH/process/0.20mm Speed @LH Stinger.json create mode 100644 resources/profiles/LH/process/0.20mm Strength @LH Stinger.json create mode 100644 resources/profiles/LH/process/0.20mm TPU @LH Stinger.json create mode 100644 resources/profiles/LH/process/0.25mm Vase Mode @LH Stinger.json create mode 100644 resources/profiles/LH/process/fdm_process_common.json create mode 100644 resources/profiles/LH/process/fdm_process_lh_common.json diff --git a/resources/profiles/LH.json b/resources/profiles/LH.json new file mode 100644 index 0000000000..32df35a0cf --- /dev/null +++ b/resources/profiles/LH.json @@ -0,0 +1,159 @@ +{ + "name": "LH", + "url": "https://github.com/lhndo/LH-Stinger", + "version": "01.00.00.00", + "force_update": "0", + "description": "LH 3D Printer Configuration", + "machine_model_list": [ + { + "name": "LH Stinger", + "sub_path": "machine/LH Stinger.json" + }, + { + "name": "LH Stinger MMU", + "sub_path": "machine/LH Stinger MMU.json" + } + ], + "process_list": [ + { + "name": "fdm_process_common", + "sub_path": "process/fdm_process_common.json" + }, + { + "name": "fdm_process_lh_common", + "sub_path": "process/fdm_process_lh_common.json" + }, + { + "name": "0.20mm Daily @LH Stinger", + "sub_path": "process/0.20mm Daily @LH Stinger.json" + }, + { + "name": "0.25mm Vase Mode @LH Stinger", + "sub_path": "process/0.25mm Vase Mode @LH Stinger.json" + }, + { + "name": "0.20mm TPU @LH Stinger", + "sub_path": "process/0.20mm TPU @LH Stinger.json" + }, + { + "name": "0.20mm Strength @LH Stinger", + "sub_path": "process/0.20mm Strength @LH Stinger.json" + }, + { + "name": "0.20mm Speed @LH Stinger", + "sub_path": "process/0.20mm Speed @LH Stinger.json" + }, + { + "name": "0.20mm Solid @LH Stinger", + "sub_path": "process/0.20mm Solid @LH Stinger.json" + }, + { + "name": "0.20mm Quiet @LH Stinger", + "sub_path": "process/0.20mm Quiet @LH Stinger.json" + }, + { + "name": "0.20mm PETG @LH Stinger", + "sub_path": "process/0.20mm PETG @LH Stinger.json" + }, + { + "name": "0.20mm MMU @LH Stinger", + "sub_path": "process/0.20mm MMU @LH Stinger.json" + }, + { + "name": "0.10mm HueForge @LH Stinger", + "sub_path": "process/0.10mm HueForge @LH Stinger.json" + }, + { + "name": "0.14mm Detail Strength @LH Stinger", + "sub_path": "process/0.14mm Detail Strength @LH Stinger.json" + }, + { + "name": "0.14mm Detail @LH Stinger", + "sub_path": "process/0.14mm Detail @LH Stinger.json" + } + ], + "filament_list": [ + { + "name": "fdm_filament_common", + "sub_path": "filament/fdm_filament_common.json" + }, + { + "name": "fdm_filament_abs", + "sub_path": "filament/fdm_filament_abs.json" + }, + { + "name": "fdm_filament_asa", + "sub_path": "filament/fdm_filament_asa.json" + }, + { + "name": "fdm_filament_pc", + "sub_path": "filament/fdm_filament_pc.json" + }, + { + "name": "fdm_filament_pet", + "sub_path": "filament/fdm_filament_pet.json" + }, + { + "name": "fdm_filament_pla", + "sub_path": "filament/fdm_filament_pla.json" + }, + { + "name": "fdm_filament_tpu", + "sub_path": "filament/fdm_filament_tpu.json" + }, + { + "name": "LHS ASA", + "sub_path": "filament/LHS ASA.json" + }, + { + "name": "LHS ABS", + "sub_path": "filament/LHS ABS.json" + }, + { + "name": "LHS TPU", + "sub_path": "filament/LHS TPU.json" + }, + { + "name": "LHS PLA", + "sub_path": "filament/LHS PLA.json" + }, + { + "name": "LHS TPU Foamy 78A", + "sub_path": "filament/LHS TPU Foamy 78A.json" + }, + { + "name": "LHS PETG", + "sub_path": "filament/LHS PETG.json" + }, + { + "name": "LHS PCTG", + "sub_path": "filament/LHS PCTG.json" + }, + { + "name": "LHS PC CF", + "sub_path": "filament/LHS PC CF.json" + } + ], + "machine_list": [ + { + "name": "fdm_machine_common", + "sub_path": "machine/fdm_machine_common.json" + }, + { + "name": "fdm_lh_common", + "sub_path": "machine/fdm_lh_common.json" + }, + { + "name": "fdm_lh_mmu_common", + "sub_path": "machine/fdm_lh_mmu_common.json" + }, + { + "name": "LH Stinger 0.4 nozzle", + "sub_path": "machine/LH Stinger 0.4 nozzle.json" + }, + { + "name": "LH Stinger MMU 0.4 nozzle", + "sub_path": "machine/LH Stinger MMU 0.4 nozzle.json" + } + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/LH Stinger MMU_cover.png b/resources/profiles/LH/LH Stinger MMU_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..ef0ed9c9e4ad59961a197706c5297c1be6b6233f GIT binary patch literal 65635 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
nzPEFjo*XqvqlBapLLemJN3cN# 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
nzPEFjo*XqvqlBapLLemJN3cN# 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 H<=p=O=H-SN literal 0 HcmV?d00001 diff --git a/resources/profiles/LH/filament/LHS ABS.json b/resources/profiles/LH/filament/LHS ABS.json new file mode 100644 index 0000000000..95cd7ccd73 --- /dev/null +++ b/resources/profiles/LH/filament/LHS ABS.json @@ -0,0 +1,355 @@ +{ + "name": "LHS ABS", + "type": "filament", + "filament_id": "LHF_abs", + "setting_id": "LHF_S_abs", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_asa", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "activate_air_filtration": [ + "0" + ], + "activate_chamber_temp_control": [ + "0" + ], + "adaptive_pressure_advance": [ + "0" + ], + "adaptive_pressure_advance_bridges": [ + "0" + ], + "adaptive_pressure_advance_model": [ + "0,0,0\n0,0,0" + ], + "adaptive_pressure_advance_overhangs": [ + "0" + ], + "additional_cooling_fan_speed": [ + "0" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "2" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "0" + ], + "cool_plate_temp_initial_layer": [ + "0" + ], + "default_filament_colour": [ + "" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "1" + ], + "eng_plate_temp": [ + "100" + ], + "eng_plate_temp_initial_layer": [ + "105" + ], + "fan_cooling_layer_time": [ + "25" + ], + "fan_max_speed": [ + "25" + ], + "fan_min_speed": [ + "25" + ], + "filament_adaptive_volumetric_speed": [ + "0" + ], + "filament_adhesiveness_category": [ + "0" + ], + "filament_change_length": [ + "10" + ], + "filament_cooling_final_speed": [ + "0" + ], + "filament_cooling_initial_speed": [ + "0" + ], + "filament_cooling_moves": [ + "0" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.04" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode\n" + ], + "filament_extruder_variant": [ + "Direct Drive Standard" + ], + "filament_flow_ratio": [ + "0.926" + ], + "filament_flush_temp": [ + "0" + ], + "filament_flush_volumetric_speed": [ + "0" + ], + "filament_ironing_flow": [ + "nil" + ], + "filament_ironing_inset": [ + "nil" + ], + "filament_ironing_spacing": [ + "nil" + ], + "filament_ironing_speed": [ + "nil" + ], + "filament_is_support": [ + "0" + ], + "filament_loading_speed": [ + "0" + ], + "filament_loading_speed_start": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "45" + ], + "filament_minimal_purge_on_wipe_tower": [ + "0" + ], + "filament_multitool_ramming": [ + "0" + ], + "filament_multitool_ramming_flow": [ + "0" + ], + "filament_multitool_ramming_volume": [ + "0" + ], + "filament_notes": [ + "" + ], + "filament_printable": [ + "3" + ], + "filament_ramming_parameters": [ + "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_lift_above": [ + "nil" + ], + "filament_retract_lift_below": [ + "nil" + ], + "filament_retract_lift_enforce": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_settings_id": [ + "LHS - ASA" + ], + "filament_shrink": [ + "100%" + ], + "filament_shrinkage_compensation_z": [ + "100%" + ], + "filament_soluble": [ + "0" + ], + "filament_stamping_distance": [ + "0" + ], + "filament_stamping_loading_speed": [ + "0" + ], + "filament_start_gcode": [ + "; filament start gcode\n; MPC_SET HEATER=extruder FILAMENT_DENSITY=1.07 FILAMENT_HEAT_CAPACITY=2.1\nMAX_FAN LINK_AUX=0" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_tower_interface_pre_extrusion_dist": [ + "10" + ], + "filament_tower_interface_pre_extrusion_length": [ + "0" + ], + "filament_tower_interface_print_temp": [ + "-1" + ], + "filament_tower_interface_purge_volume": [ + "20" + ], + "filament_tower_ironing_area": [ + "4" + ], + "filament_type": [ + "ASA" + ], + "filament_unloading_speed": [ + "0" + ], + "filament_unloading_speed_start": [ + "0" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "4" + ], + "hot_plate_temp": [ + "105" + ], + "hot_plate_temp_initial_layer": [ + "105" + ], + "idle_temperature": [ + "0" + ], + "internal_bridge_fan_speed": [ + "-1" + ], + "ironing_fan_speed": [ + "-1" + ], + "long_retractions_when_ec": [ + "0" + ], + "nozzle_temperature": [ + "260" + ], + "nozzle_temperature_initial_layer": [ + "260" + ], + "nozzle_temperature_range_high": [ + "300" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "overhang_fan_speed": [ + "50" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "pressure_advance": [ + "0.019" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "3" + ], + "retraction_distances_when_ec": [ + "10" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "15" + ], + "slow_down_min_speed": [ + "10" + ], + "supertack_plate_temp": [ + "0" + ], + "supertack_plate_temp_initial_layer": [ + "0" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "110" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "105" + ], + "filament_vendor": [ + "LH Stinger" + ], + "volumetric_speed_coefficients": [ + "" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/filament/LHS ASA.json b/resources/profiles/LH/filament/LHS ASA.json new file mode 100644 index 0000000000..9c8ed46093 --- /dev/null +++ b/resources/profiles/LH/filament/LHS ASA.json @@ -0,0 +1,352 @@ +{ + "name": "LHS ASA", + "filament_id": "LHF_asa", + "setting_id": "LHF_S_asa", + "type": "filament", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_asa", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "activate_air_filtration": [ + "0" + ], + "activate_chamber_temp_control": [ + "0" + ], + "adaptive_pressure_advance": [ + "0" + ], + "adaptive_pressure_advance_bridges": [ + "0" + ], + "adaptive_pressure_advance_model": [ + "0,0,0\n0,0,0" + ], + "adaptive_pressure_advance_overhangs": [ + "0" + ], + "additional_cooling_fan_speed": [ + "0" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "2" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "0" + ], + "cool_plate_temp_initial_layer": [ + "0" + ], + "default_filament_colour": [ + "" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "1" + ], + "eng_plate_temp": [ + "100" + ], + "eng_plate_temp_initial_layer": [ + "105" + ], + "fan_cooling_layer_time": [ + "25" + ], + "fan_max_speed": [ + "25" + ], + "fan_min_speed": [ + "25" + ], + "filament_adaptive_volumetric_speed": [ + "0" + ], + "filament_adhesiveness_category": [ + "0" + ], + "filament_change_length": [ + "10" + ], + "filament_cooling_final_speed": [ + "0" + ], + "filament_cooling_initial_speed": [ + "0" + ], + "filament_cooling_moves": [ + "0" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.04" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode\n" + ], + "filament_extruder_variant": [ + "Direct Drive Standard" + ], + "filament_flow_ratio": [ + "0.926" + ], + "filament_flush_temp": [ + "0" + ], + "filament_flush_volumetric_speed": [ + "0" + ], + "filament_ironing_flow": [ + "nil" + ], + "filament_ironing_inset": [ + "nil" + ], + "filament_ironing_spacing": [ + "nil" + ], + "filament_ironing_speed": [ + "nil" + ], + "filament_is_support": [ + "0" + ], + "filament_loading_speed": [ + "0" + ], + "filament_loading_speed_start": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "45" + ], + "filament_minimal_purge_on_wipe_tower": [ + "0" + ], + "filament_multitool_ramming": [ + "0" + ], + "filament_multitool_ramming_flow": [ + "0" + ], + "filament_multitool_ramming_volume": [ + "0" + ], + "filament_notes": [ + "" + ], + "filament_printable": [ + "3" + ], + "filament_ramming_parameters": [ + "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_lift_above": [ + "nil" + ], + "filament_retract_lift_below": [ + "nil" + ], + "filament_retract_lift_enforce": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_shrink": [ + "100%" + ], + "filament_shrinkage_compensation_z": [ + "100%" + ], + "filament_soluble": [ + "0" + ], + "filament_stamping_distance": [ + "0" + ], + "filament_stamping_loading_speed": [ + "0" + ], + "filament_start_gcode": [ + "; filament start gcode\n; MPC_SET HEATER=extruder FILAMENT_DENSITY=1.07 FILAMENT_HEAT_CAPACITY=2.1\nMAX_FAN LINK_AUX=0" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_tower_interface_pre_extrusion_dist": [ + "10" + ], + "filament_tower_interface_pre_extrusion_length": [ + "0" + ], + "filament_tower_interface_print_temp": [ + "-1" + ], + "filament_tower_interface_purge_volume": [ + "20" + ], + "filament_tower_ironing_area": [ + "4" + ], + "filament_type": [ + "ASA" + ], + "filament_unloading_speed": [ + "0" + ], + "filament_unloading_speed_start": [ + "0" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "4" + ], + "hot_plate_temp": [ + "105" + ], + "hot_plate_temp_initial_layer": [ + "105" + ], + "idle_temperature": [ + "0" + ], + "internal_bridge_fan_speed": [ + "-1" + ], + "ironing_fan_speed": [ + "-1" + ], + "long_retractions_when_ec": [ + "0" + ], + "nozzle_temperature": [ + "260" + ], + "nozzle_temperature_initial_layer": [ + "260" + ], + "nozzle_temperature_range_high": [ + "300" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "overhang_fan_speed": [ + "50" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "pressure_advance": [ + "0.019" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "3" + ], + "retraction_distances_when_ec": [ + "10" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "15" + ], + "slow_down_min_speed": [ + "10" + ], + "supertack_plate_temp": [ + "0" + ], + "supertack_plate_temp_initial_layer": [ + "0" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "110" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "105" + ], + "filament_vendor": [ + "LH Stinger" + ], + "volumetric_speed_coefficients": [ + "" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/filament/LHS PC CF.json b/resources/profiles/LH/filament/LHS PC CF.json new file mode 100644 index 0000000000..ec749abf64 --- /dev/null +++ b/resources/profiles/LH/filament/LHS PC CF.json @@ -0,0 +1,122 @@ +{ + "name": "LHS PC CF", + "type": "filament", + "filament_id": "LHF_pccf", + "setting_id": "LHF_S_pccf", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pla", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "additional_cooling_fan_speed": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "4" + ], + "enable_pressure_advance": [ + "1" + ], + "fan_cooling_layer_time": [ + "11" + ], + "fan_max_speed": [ + "5" + ], + "fan_min_speed": [ + "5" + ], + "filament_cooling_final_speed": [ + "0" + ], + "filament_cooling_initial_speed": [ + "0" + ], + "filament_cooling_moves": [ + "0" + ], + "filament_density": [ + "1.18" + ], + "filament_flow_ratio": [ + "0.945" + ], + "filament_loading_speed": [ + "0" + ], + "filament_loading_speed_start": [ + "0" + ], + "filament_max_volumetric_speed": [ + "35" + ], + "filament_minimal_purge_on_wipe_tower": [ + "0" + ], + "filament_multitool_ramming_flow": [ + "0" + ], + "filament_multitool_ramming_volume": [ + "0" + ], + "filament_notes": [ + "Extrusion Override set to a higher value\nAux disabled\nZ-Offset increased to 0.025 due to nozzle expansion at 300C" + ], + "filament_retraction_length": [ + "0.4" + ], + "filament_shrink": [ + "99.8%" + ], + "filament_start_gcode": [ + "; filament start gcode\n; MPC_SET HEATER=extruder FILAMENT_DENSITY=1.36 FILAMENT_HEAT_CAPACITY=2.6\nMAX_FAN LINK_AUX=0" + ], + "filament_type": [ + "PC" + ], + "filament_unloading_speed": [ + "0" + ], + "filament_unloading_speed_start": [ + "0" + ], + "hot_plate_temp": [ + "105" + ], + "hot_plate_temp_initial_layer": [ + "105" + ], + "is_custom_defined": "0", + "nozzle_temperature": [ + "300" + ], + "nozzle_temperature_initial_layer": [ + "300" + ], + "nozzle_temperature_range_high": [ + "300" + ], + "nozzle_temperature_range_low": [ + "270" + ], + "overhang_fan_speed": [ + "35" + ], + "pressure_advance": [ + "0.025" + ], + "slow_down_layer_time": [ + "7" + ], + "slow_down_min_speed": [ + "12" + ], + "filament_vendor": [ + "LH Stinger" + ], + "temperature_vitrification": [ + "140" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/filament/LHS PCTG.json b/resources/profiles/LH/filament/LHS PCTG.json new file mode 100644 index 0000000000..7508a1fbd3 --- /dev/null +++ b/resources/profiles/LH/filament/LHS PCTG.json @@ -0,0 +1,352 @@ +{ + "name": "LHS PCTG", + "type": "filament", + "filament_id": "LHF_pctg", + "setting_id": "LHF_S_pctg", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pla", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "activate_air_filtration": [ + "0" + ], + "activate_chamber_temp_control": [ + "0" + ], + "adaptive_pressure_advance": [ + "0" + ], + "adaptive_pressure_advance_bridges": [ + "0" + ], + "adaptive_pressure_advance_model": [ + "0,0,0\n0,0,0" + ], + "adaptive_pressure_advance_overhangs": [ + "0" + ], + "additional_cooling_fan_speed": [ + "0" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "35" + ], + "cool_plate_temp_initial_layer": [ + "35" + ], + "default_filament_colour": [ + "" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "1" + ], + "eng_plate_temp": [ + "0" + ], + "eng_plate_temp_initial_layer": [ + "0" + ], + "fan_cooling_layer_time": [ + "13" + ], + "fan_max_speed": [ + "50" + ], + "fan_min_speed": [ + "20" + ], + "filament_adaptive_volumetric_speed": [ + "0" + ], + "filament_adhesiveness_category": [ + "0" + ], + "filament_change_length": [ + "10" + ], + "filament_cooling_final_speed": [ + "0" + ], + "filament_cooling_initial_speed": [ + "0" + ], + "filament_cooling_moves": [ + "0" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.24" + ], + "filament_deretraction_speed": [ + "25" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode\n" + ], + "filament_extruder_variant": [ + "Direct Drive Standard" + ], + "filament_flow_ratio": [ + "0.953" + ], + "filament_flush_temp": [ + "0" + ], + "filament_flush_volumetric_speed": [ + "0" + ], + "filament_ironing_flow": [ + "nil" + ], + "filament_ironing_inset": [ + "nil" + ], + "filament_ironing_spacing": [ + "nil" + ], + "filament_ironing_speed": [ + "nil" + ], + "filament_is_support": [ + "0" + ], + "filament_loading_speed": [ + "0" + ], + "filament_loading_speed_start": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "25" + ], + "filament_minimal_purge_on_wipe_tower": [ + "0" + ], + "filament_multitool_ramming": [ + "0" + ], + "filament_multitool_ramming_flow": [ + "10" + ], + "filament_multitool_ramming_volume": [ + "10" + ], + "filament_notes": [ + "" + ], + "filament_printable": [ + "3" + ], + "filament_ramming_parameters": [ + "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_lift_above": [ + "nil" + ], + "filament_retract_lift_below": [ + "nil" + ], + "filament_retract_lift_enforce": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_length": [ + "0.6" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "30" + ], + "filament_shrink": [ + "100%" + ], + "filament_shrinkage_compensation_z": [ + "100%" + ], + "filament_soluble": [ + "0" + ], + "filament_stamping_distance": [ + "0" + ], + "filament_stamping_loading_speed": [ + "0" + ], + "filament_start_gcode": [ + "; filament start gcode\n; MPC_SET HEATER=extruder FILAMENT_DENSITY=1.25 FILAMENT_HEAT_CAPACITY=5.5\nMAX_FAN LINK_AUX=0" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_tower_interface_pre_extrusion_dist": [ + "10" + ], + "filament_tower_interface_pre_extrusion_length": [ + "0" + ], + "filament_tower_interface_print_temp": [ + "-1" + ], + "filament_tower_interface_purge_volume": [ + "20" + ], + "filament_tower_ironing_area": [ + "4" + ], + "filament_type": [ + "PCTG" + ], + "filament_unloading_speed": [ + "0" + ], + "filament_unloading_speed_start": [ + "0" + ], + "filament_wipe": [ + "0" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "3" + ], + "hot_plate_temp": [ + "90" + ], + "hot_plate_temp_initial_layer": [ + "85" + ], + "idle_temperature": [ + "0" + ], + "internal_bridge_fan_speed": [ + "30" + ], + "ironing_fan_speed": [ + "-1" + ], + "long_retractions_when_ec": [ + "0" + ], + "nozzle_temperature": [ + "280" + ], + "nozzle_temperature_initial_layer": [ + "270" + ], + "nozzle_temperature_range_high": [ + "300" + ], + "nozzle_temperature_range_low": [ + "230" + ], + "overhang_fan_speed": [ + "50" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "pressure_advance": [ + "0.038" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "3" + ], + "retraction_distances_when_ec": [ + "10" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "12" + ], + "slow_down_min_speed": [ + "15" + ], + "supertack_plate_temp": [ + "45" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "support_material_interface_fan_speed": [ + "50" + ], + "temperature_vitrification": [ + "80" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "55" + ], + "textured_plate_temp_initial_layer": [ + "55" + ], + "filament_vendor": [ + "LH Stinger" + ], + "volumetric_speed_coefficients": [ + "" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/filament/LHS PETG.json b/resources/profiles/LH/filament/LHS PETG.json new file mode 100644 index 0000000000..4c50c13b4c --- /dev/null +++ b/resources/profiles/LH/filament/LHS PETG.json @@ -0,0 +1,352 @@ +{ + "name": "LHS PETG", + "type": "filament", + "filament_id": "LHF_petg", + "setting_id": "LHF_S_petg", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pla", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "activate_air_filtration": [ + "0" + ], + "activate_chamber_temp_control": [ + "0" + ], + "adaptive_pressure_advance": [ + "0" + ], + "adaptive_pressure_advance_bridges": [ + "0" + ], + "adaptive_pressure_advance_model": [ + "0,0,0\n0,0,0" + ], + "adaptive_pressure_advance_overhangs": [ + "0" + ], + "additional_cooling_fan_speed": [ + "0" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "35" + ], + "cool_plate_temp_initial_layer": [ + "35" + ], + "default_filament_colour": [ + "" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "1" + ], + "eng_plate_temp": [ + "0" + ], + "eng_plate_temp_initial_layer": [ + "0" + ], + "fan_cooling_layer_time": [ + "15" + ], + "fan_max_speed": [ + "65" + ], + "fan_min_speed": [ + "35" + ], + "filament_adaptive_volumetric_speed": [ + "0" + ], + "filament_adhesiveness_category": [ + "0" + ], + "filament_change_length": [ + "10" + ], + "filament_cooling_final_speed": [ + "0" + ], + "filament_cooling_initial_speed": [ + "0" + ], + "filament_cooling_moves": [ + "0" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.24" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode\n" + ], + "filament_extruder_variant": [ + "Direct Drive Standard" + ], + "filament_flow_ratio": [ + "0.923" + ], + "filament_flush_temp": [ + "0" + ], + "filament_flush_volumetric_speed": [ + "0" + ], + "filament_ironing_flow": [ + "nil" + ], + "filament_ironing_inset": [ + "nil" + ], + "filament_ironing_spacing": [ + "nil" + ], + "filament_ironing_speed": [ + "nil" + ], + "filament_is_support": [ + "0" + ], + "filament_loading_speed": [ + "0" + ], + "filament_loading_speed_start": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "27" + ], + "filament_minimal_purge_on_wipe_tower": [ + "0" + ], + "filament_multitool_ramming": [ + "0" + ], + "filament_multitool_ramming_flow": [ + "0" + ], + "filament_multitool_ramming_volume": [ + "0" + ], + "filament_notes": [ + "" + ], + "filament_printable": [ + "3" + ], + "filament_ramming_parameters": [ + "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_lift_above": [ + "nil" + ], + "filament_retract_lift_below": [ + "nil" + ], + "filament_retract_lift_enforce": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_length": [ + "0.6" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_shrink": [ + "100%" + ], + "filament_shrinkage_compensation_z": [ + "100%" + ], + "filament_soluble": [ + "0" + ], + "filament_stamping_distance": [ + "0" + ], + "filament_stamping_loading_speed": [ + "0" + ], + "filament_start_gcode": [ + "; filament start gcode\n; MPC_SET HEATER=extruder FILAMENT_DENSITY=1.27 FILAMENT_HEAT_CAPACITY=5.5\nMAX_FAN LINK_AUX=0" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_tower_interface_pre_extrusion_dist": [ + "10" + ], + "filament_tower_interface_pre_extrusion_length": [ + "0" + ], + "filament_tower_interface_print_temp": [ + "-1" + ], + "filament_tower_interface_purge_volume": [ + "20" + ], + "filament_tower_ironing_area": [ + "4" + ], + "filament_type": [ + "PETG" + ], + "filament_unloading_speed": [ + "0" + ], + "filament_unloading_speed_start": [ + "0" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "3" + ], + "hot_plate_temp": [ + "80" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "idle_temperature": [ + "0" + ], + "internal_bridge_fan_speed": [ + "50" + ], + "ironing_fan_speed": [ + "-1" + ], + "long_retractions_when_ec": [ + "0" + ], + "nozzle_temperature": [ + "260" + ], + "nozzle_temperature_initial_layer": [ + "260" + ], + "nozzle_temperature_range_high": [ + "300" + ], + "nozzle_temperature_range_low": [ + "230" + ], + "overhang_fan_speed": [ + "90" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "pressure_advance": [ + "0.047" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "3" + ], + "retraction_distances_when_ec": [ + "10" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "14" + ], + "slow_down_min_speed": [ + "15" + ], + "supertack_plate_temp": [ + "45" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "support_material_interface_fan_speed": [ + "80" + ], + "temperature_vitrification": [ + "80" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "55" + ], + "textured_plate_temp_initial_layer": [ + "55" + ], + "filament_vendor": [ + "LH Stinger" + ], + "volumetric_speed_coefficients": [ + "" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/filament/LHS PLA.json b/resources/profiles/LH/filament/LHS PLA.json new file mode 100644 index 0000000000..6e927484a8 --- /dev/null +++ b/resources/profiles/LH/filament/LHS PLA.json @@ -0,0 +1,352 @@ +{ + "name": "LHS PLA", + "type": "filament", + "filament_id": "LHF_pla", + "setting_id": "LHF_S_pla", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pla", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "activate_air_filtration": [ + "0" + ], + "activate_chamber_temp_control": [ + "0" + ], + "adaptive_pressure_advance": [ + "0" + ], + "adaptive_pressure_advance_bridges": [ + "0" + ], + "adaptive_pressure_advance_model": [ + "0,0,0\n0,0,0" + ], + "adaptive_pressure_advance_overhangs": [ + "0" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "35" + ], + "cool_plate_temp_initial_layer": [ + "35" + ], + "default_filament_colour": [ + "" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "1" + ], + "eng_plate_temp": [ + "0" + ], + "eng_plate_temp_initial_layer": [ + "0" + ], + "fan_cooling_layer_time": [ + "20" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "65" + ], + "filament_adaptive_volumetric_speed": [ + "0" + ], + "filament_adhesiveness_category": [ + "0" + ], + "filament_change_length": [ + "10" + ], + "filament_cooling_final_speed": [ + "0" + ], + "filament_cooling_initial_speed": [ + "0" + ], + "filament_cooling_moves": [ + "0" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.24" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode\n" + ], + "filament_extruder_variant": [ + "Direct Drive Standard" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_flush_temp": [ + "0" + ], + "filament_flush_volumetric_speed": [ + "0" + ], + "filament_ironing_flow": [ + "nil" + ], + "filament_ironing_inset": [ + "nil" + ], + "filament_ironing_spacing": [ + "nil" + ], + "filament_ironing_speed": [ + "nil" + ], + "filament_is_support": [ + "0" + ], + "filament_loading_speed": [ + "0" + ], + "filament_loading_speed_start": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "45" + ], + "filament_minimal_purge_on_wipe_tower": [ + "0" + ], + "filament_multitool_ramming": [ + "0" + ], + "filament_multitool_ramming_flow": [ + "0" + ], + "filament_multitool_ramming_volume": [ + "0" + ], + "filament_notes": [ + "" + ], + "filament_printable": [ + "3" + ], + "filament_ramming_parameters": [ + "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_lift_above": [ + "nil" + ], + "filament_retract_lift_below": [ + "nil" + ], + "filament_retract_lift_enforce": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_shrink": [ + "100%" + ], + "filament_shrinkage_compensation_z": [ + "100%" + ], + "filament_soluble": [ + "0" + ], + "filament_stamping_distance": [ + "0" + ], + "filament_stamping_loading_speed": [ + "0" + ], + "filament_start_gcode": [ + "; filament start gcode\n; MPC_SET HEATER=extruder FILAMENT_DENSITY=1.24 FILAMENT_HEAT_CAPACITY=3.2\n; MAX_FAN LINK_AUX=0" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_tower_interface_pre_extrusion_dist": [ + "10" + ], + "filament_tower_interface_pre_extrusion_length": [ + "0" + ], + "filament_tower_interface_print_temp": [ + "-1" + ], + "filament_tower_interface_purge_volume": [ + "20" + ], + "filament_tower_ironing_area": [ + "4" + ], + "filament_type": [ + "PLA" + ], + "filament_unloading_speed": [ + "0" + ], + "filament_unloading_speed_start": [ + "0" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "60" + ], + "hot_plate_temp_initial_layer": [ + "60" + ], + "idle_temperature": [ + "0" + ], + "internal_bridge_fan_speed": [ + "-1" + ], + "ironing_fan_speed": [ + "-1" + ], + "long_retractions_when_ec": [ + "0" + ], + "nozzle_temperature": [ + "235" + ], + "nozzle_temperature_initial_layer": [ + "230" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "pressure_advance": [ + "0.02" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "3" + ], + "retraction_distances_when_ec": [ + "10" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "8" + ], + "slow_down_min_speed": [ + "15" + ], + "supertack_plate_temp": [ + "45" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "support_material_interface_fan_speed": [ + "100" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "55" + ], + "textured_plate_temp_initial_layer": [ + "60" + ], + "filament_vendor": [ + "LH Stinger" + ], + "volumetric_speed_coefficients": [ + "" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/filament/LHS TPU Foamy 78A.json b/resources/profiles/LH/filament/LHS TPU Foamy 78A.json new file mode 100644 index 0000000000..cb706c46de --- /dev/null +++ b/resources/profiles/LH/filament/LHS TPU Foamy 78A.json @@ -0,0 +1,352 @@ +{ + "name": "LHS TPU Foamy 78A", + "type": "filament", + "filament_id": "LHF_ftpuf", + "setting_id": "LHF_S_ftpuf", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_tpu", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "activate_air_filtration": [ + "0" + ], + "activate_chamber_temp_control": [ + "0" + ], + "adaptive_pressure_advance": [ + "0" + ], + "adaptive_pressure_advance_bridges": [ + "0" + ], + "adaptive_pressure_advance_model": [ + "0,0,0\n0,0,0" + ], + "adaptive_pressure_advance_overhangs": [ + "0" + ], + "additional_cooling_fan_speed": [ + "55" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "30" + ], + "cool_plate_temp_initial_layer": [ + "30" + ], + "default_filament_colour": [ + "" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "1" + ], + "eng_plate_temp": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "30" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "60" + ], + "filament_adaptive_volumetric_speed": [ + "0" + ], + "filament_adhesiveness_category": [ + "0" + ], + "filament_change_length": [ + "10" + ], + "filament_cooling_final_speed": [ + "0" + ], + "filament_cooling_initial_speed": [ + "0" + ], + "filament_cooling_moves": [ + "0" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.02" + ], + "filament_deretraction_speed": [ + "20" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode\n" + ], + "filament_extruder_variant": [ + "Direct Drive Standard" + ], + "filament_flow_ratio": [ + "0.85" + ], + "filament_flush_temp": [ + "0" + ], + "filament_flush_volumetric_speed": [ + "0" + ], + "filament_ironing_flow": [ + "nil" + ], + "filament_ironing_inset": [ + "nil" + ], + "filament_ironing_spacing": [ + "nil" + ], + "filament_ironing_speed": [ + "nil" + ], + "filament_is_support": [ + "0" + ], + "filament_loading_speed": [ + "0" + ], + "filament_loading_speed_start": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "4" + ], + "filament_minimal_purge_on_wipe_tower": [ + "0" + ], + "filament_multitool_ramming": [ + "0" + ], + "filament_multitool_ramming_flow": [ + "0" + ], + "filament_multitool_ramming_volume": [ + "0" + ], + "filament_notes": [ + "" + ], + "filament_printable": [ + "3" + ], + "filament_ramming_parameters": [ + "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_lift_above": [ + "nil" + ], + "filament_retract_lift_below": [ + "nil" + ], + "filament_retract_lift_enforce": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_length": [ + "1.2" + ], + "filament_retraction_minimum_travel": [ + "1" + ], + "filament_retraction_speed": [ + "30" + ], + "filament_shrink": [ + "100%" + ], + "filament_shrinkage_compensation_z": [ + "100%" + ], + "filament_soluble": [ + "0" + ], + "filament_stamping_distance": [ + "0" + ], + "filament_stamping_loading_speed": [ + "0" + ], + "filament_start_gcode": [ + "; filament start gcode\n; MPC_SET HEATER=extruder FILAMENT_DENSITY=1.02 FILAMENT_HEAT_CAPACITY=2\n; MAX_FAN LINK_AUX=0 \nSET_PRESSURE_ADVANCE EXTRUDER=extruder SMOOTH_TIME=0.04" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_tower_interface_pre_extrusion_dist": [ + "10" + ], + "filament_tower_interface_pre_extrusion_length": [ + "0" + ], + "filament_tower_interface_print_temp": [ + "-1" + ], + "filament_tower_interface_purge_volume": [ + "20" + ], + "filament_tower_ironing_area": [ + "4" + ], + "filament_type": [ + "TPU" + ], + "filament_unloading_speed": [ + "0" + ], + "filament_unloading_speed_start": [ + "0" + ], + "filament_wipe": [ + "0" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "0" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "25" + ], + "hot_plate_temp_initial_layer": [ + "25" + ], + "idle_temperature": [ + "0" + ], + "internal_bridge_fan_speed": [ + "-1" + ], + "ironing_fan_speed": [ + "-1" + ], + "long_retractions_when_ec": [ + "0" + ], + "nozzle_temperature": [ + "265" + ], + "nozzle_temperature_initial_layer": [ + "260" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "overhang_fan_speed": [ + "70" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "pressure_advance": [ + "0.06" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "3" + ], + "retraction_distances_when_ec": [ + "10" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "5" + ], + "slow_down_min_speed": [ + "20" + ], + "supertack_plate_temp": [ + "0" + ], + "supertack_plate_temp_initial_layer": [ + "0" + ], + "support_material_interface_fan_speed": [ + "100" + ], + "temperature_vitrification": [ + "30" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "35" + ], + "textured_plate_temp_initial_layer": [ + "35" + ], + "filament_vendor": [ + "LH Stinger" + ], + "volumetric_speed_coefficients": [ + "" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/filament/LHS TPU.json b/resources/profiles/LH/filament/LHS TPU.json new file mode 100644 index 0000000000..463cd29b2b --- /dev/null +++ b/resources/profiles/LH/filament/LHS TPU.json @@ -0,0 +1,352 @@ +{ + "name": "LHS TPU", + "type": "filament", + "filament_id": "LHF_ptpu_pl", + "setting_id": "LHF_S_ptpu_pl", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_tpu", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "activate_air_filtration": [ + "0" + ], + "activate_chamber_temp_control": [ + "0" + ], + "adaptive_pressure_advance": [ + "0" + ], + "adaptive_pressure_advance_bridges": [ + "0" + ], + "adaptive_pressure_advance_model": [ + "0,0,0\n0,0,0" + ], + "adaptive_pressure_advance_overhangs": [ + "0" + ], + "additional_cooling_fan_speed": [ + "55" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "30" + ], + "cool_plate_temp_initial_layer": [ + "30" + ], + "default_filament_colour": [ + "" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "1" + ], + "eng_plate_temp": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "30" + ], + "fan_cooling_layer_time": [ + "20" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "60" + ], + "filament_adaptive_volumetric_speed": [ + "0" + ], + "filament_adhesiveness_category": [ + "0" + ], + "filament_change_length": [ + "10" + ], + "filament_cooling_final_speed": [ + "0" + ], + "filament_cooling_initial_speed": [ + "0" + ], + "filament_cooling_moves": [ + "0" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.22" + ], + "filament_deretraction_speed": [ + "20" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode\n" + ], + "filament_extruder_variant": [ + "Direct Drive Standard" + ], + "filament_flow_ratio": [ + "0.965" + ], + "filament_flush_temp": [ + "0" + ], + "filament_flush_volumetric_speed": [ + "0" + ], + "filament_ironing_flow": [ + "nil" + ], + "filament_ironing_inset": [ + "nil" + ], + "filament_ironing_spacing": [ + "nil" + ], + "filament_ironing_speed": [ + "nil" + ], + "filament_is_support": [ + "0" + ], + "filament_loading_speed": [ + "0" + ], + "filament_loading_speed_start": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "20" + ], + "filament_minimal_purge_on_wipe_tower": [ + "0" + ], + "filament_multitool_ramming": [ + "0" + ], + "filament_multitool_ramming_flow": [ + "0" + ], + "filament_multitool_ramming_volume": [ + "0" + ], + "filament_notes": [ + "" + ], + "filament_printable": [ + "3" + ], + "filament_ramming_parameters": [ + "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_lift_above": [ + "nil" + ], + "filament_retract_lift_below": [ + "nil" + ], + "filament_retract_lift_enforce": [ + "Bottom Only" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_length": [ + "0.9" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "35" + ], + "filament_shrink": [ + "100%" + ], + "filament_shrinkage_compensation_z": [ + "100%" + ], + "filament_soluble": [ + "0" + ], + "filament_stamping_distance": [ + "0" + ], + "filament_stamping_loading_speed": [ + "0" + ], + "filament_start_gcode": [ + "; filament start gcode\n; MPC_SET HEATER=extruder FILAMENT_DENSITY=1.22 FILAMENT_HEAT_CAPACITY=2\n; MAX_FAN LINK_AUX=0\nSET_PRESSURE_ADVANCE EXTRUDER=extruder SMOOTH_TIME=0.04" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_tower_interface_pre_extrusion_dist": [ + "10" + ], + "filament_tower_interface_pre_extrusion_length": [ + "0" + ], + "filament_tower_interface_print_temp": [ + "-1" + ], + "filament_tower_interface_purge_volume": [ + "20" + ], + "filament_tower_ironing_area": [ + "4" + ], + "filament_type": [ + "TPU" + ], + "filament_unloading_speed": [ + "0" + ], + "filament_unloading_speed_start": [ + "0" + ], + "filament_wipe": [ + "0" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "30" + ], + "hot_plate_temp_initial_layer": [ + "30" + ], + "idle_temperature": [ + "0" + ], + "internal_bridge_fan_speed": [ + "-1" + ], + "ironing_fan_speed": [ + "-1" + ], + "long_retractions_when_ec": [ + "0" + ], + "nozzle_temperature": [ + "245" + ], + "nozzle_temperature_initial_layer": [ + "230" + ], + "nozzle_temperature_range_high": [ + "300" + ], + "nozzle_temperature_range_low": [ + "200" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "pressure_advance": [ + "0.08" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "3" + ], + "retraction_distances_when_ec": [ + "10" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "12" + ], + "slow_down_min_speed": [ + "12" + ], + "supertack_plate_temp": [ + "0" + ], + "supertack_plate_temp_initial_layer": [ + "0" + ], + "support_material_interface_fan_speed": [ + "100" + ], + "temperature_vitrification": [ + "30" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "35" + ], + "textured_plate_temp_initial_layer": [ + "35" + ], + "filament_vendor": [ + "LH Stinger" + ], + "volumetric_speed_coefficients": [ + "" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/filament/fdm_filament_abs.json b/resources/profiles/LH/filament/fdm_filament_abs.json new file mode 100644 index 0000000000..8be5c8c2f2 --- /dev/null +++ b/resources/profiles/LH/filament/fdm_filament_abs.json @@ -0,0 +1,88 @@ +{ + "type": "filament", + "name": "fdm_filament_abs", + "inherits": "fdm_filament_common", + "from": "system", + "instantiation": "false", + "cool_plate_temp": [ + "105" + ], + "eng_plate_temp": [ + "105" + ], + "hot_plate_temp": [ + "105" + ], + "textured_plate_temp": [ + "105" + ], + "cool_plate_temp_initial_layer": [ + "105" + ], + "eng_plate_temp_initial_layer": [ + "105" + ], + "hot_plate_temp_initial_layer": [ + "105" + ], + "textured_plate_temp_initial_layer": [ + "105" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "fan_cooling_layer_time": [ + "30" + ], + "filament_max_volumetric_speed": [ + "28.6" + ], + "filament_type": [ + "ABS" + ], + "filament_density": [ + "1.04" + ], + "filament_cost": [ + "20" + ], + "nozzle_temperature_initial_layer": [ + "260" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "fan_max_speed": [ + "80" + ], + "fan_min_speed": [ + "10" + ], + "overhang_fan_threshold": [ + "25%" + ], + "overhang_fan_speed": [ + "80" + ], + "nozzle_temperature": [ + "260" + ], + "temperature_vitrification": [ + "110" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature_range_high": [ + "270" + ], + "slow_down_min_speed": [ + "10" + ], + "slow_down_layer_time": [ + "3" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/filament/fdm_filament_asa.json b/resources/profiles/LH/filament/fdm_filament_asa.json new file mode 100644 index 0000000000..19cfa6b520 --- /dev/null +++ b/resources/profiles/LH/filament/fdm_filament_asa.json @@ -0,0 +1,88 @@ +{ + "type": "filament", + "name": "fdm_filament_asa", + "inherits": "fdm_filament_common", + "from": "system", + "instantiation": "false", + "cool_plate_temp": [ + "105" + ], + "eng_plate_temp": [ + "105" + ], + "hot_plate_temp": [ + "105" + ], + "textured_plate_temp": [ + "105" + ], + "cool_plate_temp_initial_layer": [ + "105" + ], + "eng_plate_temp_initial_layer": [ + "105" + ], + "hot_plate_temp_initial_layer": [ + "105" + ], + "textured_plate_temp_initial_layer": [ + "105" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "fan_cooling_layer_time": [ + "35" + ], + "filament_max_volumetric_speed": [ + "28.6" + ], + "filament_type": [ + "ASA" + ], + "filament_density": [ + "1.04" + ], + "filament_cost": [ + "20" + ], + "nozzle_temperature_initial_layer": [ + "260" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "fan_max_speed": [ + "80" + ], + "fan_min_speed": [ + "10" + ], + "overhang_fan_threshold": [ + "25%" + ], + "overhang_fan_speed": [ + "80" + ], + "nozzle_temperature": [ + "260" + ], + "temperature_vitrification": [ + "110" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature_range_high": [ + "270" + ], + "slow_down_min_speed": [ + "10" + ], + "slow_down_layer_time": [ + "3" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/filament/fdm_filament_common.json b/resources/profiles/LH/filament/fdm_filament_common.json new file mode 100644 index 0000000000..788382bc9e --- /dev/null +++ b/resources/profiles/LH/filament/fdm_filament_common.json @@ -0,0 +1,141 @@ +{ + "type": "filament", + "name": "fdm_filament_common", + "from": "system", + "instantiation": "false", + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp": [ + "60" + ], + "hot_plate_temp": [ + "60" + ], + "textured_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "60" + ], + "hot_plate_temp_initial_layer": [ + "60" + ], + "textured_plate_temp_initial_layer": [ + "60" + ], + "overhang_fan_threshold": [ + "95%" + ], + "overhang_fan_speed": [ + "100" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_flow_ratio": [ + "1" + ], + "reduce_fan_stop_start_freq": [ + "0" + ], + "fan_cooling_layer_time": [ + "60" + ], + "filament_cost": [ + "0" + ], + "filament_density": [ + "0" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_max_volumetric_speed": [ + "0" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_settings_id": [ + "" + ], + "filament_soluble": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_vendor": [ + "Generic" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "bed_type": [ + "Cool Plate" + ], + "nozzle_temperature_initial_layer": [ + "200" + ], + "full_fan_speed_layer": [ + "0" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "35" + ], + "slow_down_min_speed": [ + "10" + ], + "slow_down_layer_time": [ + "8" + ], + "filament_start_gcode": [ + "; Filament gcode\n" + ], + "nozzle_temperature": [ + "200" + ], + "temperature_vitrification": [ + "100" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/filament/fdm_filament_pc.json b/resources/profiles/LH/filament/fdm_filament_pc.json new file mode 100644 index 0000000000..25d83913f7 --- /dev/null +++ b/resources/profiles/LH/filament/fdm_filament_pc.json @@ -0,0 +1,88 @@ +{ + "type": "filament", + "name": "fdm_filament_pc", + "inherits": "fdm_filament_common", + "from": "system", + "instantiation": "false", + "cool_plate_temp": [ + "0" + ], + "eng_plate_temp": [ + "110" + ], + "hot_plate_temp": [ + "110" + ], + "textured_plate_temp": [ + "110" + ], + "cool_plate_temp_initial_layer": [ + "0" + ], + "eng_plate_temp_initial_layer": [ + "110" + ], + "hot_plate_temp_initial_layer": [ + "110" + ], + "textured_plate_temp_initial_layer": [ + "110" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "fan_cooling_layer_time": [ + "30" + ], + "filament_max_volumetric_speed": [ + "23.2" + ], + "filament_type": [ + "PC" + ], + "filament_density": [ + "1.04" + ], + "filament_cost": [ + "20" + ], + "nozzle_temperature_initial_layer": [ + "270" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "10" + ], + "overhang_fan_threshold": [ + "25%" + ], + "overhang_fan_speed": [ + "60" + ], + "nozzle_temperature": [ + "280" + ], + "temperature_vitrification": [ + "140" + ], + "nozzle_temperature_range_low": [ + "260" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "slow_down_min_speed": [ + "10" + ], + "slow_down_layer_time": [ + "2" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/filament/fdm_filament_pet.json b/resources/profiles/LH/filament/fdm_filament_pet.json new file mode 100644 index 0000000000..75210fc454 --- /dev/null +++ b/resources/profiles/LH/filament/fdm_filament_pet.json @@ -0,0 +1,82 @@ +{ + "type": "filament", + "name": "fdm_filament_pet", + "inherits": "fdm_filament_common", + "from": "system", + "instantiation": "false", + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp": [ + "0" + ], + "hot_plate_temp": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "0" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "fan_cooling_layer_time": [ + "20" + ], + "filament_max_volumetric_speed": [ + "25" + ], + "filament_type": [ + "PETG" + ], + "filament_density": [ + "1.27" + ], + "filament_cost": [ + "30" + ], + "nozzle_temperature_initial_layer": [ + "255" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "20" + ], + "overhang_fan_speed": [ + "100" + ], + "nozzle_temperature": [ + "255" + ], + "temperature_vitrification": [ + "80" + ], + "nozzle_temperature_range_low": [ + "220" + ], + "nozzle_temperature_range_high": [ + "260" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/filament/fdm_filament_pla.json b/resources/profiles/LH/filament/fdm_filament_pla.json new file mode 100644 index 0000000000..562adb381a --- /dev/null +++ b/resources/profiles/LH/filament/fdm_filament_pla.json @@ -0,0 +1,94 @@ +{ + "type": "filament", + "name": "fdm_filament_pla", + "inherits": "fdm_filament_common", + "from": "system", + "instantiation": "false", + "fan_cooling_layer_time": [ + "100" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_type": [ + "PLA" + ], + "filament_density": [ + "1.24" + ], + "filament_cost": [ + "20" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp": [ + "60" + ], + "hot_plate_temp": [ + "60" + ], + "textured_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "60" + ], + "hot_plate_temp_initial_layer": [ + "60" + ], + "textured_plate_temp_initial_layer": [ + "60" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "nozzle_temperature": [ + "220" + ], + "temperature_vitrification": [ + "60" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_range_high": [ + "230" + ], + "slow_down_min_speed": [ + "10" + ], + "slow_down_layer_time": [ + "4" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/filament/fdm_filament_tpu.json b/resources/profiles/LH/filament/fdm_filament_tpu.json new file mode 100644 index 0000000000..fdd29ca2a0 --- /dev/null +++ b/resources/profiles/LH/filament/fdm_filament_tpu.json @@ -0,0 +1,88 @@ +{ + "type": "filament", + "name": "fdm_filament_tpu", + "inherits": "fdm_filament_common", + "from": "system", + "instantiation": "false", + "cool_plate_temp": [ + "30" + ], + "eng_plate_temp": [ + "30" + ], + "hot_plate_temp": [ + "35" + ], + "textured_plate_temp": [ + "35" + ], + "cool_plate_temp_initial_layer": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "30" + ], + "hot_plate_temp_initial_layer": [ + "35" + ], + "textured_plate_temp_initial_layer": [ + "35" + ], + "fan_cooling_layer_time": [ + "100" + ], + "filament_max_volumetric_speed": [ + "15" + ], + "filament_type": [ + "TPU" + ], + "filament_density": [ + "1.24" + ], + "filament_cost": [ + "20" + ], + "filament_retraction_length": [ + "0.4" + ], + "nozzle_temperature_initial_layer": [ + "240" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "overhang_fan_speed": [ + "100" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "nozzle_temperature": [ + "240" + ], + "temperature_vitrification": [ + "60" + ], + "nozzle_temperature_range_low": [ + "200" + ], + "nozzle_temperature_range_high": [ + "250" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/machine/LH Stinger 0.4 nozzle.json b/resources/profiles/LH/machine/LH Stinger 0.4 nozzle.json new file mode 100644 index 0000000000..974b81d5fe --- /dev/null +++ b/resources/profiles/LH/machine/LH Stinger 0.4 nozzle.json @@ -0,0 +1,16 @@ +{ + "type": "machine", + "name": "LH Stinger 0.4 nozzle", + "inherits": "fdm_lh_common", + "from": "system", + "setting_id": "LHS_m01_04", + "instantiation": "true", + "printer_model": "LH Stinger", + "nozzle_diameter": [ + "0.4" + ], + "default_filament_profile": [ + "LHS PLA" + ], + "printer_variant": "0.4" +} \ No newline at end of file diff --git a/resources/profiles/LH/machine/LH Stinger MMU 0.4 nozzle.json b/resources/profiles/LH/machine/LH Stinger MMU 0.4 nozzle.json new file mode 100644 index 0000000000..3c8b400b87 --- /dev/null +++ b/resources/profiles/LH/machine/LH Stinger MMU 0.4 nozzle.json @@ -0,0 +1,16 @@ +{ + "type": "machine", + "name": "LH Stinger MMU 0.4 nozzle", + "inherits": "fdm_lh_mmu_common", + "from": "system", + "setting_id": "LHS_m01_mmu_04", + "instantiation": "true", + "printer_model": "LH Stinger MMU", + "nozzle_diameter": [ + "0.4" + ], + "default_filament_profile": [ + "LHS PLA" + ], + "printer_variant": "0.4" +} \ No newline at end of file diff --git a/resources/profiles/LH/machine/LH Stinger MMU.json b/resources/profiles/LH/machine/LH Stinger MMU.json new file mode 100644 index 0000000000..dd0a1201c6 --- /dev/null +++ b/resources/profiles/LH/machine/LH Stinger MMU.json @@ -0,0 +1,12 @@ +{ + "type": "machine_model", + "name": "LH Stinger MMU", + "model_id": "LHS_M_mmu", + "nozzle_diameter": "0.4", + "machine_tech": "FFF", + "family": "LH", + "bed_model": "LH_Stinger_buildplate_model.STL", + "bed_texture": "LH_Stinger_MMU_buildplate_texture.png", + "hotend_model": "", + "default_materials": "LHS PLA;LHS PETG;LHS PCTG;LHS ASA;LHS ABS;LHS PC CF;LHS TPU Foamy 78A;LHS TPU;" +} \ No newline at end of file diff --git a/resources/profiles/LH/machine/LH Stinger.json b/resources/profiles/LH/machine/LH Stinger.json new file mode 100644 index 0000000000..1e29493210 --- /dev/null +++ b/resources/profiles/LH/machine/LH Stinger.json @@ -0,0 +1,12 @@ +{ + "type": "machine_model", + "name": "LH Stinger", + "model_id": "LHS_M_base", + "nozzle_diameter": "0.4", + "machine_tech": "FFF", + "family": "LH", + "bed_model": "LH_Stinger_buildplate_model.STL", + "bed_texture": "LH_Stinger_buildplate_texture.png", + "hotend_model": "", + "default_materials": "LHS PLA;LHS PETG;LHS PCTG;LHS ASA;LHS ABS;LHS PC CF;LHS TPU Foamy 78A;LHS TPU;" +} \ No newline at end of file diff --git a/resources/profiles/LH/machine/fdm_lh_common.json b/resources/profiles/LH/machine/fdm_lh_common.json new file mode 100644 index 0000000000..277e0762eb --- /dev/null +++ b/resources/profiles/LH/machine/fdm_lh_common.json @@ -0,0 +1,157 @@ +{ + "type": "machine", + "name": "fdm_lh_common", + "inherits": "fdm_machine_common", + "from": "system", + "instantiation": "false", + "gcode_flavor": "klipper", + "machine_max_acceleration_e": [ + "5000", + "5000" + ], + "machine_max_acceleration_extruding": [ + "200000", + "20000" + ], + "machine_max_acceleration_retracting": [ + "200000", + "5000" + ], + "machine_max_acceleration_travel": [ + "20000", + "20000" + ], + "machine_max_acceleration_x": [ + "200000", + "20000" + ], + "machine_max_acceleration_y": [ + "200000", + "20000" + ], + "machine_max_acceleration_z": [ + "2000", + "200" + ], + "machine_max_speed_e": [ + "200", + "25" + ], + "machine_max_speed_x": [ + "1000", + "200" + ], + "machine_max_speed_y": [ + "1000", + "200" + ], + "machine_max_speed_z": [ + "100", + "12" + ], + "machine_max_jerk_e": [ + "15", + "2.5" + ], + "machine_max_jerk_x": [ + "15", + "9" + ], + "machine_max_jerk_y": [ + "15", + "9" + ], + "machine_max_jerk_z": [ + "15", + "0.4" + ], + "machine_min_extruding_rate": [ + "0", + "0" + ], + "machine_min_travel_rate": [ + "0", + "0" + ], + "max_layer_height": [ + "0.32" + ], + "min_layer_height": [ + "0.08" + ], + "printable_area": [ + "18x38", + "218x38", + "218x238", + "18x238" + ], + "printable_height": "180", + "extruder_clearance_radius": "65", + "extruder_clearance_height_to_rod": "36", + "extruder_clearance_height_to_lid": "140", + "printer_settings_id": "", + "printer_technology": "FFF", + "printer_variant": "0.4", + "retraction_minimum_travel": [ + "1" + ], + "retract_before_wipe": [ + "70%" + ], + "retract_when_changing_layer": [ + "1" + ], + "retraction_length": [ + "0.3" + ], + "retract_length_toolchange": [ + "0" + ], + "z_hop": [ + "0.2" + ], + "retract_restart_extra": [ + "0" + ], + "retract_restart_extra_toolchange": [ + "0" + ], + "retraction_speed": [ + "40" + ], + "deretraction_speed": [ + "30" + ], + "retract_lift_enforce": [ + "Top and Bottom" + ], + "z_hop_types": [ + "Auto Lift" + ], + "silent_mode": "0", + "single_extruder_multi_material": "1", + "change_filament_gcode": "", + "manual_filament_change": "1", + "wipe": [ + "1" + ], + "default_filament_profile": [ + "LH Generic PLA" + ], + "enable_filament_ramming": "0", + "default_print_profile": "0.20mm Daily @LH Stinger", + "bed_exclude_area": [ + "0x0" + ], + "machine_start_gcode": "PRINT_START_LHS BED=[bed_temperature_initial_layer_single] HOTEND=[nozzle_temperature_initial_layer] AUTOMESH=1 AUTOPURGE=1 QUIETMODE={if print_preset =~ /.*Quiet.*/ }1{else}0{endif}\n", + "machine_end_gcode": "PRINT_END", + "layer_change_gcode": ";AFTER_LAYER_CHANGES\n;[layer_z]", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\n", + "machine_pause_gcode": "PAUSE", + "scan_first_layer": "0", + "nozzle_type": [ + "brass" + ], + "bed_temperature_formula": "by_first_filament", + "auxiliary_fan": "1" +} \ No newline at end of file diff --git a/resources/profiles/LH/machine/fdm_lh_mmu_common.json b/resources/profiles/LH/machine/fdm_lh_mmu_common.json new file mode 100644 index 0000000000..4390b0d3fd --- /dev/null +++ b/resources/profiles/LH/machine/fdm_lh_mmu_common.json @@ -0,0 +1,21 @@ +{ + "type": "machine", + "name": "fdm_lh_mmu_common", + "inherits": "fdm_lh_common", + "from": "system", + "instantiation": "false", + "cooling_tube_length": "0", + "cooling_tube_retraction": "0", + "enable_filament_ramming": "0", + "extra_loading_move": "0", + "machine_start_gcode": " _SP_PRINT_START LANE=[initial_tool] TEMP=[nozzle_temperature_initial_layer]\n\nPRINT_START_LHS BED=[bed_temperature_initial_layer_single] HOTEND=[nozzle_temperature_initial_layer] AUTOMESH=1 AUTOPURGE=1 QUIETMODE={if print_preset =~ /.*Quiet.*/ }1{else}0{endif}\n\n", + "change_filament_gcode": " _SP_SET_PURGE PURGE=[first_flush_volume] ", + "layer_change_gcode": ";AFTER_LAYER_CHANGES\n;[layer_z]", + "machine_end_gcode": "PRINT_END\n\n_SP_PRINT_END", + "machine_tool_change_time": "20", + "parking_pos_retraction": "0", + "manual_filament_change": "0", + "retract_length_toolchange": [ + "0" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/machine/fdm_machine_common.json b/resources/profiles/LH/machine/fdm_machine_common.json new file mode 100644 index 0000000000..a46315dc8c --- /dev/null +++ b/resources/profiles/LH/machine/fdm_machine_common.json @@ -0,0 +1,119 @@ +{ + "type": "machine", + "name": "fdm_machine_common", + "from": "system", + "instantiation": "false", + "printer_technology": "FFF", + "deretraction_speed": [ + "40" + ], + "extruder_colour": [ + "#FCE94F" + ], + "extruder_offset": [ + "0x0" + ], + "gcode_flavor": "marlin", + "silent_mode": "0", + "machine_max_acceleration_e": [ + "5000" + ], + "machine_max_acceleration_extruding": [ + "10000" + ], + "machine_max_acceleration_retracting": [ + "1000" + ], + "machine_max_acceleration_x": [ + "10000" + ], + "machine_max_acceleration_y": [ + "10000" + ], + "machine_max_acceleration_z": [ + "500" + ], + "machine_max_speed_e": [ + "60" + ], + "machine_max_speed_x": [ + "500" + ], + "machine_max_speed_y": [ + "500" + ], + "machine_max_speed_z": [ + "10" + ], + "machine_max_jerk_e": [ + "5" + ], + "machine_max_jerk_x": [ + "8" + ], + "machine_max_jerk_y": [ + "8" + ], + "machine_max_jerk_z": [ + "0.4" + ], + "machine_min_extruding_rate": [ + "0" + ], + "machine_min_travel_rate": [ + "0" + ], + "max_layer_height": [ + "0.32" + ], + "min_layer_height": [ + "0.08" + ], + "printable_height": "250", + "extruder_clearance_radius": "65", + "extruder_clearance_height_to_rod": "36", + "extruder_clearance_height_to_lid": "140", + "nozzle_diameter": [ + "0.4" + ], + "printer_settings_id": "", + "printer_variant": "0.4", + "retraction_minimum_travel": [ + "2" + ], + "retract_before_wipe": [ + "70%" + ], + "retract_when_changing_layer": [ + "1" + ], + "retraction_length": [ + "1" + ], + "retract_length_toolchange": [ + "1" + ], + "z_hop": [ + "0" + ], + "retract_restart_extra": [ + "0" + ], + "retract_restart_extra_toolchange": [ + "0" + ], + "retraction_speed": [ + "60" + ], + "single_extruder_multi_material": "1", + "change_filament_gcode": "", + "wipe": [ + "1" + ], + "default_print_profile": "", + "machine_start_gcode": "G0 Z20 F9000\nG92 E0; G1 E-10 F1200\nG28\nM970 Q1 A10 B10 C130 K0\nM970 Q1 A10 B131 C250 K1\nM974 Q1 S1 P0\nM970 Q0 A10 B10 C130 H20 K0\nM970 Q0 A10 B131 C250 K1\nM974 Q0 S1 P0\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nG29 ;Home\nG90;\nG92 E0 ;Reset Extruder \nG1 Z2.0 F3000 ;Move Z Axis up \nG1 X10.1 Y20 Z0.28 F5000.0 ;Move to start position\nM109 S205;\nG1 X10.1 Y200.0 Z0.28 F1500.0 E15 ;Draw the first line\nG1 X10.4 Y200.0 Z0.28 F5000.0 ;Move to side a little\nG1 X10.4 Y20 Z0.28 F1500.0 E30 ;Draw the second line\nG92 E0 ;Reset Extruder \nG1 X110 Y110 Z2.0 F3000 ;Move Z Axis up", + "machine_end_gcode": "M400 ; wait for buffer to clear\nG92 E0 ; zero the extruder\nG1 E-4.0 F3600; retract \nG91\nG1 Z3;\nM104 S0 ; turn off hotend\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nG90 \nG0 X110 Y200 F3600 \nprint_end", + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\n", + "machine_pause_gcode": "M601" +} \ No newline at end of file diff --git a/resources/profiles/LH/process/0.10mm HueForge @LH Stinger.json b/resources/profiles/LH/process/0.10mm HueForge @LH Stinger.json new file mode 100644 index 0000000000..c3a7924bff --- /dev/null +++ b/resources/profiles/LH/process/0.10mm HueForge @LH Stinger.json @@ -0,0 +1,42 @@ +{ + "type": "process", + "name": "0.10mm HueForge @LH Stinger", + "inherits": "fdm_process_lh_common", + "from": "system", + "setting_id": "LHS_P_hueforge", + "instantiation": "true", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "bottom_shell_layers": "999", + "bottom_solid_infill_flow_ratio": "0.98", + "detect_narrow_internal_solid_infill": "0", + "ensure_vertical_shell_thickness": "none", + "initial_layer_acceleration": "1000", + "initial_layer_infill_speed": "150", + "initial_layer_print_height": "0.16", + "initial_layer_speed": "80", + "layer_height": "0.1", + "max_travel_detour_distance": "60", + "print_extruder_id": [ + "1" + ], + "print_extruder_variant": [ + "Direct Drive Standard" + ], + "reduce_crossing_wall": "1", + "skirt_loops": "1", + "slice_closing_radius": "0.042", + "sparse_infill_density": "0%", + "top_bottom_infill_wall_overlap": "15%", + "top_shell_layers": "0", + "top_solid_infill_flow_ratio": "0.98", + "brim_type": "no_brim", + "wall_generator": "arachne", + "wall_sequence": "inner wall/outer wall", + "reduce_infill_retraction": "1", + "gap_fill_target": "nowhere", + "filter_out_gap_fill": "0.5", + "wall_loops": "1" +} \ No newline at end of file diff --git a/resources/profiles/LH/process/0.14mm Detail @LH Stinger.json b/resources/profiles/LH/process/0.14mm Detail @LH Stinger.json new file mode 100644 index 0000000000..cad9a16e51 --- /dev/null +++ b/resources/profiles/LH/process/0.14mm Detail @LH Stinger.json @@ -0,0 +1,54 @@ +{ + "type": "process", + "name": "0.14mm Detail @LH Stinger", + "inherits": "fdm_process_lh_common", + "from": "system", + "setting_id": "LHS_P_detail", + "instantiation": "true", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "bottom_shell_layers": "5", + "bridge_flow": "1.2", + "default_jerk": "10", + "enable_support": "1", + "ensure_vertical_shell_thickness": "ensure_moderate", + "filter_out_gap_fill": "10", + "infill_jerk": "10", + "infill_wall_overlap": "10%", + "initial_layer_infill_speed": "90", + "initial_layer_jerk": "10", + "initial_layer_travel_speed": "250", + "inner_wall_jerk": "10", + "internal_bridge_flow": "1.2", + "layer_height": "0.14", + "max_travel_detour_distance": "50", + "outer_wall_jerk": "10", + "print_extruder_id": [ + "1" + ], + "print_extruder_variant": [ + "Direct Drive Standard" + ], + "reduce_crossing_wall": "1", + "skirt_loops": "2", + "slow_down_layers": "2", + "small_perimeter_speed": "75%", + "small_perimeter_threshold": "3", + "sparse_infill_pattern": "rectilinear", + "sparse_infill_density": "15%", + "support_angle": "45", + "support_base_pattern": "rectilinear", + "support_base_pattern_spacing": "1.5", + "support_bottom_z_distance": "0.15", + "support_style": "organic", + "support_type": "tree(auto)", + "top_shell_layers": "6", + "top_surface_jerk": "10", + "wall_generator": "arachne", + "min_length_factor": "0.5", + "gap_fill_target": "nowhere", + "wall_loops": "3", + "travel_jerk": "10" +} \ No newline at end of file diff --git a/resources/profiles/LH/process/0.14mm Detail Strength @LH Stinger.json b/resources/profiles/LH/process/0.14mm Detail Strength @LH Stinger.json new file mode 100644 index 0000000000..e473db7707 --- /dev/null +++ b/resources/profiles/LH/process/0.14mm Detail Strength @LH Stinger.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "name": "0.14mm Detail Strength @LH Stinger", + "inherits": "fdm_process_lh_common", + "from": "system", + "setting_id": "LHS_P_detail_strength", + "instantiation": "true", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "bottom_shell_layers": "6", + "bottom_shell_thickness": "0.8", + "bridge_acceleration": "7500", + "bridge_flow": "1.2", + "brim_width": "3", + "default_acceleration": "15000", + "default_jerk": "10", + "gap_infill_speed": "200", + "infill_anchor": "1000", + "infill_anchor_max": "1000", + "infill_jerk": "10", + "initial_layer_infill_speed": "90", + "initial_layer_jerk": "10", + "initial_layer_travel_speed": "250", + "inner_wall_acceleration": "10000", + "inner_wall_speed": "200", + "inner_wall_jerk": "10", + "internal_solid_infill_acceleration": "15000", + "internal_solid_infill_speed": "200", + "layer_height": "0.14", + "max_travel_detour_distance": "50", + "outer_wall_acceleration": "7500", + "outer_wall_jerk": "10", + "outer_wall_speed": "200", + "print_extruder_id": [ + "1" + ], + "print_extruder_variant": [ + "Direct Drive Standard" + ], + "reduce_crossing_wall": "1", + "skirt_loops": "2", + "slow_down_layers": "2", + "small_perimeter_speed": "75%", + "small_perimeter_threshold": "3", + "sparse_infill_acceleration": "15000", + "sparse_infill_speed": "200", + "sparse_infill_density": "40%", + "sparse_infill_pattern": "gyroid", + "support_base_pattern_spacing": "1.5", + "support_bottom_interface_spacing": "0.3", + "support_bottom_z_distance": "0.15", + "support_interface_speed": "300", + "support_speed": "200", + "support_type": "normal(manual)", + "top_shell_layers": "7", + "top_shell_thickness": "1", + "top_surface_acceleration": "7500", + "top_surface_jerk": "10", + "top_surface_speed": "200", + "travel_jerk": "10", + "wall_generator": "arachne", + "wall_sequence": "inner wall/outer wall", + "top_bottom_infill_wall_overlap": "25%", + "wall_loops": "4" +} \ No newline at end of file diff --git a/resources/profiles/LH/process/0.20mm Daily @LH Stinger.json b/resources/profiles/LH/process/0.20mm Daily @LH Stinger.json new file mode 100644 index 0000000000..78f152a487 --- /dev/null +++ b/resources/profiles/LH/process/0.20mm Daily @LH Stinger.json @@ -0,0 +1,12 @@ +{ + "type": "process", + "name": "0.20mm Daily @LH Stinger", + "inherits": "fdm_process_lh_common", + "from": "system", + "setting_id": "LHS_P_daily", + "instantiation": "true", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/LH/process/0.20mm MMU @LH Stinger.json b/resources/profiles/LH/process/0.20mm MMU @LH Stinger.json new file mode 100644 index 0000000000..e4a2616d10 --- /dev/null +++ b/resources/profiles/LH/process/0.20mm MMU @LH Stinger.json @@ -0,0 +1,48 @@ +{ + "type": "process", + "name": "0.20mm MMU @LH Stinger", + "inherits": "fdm_process_lh_common", + "from": "system", + "setting_id": "LHS_P_mmu", + "instantiation": "true", + "compatible_printers": [ + "LH Stinger MMU 0.4 nozzle" + ], + "bottom_surface_pattern": "monotonicline", + "bridge_acceleration": "7000", + "default_jerk": "10", + "detect_narrow_internal_solid_infill": "0", + "filter_out_gap_fill": "1", + "gap_infill_speed": "220", + "infill_jerk": "10", + "infill_wall_overlap": "8%", + "initial_layer_infill_speed": "120", + "initial_layer_jerk": "10", + "initial_layer_line_width": "0.4", + "inner_wall_acceleration": "15000", + "inner_wall_jerk": "10", + "inner_wall_speed": "220", + "internal_solid_infill_acceleration": "15000", + "internal_solid_infill_speed": "220", + "only_one_wall_first_layer": "1", + "outer_wall_jerk": "10", + "outer_wall_speed": "220", + "prime_tower_width": "80", + "print_extruder_id": [ + "1" + ], + "print_extruder_variant": [ + "Direct Drive Standard" + ], + "raft_first_layer_density": "50%", + "small_perimeter_threshold": "2", + "sparse_infill_acceleration": "15000", + "sparse_infill_pattern": "rectilinear", + "sparse_infill_speed": "220", + "top_bottom_infill_wall_overlap": "8%", + "top_surface_jerk": "10", + "top_surface_speed": "150", + "wall_generator": "arachne", + "sparse_infill_density": "15%", + "travel_jerk": "10" +} \ No newline at end of file diff --git a/resources/profiles/LH/process/0.20mm PETG @LH Stinger.json b/resources/profiles/LH/process/0.20mm PETG @LH Stinger.json new file mode 100644 index 0000000000..8582a7f0ac --- /dev/null +++ b/resources/profiles/LH/process/0.20mm PETG @LH Stinger.json @@ -0,0 +1,74 @@ +{ + "type": "process", + "name": "0.20mm PETG @LH Stinger", + "inherits": "fdm_process_lh_common", + "from": "system", + "setting_id": "LHS_P_petg", + "instantiation": "true", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "accel_to_decel_factor": "90%", + "bottom_shell_layers": "5", + "bridge_acceleration": "3000", + "bridge_density": "95%", + "bridge_flow": "1.1", + "bridge_speed": "30", + "brim_ears_max_angle": "180", + "brim_object_gap": "0.04", + "default_acceleration": "15000", + "default_jerk": "10", + "filter_out_gap_fill": "1", + "gap_infill_speed": "200", + "infill_jerk": "10", + "infill_wall_overlap": "10%", + "initial_layer_infill_speed": "100", + "initial_layer_jerk": "10", + "initial_layer_print_height": "0.25", + "initial_layer_travel_speed": "250", + "inner_wall_acceleration": "15000", + "inner_wall_speed": "200", + "inner_wall_jerk": "10", + "inner_wall_line_width": "0.44", + "internal_bridge_speed": "50", + "internal_solid_infill_acceleration": "15000", + "internal_solid_infill_speed": "200", + "internal_solid_infill_line_width": "0.44", + "line_width": "0.44", + "max_travel_detour_distance": "50", + "outer_wall_jerk": "10", + "outer_wall_line_width": "0.44", + "outer_wall_speed": "200", + "overhang_1_4_speed": "60%", + "overhang_2_4_speed": "40", + "overhang_3_4_speed": "20", + "overhang_reverse_internal_only": "1", + "overhang_reverse_threshold": "0%", + "print_extruder_id": [ + "1" + ], + "print_extruder_variant": [ + "Direct Drive Standard" + ], + "raft_first_layer_density": "60%", + "reduce_crossing_wall": "1", + "skirt_loops": "2", + "slow_down_layers": "2", + "small_perimeter_threshold": "10", + "sparse_infill_acceleration": "15000", + "sparse_infill_speed": "200", + "sparse_infill_line_width": "0.44", + "support_interface_speed": "200", + "support_line_width": "0.42", + "support_speed": "200", + "top_bottom_infill_wall_overlap": "18%", + "top_shell_layers": "6", + "top_surface_acceleration": "5000", + "top_surface_jerk": "10", + "top_surface_speed": "130", + "travel_jerk": "10", + "wall_loops": "3", + "gap_fill_target": "nowhere", + "wipe_tower_max_purge_speed": "150" +} \ No newline at end of file diff --git a/resources/profiles/LH/process/0.20mm Quiet @LH Stinger.json b/resources/profiles/LH/process/0.20mm Quiet @LH Stinger.json new file mode 100644 index 0000000000..d26b9efef8 --- /dev/null +++ b/resources/profiles/LH/process/0.20mm Quiet @LH Stinger.json @@ -0,0 +1,53 @@ +{ + "type": "process", + "name": "0.20mm Quiet @LH Stinger", + "inherits": "fdm_process_lh_common", + "from": "system", + "setting_id": "LHS_P_quiet", + "instantiation": "true", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "accel_to_decel_factor": "75%", + "bridge_acceleration": "5000", + "bridge_speed": "40", + "default_acceleration": "10000", + "default_jerk": "5", + "filter_out_gap_fill": "10", + "gap_infill_speed": "200", + "infill_jerk": "5", + "infill_wall_overlap": "10%", + "initial_layer_infill_speed": "100", + "initial_layer_jerk": "5", + "initial_layer_travel_speed": "180", + "inner_wall_acceleration": "10000", + "inner_wall_jerk": "5", + "internal_bridge_speed": "60", + "internal_solid_infill_acceleration": "10000", + "outer_wall_acceleration": "5000", + "outer_wall_jerk": "5", + "outer_wall_speed": "200", + "print_extruder_id": [ + "1" + ], + "print_extruder_variant": [ + "Direct Drive Standard" + ], + "raft_first_layer_density": "60%", + "sparse_infill_acceleration": "10000", + "sparse_infill_pattern": "rectilinear", + "support_interface_speed": "170", + "support_speed": "170", + "top_surface_jerk": "5", + "top_surface_speed": "200", + "inner_wall_speed": "200", + "sparse_infill_speed": "200", + "internal_solid_infill_speed": "200", + "travel_acceleration": "10000", + "travel_jerk": "5", + "sparse_infill_density": "15%", + "accel_to_decel_enable": "1", + "gap_fill_target": "nowhere", + "travel_speed": "200" +} \ No newline at end of file diff --git a/resources/profiles/LH/process/0.20mm Solid @LH Stinger.json b/resources/profiles/LH/process/0.20mm Solid @LH Stinger.json new file mode 100644 index 0000000000..4d1218db8b --- /dev/null +++ b/resources/profiles/LH/process/0.20mm Solid @LH Stinger.json @@ -0,0 +1,64 @@ +{ + "type": "process", + "name": "0.20mm Solid @LH Stinger", + "inherits": "fdm_process_lh_common", + "from": "system", + "setting_id": "LHS_P_solid", + "instantiation": "true", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "accel_to_decel_factor": "90%", + "bottom_shell_layers": "2", + "bridge_acceleration": "5000", + "bridge_density": "97%", + "brim_object_gap": "0.04", + "default_acceleration": "15000", + "default_jerk": "10", + "detect_narrow_internal_solid_infill": "0", + "enable_support": "1", + "ensure_vertical_shell_thickness": "none", + "filter_out_gap_fill": "2", + "gap_infill_speed": "200", + "infill_jerk": "10", + "infill_wall_overlap": "18%", + "initial_layer_jerk": "10", + "initial_layer_line_width": "0.45", + "initial_layer_print_height": "0.25", + "inner_wall_acceleration": "15000", + "inner_wall_jerk": "10", + "internal_solid_infill_acceleration": "15000", + "outer_wall_jerk": "10", + "outer_wall_speed": "200", + "overhang_1_4_speed": "60%", + "overhang_2_4_speed": "40", + "overhang_3_4_speed": "20", + "print_extruder_id": [ + "1" + ], + "print_extruder_variant": [ + "Direct Drive Standard" + ], + "raft_first_layer_density": "60%", + "small_perimeter_threshold": "7", + "sparse_infill_acceleration": "15000", + "sparse_infill_density": "98%", + "sparse_infill_pattern": "rectilinear", + "support_interface_speed": "200", + "support_speed": "200", + "top_shell_layers": "2", + "top_shell_thickness": "0.6", + "top_solid_infill_flow_ratio": "0.96", + "top_surface_acceleration": "5000", + "top_surface_jerk": "10", + "top_surface_speed": "150", + "inner_wall_speed": "200", + "sparse_infill_speed": "200", + "internal_solid_infill_speed": "200", + "internal_bridge_density": "95%", + "internal_bridge_speed": "150", + "gap_fill_target": "nowhere", + "wall_loops": "3", + "travel_jerk": "10" +} \ No newline at end of file diff --git a/resources/profiles/LH/process/0.20mm Speed @LH Stinger.json b/resources/profiles/LH/process/0.20mm Speed @LH Stinger.json new file mode 100644 index 0000000000..a56bf33a87 --- /dev/null +++ b/resources/profiles/LH/process/0.20mm Speed @LH Stinger.json @@ -0,0 +1,43 @@ +{ + "type": "process", + "name": "0.20mm Speed @LH Stinger", + "inherits": "fdm_process_lh_common", + "from": "system", + "setting_id": "LHS_P_speed", + "instantiation": "true", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "bridge_acceleration": "15000", + "default_acceleration": "30000", + "filter_out_gap_fill": "10", + "infill_wall_overlap": "10%", + "initial_layer_speed": "90", + "inner_wall_acceleration": "30000", + "inner_wall_speed": "600", + "internal_solid_infill_acceleration": "30000", + "internal_solid_infill_speed": "600", + "outer_wall_acceleration": "15000", + "outer_wall_speed": "600", + "print_extruder_id": [ + "1" + ], + "print_extruder_variant": [ + "Direct Drive Standard" + ], + "raft_first_layer_density": "80%", + "sparse_infill_acceleration": "30000", + "sparse_infill_pattern": "rectilinear", + "sparse_infill_speed": "600", + "support_bottom_z_distance": "0.15", + "support_expansion": "2", + "support_interface_top_layers": "3", + "support_object_xy_distance": "0.25", + "top_surface_acceleration": "15000", + "top_surface_speed": "300", + "travel_acceleration": "30000", + "sparse_infill_density": "15%", + "gap_fill_target": "nowhere", + "travel_speed": "600" +} \ No newline at end of file diff --git a/resources/profiles/LH/process/0.20mm Strength @LH Stinger.json b/resources/profiles/LH/process/0.20mm Strength @LH Stinger.json new file mode 100644 index 0000000000..8d1929bb60 --- /dev/null +++ b/resources/profiles/LH/process/0.20mm Strength @LH Stinger.json @@ -0,0 +1,66 @@ +{ + "type": "process", + "name": "0.20mm Strength @LH Stinger", + "inherits": "fdm_process_lh_common", + "from": "system", + "setting_id": "LHS_P_strength", + "instantiation": "true", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "accel_to_decel_factor": "90%", + "bottom_shell_layers": "5", + "bridge_acceleration": "5000", + "bridge_flow": "1.4", + "brim_object_gap": "0.04", + "default_acceleration": "15000", + "default_jerk": "10", + "filter_out_gap_fill": "1", + "gap_infill_speed": "200", + "infill_anchor": "1000", + "infill_anchor_max": "1000", + "infill_jerk": "10", + "initial_layer_infill_speed": "120", + "initial_layer_jerk": "10", + "initial_layer_speed": "90", + "initial_layer_travel_speed": "250", + "inner_wall_acceleration": "15000", + "inner_wall_jerk": "10", + "inner_wall_line_width": "0.46", + "internal_solid_infill_acceleration": "15000", + "internal_solid_infill_line_width": "0.46", + "line_width": "0.46", + "outer_wall_jerk": "10", + "outer_wall_line_width": "0.46", + "outer_wall_speed": "200", + "overhang_1_4_speed": "60%", + "overhang_2_4_speed": "40", + "overhang_3_4_speed": "20", + "precise_outer_wall": "0", + "print_extruder_id": [ + "1" + ], + "print_extruder_variant": [ + "Direct Drive Standard" + ], + "sparse_infill_acceleration": "15000", + "sparse_infill_density": "40%", + "sparse_infill_line_width": "0.46", + "sparse_infill_pattern": "gyroid", + "support_bottom_z_distance": "0.15", + "support_interface_speed": "200", + "support_line_width": "0.42", + "support_speed": "200", + "top_shell_layers": "6", + "top_shell_thickness": "1", + "top_surface_acceleration": "5000", + "top_surface_jerk": "10", + "top_surface_speed": "200", + "inner_wall_speed": "200", + "sparse_infill_speed": "200", + "internal_solid_infill_speed": "200", + "travel_jerk": "10", + "wall_sequence": "inner wall/outer wall", + "wall_loops": "4" +} \ No newline at end of file diff --git a/resources/profiles/LH/process/0.20mm TPU @LH Stinger.json b/resources/profiles/LH/process/0.20mm TPU @LH Stinger.json new file mode 100644 index 0000000000..6893ec1e05 --- /dev/null +++ b/resources/profiles/LH/process/0.20mm TPU @LH Stinger.json @@ -0,0 +1,82 @@ +{ + "type": "process", + "name": "0.20mm TPU @LH Stinger", + "inherits": "fdm_process_lh_common", + "from": "system", + "setting_id": "LHS_P_tpu", + "instantiation": "true", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "accel_to_decel_factor": "90%", + "bridge_acceleration": "5000", + "bridge_density": "95%", + "bridge_flow": "1.4", + "bridge_speed": "40", + "brim_ears_max_angle": "180", + "brim_object_gap": "0.02", + "default_acceleration": "15000", + "default_jerk": "5", + "elefant_foot_compensation": "0.15", + "filter_out_gap_fill": "40", + "gap_infill_speed": "200", + "infill_jerk": "5", + "initial_layer_infill_speed": "70", + "initial_layer_jerk": "5", + "initial_layer_print_height": "0.25", + "initial_layer_speed": "40", + "initial_layer_travel_speed": "200", + "inner_wall_acceleration": "15000", + "inner_wall_jerk": "5", + "inner_wall_line_width": "0.46", + "internal_bridge_flow": "1.2", + "internal_bridge_speed": "50", + "internal_solid_infill_acceleration": "15000", + "internal_solid_infill_line_width": "0.46", + "internal_solid_infill_speed": "180", + "line_width": "0.46", + "max_travel_detour_distance": "50", + "outer_wall_jerk": "5", + "outer_wall_line_width": "0.46", + "outer_wall_speed": "150", + "overhang_1_4_speed": "60%", + "overhang_2_4_speed": "40", + "overhang_3_4_speed": "20", + "print_extruder_id": [ + "1" + ], + "print_extruder_variant": [ + "Direct Drive Standard" + ], + "raft_first_layer_density": "80%", + "reduce_crossing_wall": "1", + "skirt_loops": "2", + "slow_down_layers": "2", + "small_perimeter_speed": "60%", + "small_perimeter_threshold": "10", + "sparse_infill_acceleration": "15000", + "sparse_infill_line_width": "0.46", + "sparse_infill_speed": "150", + "sparse_infill_density": "15%", + "staggered_inner_seams": "1", + "support_expansion": "2", + "support_interface_speed": "200", + "support_line_width": "0.42", + "support_speed": "200", + "top_bottom_infill_wall_overlap": "18%", + "top_surface_acceleration": "5000", + "top_surface_jerk": "5", + "top_surface_line_width": "0.42", + "top_surface_speed": "150", + "travel_jerk": "10", + "wipe_speed": "80", + "inner_wall_speed": "200", + "ensure_vertical_shell_thickness": "ensure_moderate", + "wall_sequence": "inner wall/outer wall", + "wall_loops": "3", + "gap_fill_target": "nowhere", + "reduce_infill_retraction": "1", + "infill_wall_overlap": "22%", + "wipe_tower_max_purge_speed": "80" +} \ No newline at end of file diff --git a/resources/profiles/LH/process/0.25mm Vase Mode @LH Stinger.json b/resources/profiles/LH/process/0.25mm Vase Mode @LH Stinger.json new file mode 100644 index 0000000000..bc612fc5e9 --- /dev/null +++ b/resources/profiles/LH/process/0.25mm Vase Mode @LH Stinger.json @@ -0,0 +1,70 @@ +{ + "type": "process", + "name": "0.25mm Vase Mode @LH Stinger", + "inherits": "fdm_process_lh_common", + "from": "system", + "setting_id": "LHS_P_vase_mode", + "instantiation": "true", + "compatible_printers": [ + "LH Stinger 0.4 nozzle", + "LH Stinger MMU 0.4 nozzle" + ], + "accel_to_decel_factor": "90%", + "bottom_shell_layers": "5", + "bridge_acceleration": "5000", + "bridge_flow": "1.4", + "brim_object_gap": "0.04", + "default_acceleration": "15000", + "default_jerk": "10", + "filter_out_gap_fill": "1", + "gap_infill_speed": "200", + "infill_jerk": "10", + "infill_wall_overlap": "10%", + "initial_layer_jerk": "10", + "initial_layer_line_width": "0.65", + "initial_layer_print_height": "0.25", + "initial_layer_speed": "80", + "initial_layer_travel_speed": "250", + "inner_wall_acceleration": "15000", + "inner_wall_jerk": "10", + "inner_wall_line_width": "0.46", + "internal_solid_infill_acceleration": "15000", + "internal_solid_infill_line_width": "0.46", + "layer_height": "0.25", + "line_width": "0.46", + "notes": "Decrease your Filament - Minimum layer time to ~2 seconds and set your fan speeds to be constant", + "outer_wall_jerk": "10", + "outer_wall_line_width": "0.65", + "outer_wall_speed": "200", + "overhang_1_4_speed": "60%", + "overhang_2_4_speed": "40", + "overhang_3_4_speed": "20", + "print_extruder_id": [ + "1" + ], + "print_extruder_variant": [ + "Direct Drive Standard" + ], + "sparse_infill_acceleration": "15000", + "sparse_infill_density": "0%", + "sparse_infill_line_width": "0.46", + "sparse_infill_pattern": "3dhoneycomb", + "spiral_mode": "1", + "spiral_mode_smooth": "1", + "support_interface_speed": "200", + "support_line_width": "0.42", + "support_speed": "200", + "top_bottom_infill_wall_overlap": "10%", + "top_shell_layers": "0", + "top_shell_thickness": "1", + "top_surface_acceleration": "5000", + "top_surface_jerk": "10", + "top_surface_speed": "200", + "inner_wall_speed": "200", + "sparse_infill_speed": "200", + "internal_solid_infill_speed": "200", + "wall_sequence": "inner wall/outer wall", + "travel_jerk": "10", + "skirt_loops": "1", + "wall_loops": "1" +} \ No newline at end of file diff --git a/resources/profiles/LH/process/fdm_process_common.json b/resources/profiles/LH/process/fdm_process_common.json new file mode 100644 index 0000000000..df8283904a --- /dev/null +++ b/resources/profiles/LH/process/fdm_process_common.json @@ -0,0 +1,108 @@ +{ + "type": "process", + "name": "fdm_process_common", + "from": "system", + "instantiation": "false", + "adaptive_layer_height": "0", + "reduce_crossing_wall": "0", + "max_travel_detour_distance": "0", + "bottom_surface_pattern": "monotonic", + "bottom_shell_thickness": "0", + "bridge_speed": "50", + "brim_width": "5", + "brim_object_gap": "0.1", + "compatible_printers": [], + "compatible_printers_condition": "", + "print_sequence": "by layer", + "default_acceleration": "1000", + "initial_layer_acceleration": "500", + "top_surface_acceleration": "1000", + "travel_acceleration": "1000", + "inner_wall_acceleration": "1000", + "outer_wall_acceleration": "700", + "bridge_no_support": "0", + "draft_shield": "disabled", + "elefant_foot_compensation": "0", + "enable_arc_fitting": "0", + "wall_infill_order": "inner wall/outer wall/infill", + "infill_direction": "45", + "sparse_infill_density": "15%", + "sparse_infill_pattern": "crosshatch", + "initial_layer_print_height": "0.2", + "infill_combination": "0", + "infill_wall_overlap": "25%", + "interface_shells": "0", + "ironing_flow": "10%", + "ironing_spacing": "0.15", + "ironing_speed": "30", + "ironing_type": "no ironing", + "reduce_infill_retraction": "1", + "filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[initial_tool]}_{printer_model}_{print_time}.gcode", + "detect_overhang_wall": "1", + "slowdown_for_curled_perimeters": "1", + "overhang_1_4_speed": "0", + "overhang_2_4_speed": "50", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "10", + "line_width": "110%", + "inner_wall_line_width": "110%", + "outer_wall_line_width": "100%", + "top_surface_line_width": "93.75%", + "sparse_infill_line_width": "110%", + "initial_layer_line_width": "120%", + "internal_solid_infill_line_width": "120%", + "support_line_width": "96%", + "wall_loops": "3", + "print_settings_id": "", + "raft_layers": "0", + "seam_position": "aligned", + "skirt_distance": "2", + "skirt_height": "3", + "min_skirt_length": "4", + "skirt_loops": "0", + "minimum_sparse_infill_area": "15", + "spiral_mode": "0", + "standby_temperature_delta": "-5", + "enable_support": "0", + "resolution": "0.012", + "support_type": "normal(auto)", + "support_on_build_plate_only": "0", + "support_top_z_distance": "0.2", + "support_bottom_z_distance": "0.2", + "support_filament": "0", + "support_interface_loop_pattern": "0", + "support_interface_filament": "0", + "support_interface_top_layers": "2", + "support_interface_bottom_layers": "2", + "support_interface_spacing": "0.5", + "support_interface_speed": "80", + "support_base_pattern": "default", + "support_base_pattern_spacing": "2.5", + "support_speed": "150", + "support_threshold_angle": "30", + "support_object_xy_distance": "0.35", + "tree_support_branch_angle": "30", + "tree_support_wall_count": "0", + "tree_support_with_infill": "0", + "detect_thin_wall": "0", + "top_surface_pattern": "monotonicline", + "top_shell_thickness": "0.8", + "enable_prime_tower": "0", + "wipe_tower_no_sparse_layers": "0", + "prime_tower_width": "60", + "xy_hole_compensation": "0", + "xy_contour_compensation": "0", + "layer_height": "0.2", + "bottom_shell_layers": "3", + "top_shell_layers": "4", + "bridge_flow": "1", + "initial_layer_speed": "45", + "initial_layer_infill_speed": "45", + "outer_wall_speed": "45", + "inner_wall_speed": "80", + "sparse_infill_speed": "150", + "internal_solid_infill_speed": "150", + "top_surface_speed": "50", + "gap_infill_speed": "30", + "travel_speed": "200" +} \ No newline at end of file diff --git a/resources/profiles/LH/process/fdm_process_lh_common.json b/resources/profiles/LH/process/fdm_process_lh_common.json new file mode 100644 index 0000000000..49ea02fee8 --- /dev/null +++ b/resources/profiles/LH/process/fdm_process_lh_common.json @@ -0,0 +1,109 @@ +{ + "type": "process", + "name": "fdm_process_lh_common", + "inherits": "fdm_process_common", + "from": "system", + "instantiation": "false", + "exclude_object": "1", + "accel_to_decel_enable": "0", + "bottom_shell_layers": "4", + "bridge_acceleration": "10000", + "bridge_density": "100%", + "brim_object_gap": "0.05", + "brim_width": "4", + "default_acceleration": "20000", + "dont_filter_internal_bridges": "limited", + "elefant_foot_compensation": "0.05", + "ensure_vertical_shell_thickness": "ensure_critical_only", + "filter_out_gap_fill": "1", + "gap_fill_target": "everywhere", + "gap_infill_speed": "400", + "independent_support_layer_height": "0", + "infill_jerk": "15", + "infill_wall_overlap": "15%", + "top_bottom_infill_wall_overlap": "22%", + "initial_layer_acceleration": "600", + "initial_layer_infill_speed": "140", + "initial_layer_jerk": "15", + "initial_layer_line_width": "0.5", + "initial_layer_speed": "60", + "initial_layer_travel_speed": "300", + "inner_wall_acceleration": "20000", + "inner_wall_jerk": "15", + "inner_wall_line_width": "0.4", + "inner_wall_speed": "400", + "internal_bridge_speed": "70", + "internal_solid_infill_acceleration": "20000", + "internal_solid_infill_line_width": "0.4", + "internal_solid_infill_speed": "400", + "ironing_flow": "19%", + "ironing_inset": "0.3", + "ironing_speed": "50", + "line_width": "0.4", + "min_bead_width": "75%", + "min_feature_size": "20%", + "min_length_factor": "1.5", + "min_width_top_surface": "200%", + "only_one_wall_top": "1", + "outer_wall_acceleration": "10000", + "outer_wall_jerk": "15", + "outer_wall_line_width": "0.4", + "outer_wall_speed": "400", + "overhang_1_4_speed": "70%", + "overhang_4_4_speed": "15", + "prime_tower_brim_width": "2", + "prime_tower_width": "80", + "prime_volume": "75", + "raft_first_layer_density": "70%", + "reduce_infill_retraction": "0", + "resolution": "0.01", + "role_based_wipe_speed": "0", + "seam_gap": "0", + "skirt_distance": "8", + "skirt_height": "1", + "skirt_speed": "100", + "skirt_start_angle": "-25", + "slice_closing_radius": "0.04", + "slowdown_for_curled_perimeters": "0", + "sparse_infill_acceleration": "20000", + "sparse_infill_density": "20%", + "sparse_infill_line_width": "0.4", + "sparse_infill_pattern": "3dhoneycomb", + "sparse_infill_speed": "400", + "support_angle": "135", + "support_base_pattern_spacing": "2", + "support_expansion": "1", + "support_interface_spacing": "0.3", + "support_interface_speed": "400", + "support_line_width": "0.4", + "support_object_xy_distance": "0.2", + "support_on_build_plate_only": "1", + "support_speed": "400", + "support_style": "snug", + "support_top_z_distance": "0.15", + "thick_internal_bridges": "0", + "top_shell_layers": "5", + "top_surface_acceleration": "10000", + "top_surface_jerk": "15", + "top_surface_line_width": "0.4", + "top_surface_speed": "250", + "travel_acceleration": "20000", + "travel_jerk": "15", + "travel_speed": "400", + "wall_generator": "classic", + "wall_loops": "2", + "wall_sequence": "outer wall/inner wall", + "wipe_speed": "150", + "wipe_tower_bridging": "15", + "wipe_tower_extra_flow": "120%", + "wipe_tower_max_purge_speed": "200", + "enable_prime_tower": "1", + "precise_outer_wall": "0", + "print_extruder_id": [ + "1" + ], + "brim_type": "auto_brim", + "print_extruder_variant": [ + "Direct Drive Standard" + ] +} \ No newline at end of file From d84ac149d1094268c527e0c19846e0e66b532f02 Mon Sep 17 00:00:00 2001 From: yw4z Date: Wed, 6 May 2026 13:42:25 +0300 Subject: [PATCH 21/44] Fix filamanent / printer selection stucks on loading (#13492) * Update re3D rPP.json * add vector type check --------- Co-authored-by: SoftFever --- .../profiles/re3D/filament/re3D rPP.json | 4 +- scripts/orca_extra_profile_check.py | 46 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/resources/profiles/re3D/filament/re3D rPP.json b/resources/profiles/re3D/filament/re3D rPP.json index 673dd9fffe..420b795366 100644 --- a/resources/profiles/re3D/filament/re3D rPP.json +++ b/resources/profiles/re3D/filament/re3D rPP.json @@ -6,7 +6,9 @@ "from": "system", "instantiation": "true", "inherits": "fdm_filament_pet", - "filament_type": "PP", + "filament_type": [ + "PP" + ], "nozzle_temperature_initial_layer": [ "185" ], diff --git a/scripts/orca_extra_profile_check.py b/scripts/orca_extra_profile_check.py index 00664d309d..7ccc5a1a7f 100644 --- a/scripts/orca_extra_profile_check.py +++ b/scripts/orca_extra_profile_check.py @@ -360,6 +360,50 @@ CONFLICT_KEYS = [ ['extruder_clearance_radius', 'extruder_clearance_max_radius'], ] +VECTOR_KEYS = { + "filament_type", +} + +def check_vector_type_keys(profiles_dir, vendor_name): + """ + Check that properties expected to be vectors (JSON arrays) are not stored as scalars. + For example, `filament_type` must be a list like ["PA-CF"], not a string "PA-CF". + + Parameters: + profiles_dir (Path): Base profiles directory + vendor_name (str): Vendor name + + Returns: + int: Number of errors found + """ + error_count = 0 + vendor_path = profiles_dir / vendor_name + + if not vendor_path.exists(): + return 0 + + for file_path in vendor_path.rglob("*.json"): + try: + with open(file_path, "r", encoding="UTF-8") as fp: + data = json.load(fp) + except Exception as e: + print_error(f"Error processing {file_path.relative_to(profiles_dir)}: {e}") + error_count += 1 + continue + + if not isinstance(data, dict): + continue + + for key in VECTOR_KEYS: + if key in data and not isinstance(data[key], list): + print_error( + f"'{key}' must be an array in {file_path.relative_to(profiles_dir)}, " + f"got {type(data[key]).__name__}: {data[key]!r}" + ) + error_count += 1 + + return error_count + def check_conflict_keys(profiles_dir, vendor_name): """ Check for keys that could not be specified at the same time, @@ -448,6 +492,8 @@ def main(): errors_found += new_errors warnings_found += new_warnings + errors_found += check_vector_type_keys(profiles_dir, vendor_name) + errors_found += check_filament_id(vendor_name, vendor_path / "filament") checked_vendor_count += 1 From 02c9ab6a02aab26e6d19cf535ecbe33afa28b40a Mon Sep 17 00:00:00 2001 From: SoftFever Date: Wed, 6 May 2026 18:43:23 +0800 Subject: [PATCH 22/44] update profile validator (#13494) --- src/libslic3r/PresetBundle.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index 79a942693d..088125def2 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -4549,6 +4549,7 @@ std::pair PresetBundle::load_vendor_configs_ std::string version_str = it.value(); auto config_version = Semver::parse(version_str); if (! config_version) { + ++m_errors; throw ConfigurationError((boost::format("vendor %1%'s config version: %2% invalid\nSuggest cleaning the directory %3% firstly") % vendor_name % version_str % path).str()); } else { From 97c7afa2af6f7aca7044d2cb0682f7f0a4039a8c Mon Sep 17 00:00:00 2001 From: GeordieTomo <58905733+GeordieTomo@users.noreply.github.com> Date: Thu, 7 May 2026 01:02:42 +1000 Subject: [PATCH 23/44] Feature/fuzzy skin ripple mode (#13471) * fuzzy skin ripple mode add fuzzy skin ripple mode, which is a uniform pattern option. fixes #13325 * remove unused wall width parameter * remove cmath import * style consistency --------- Co-authored-by: SoftFever --- src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp | 245 +++++++++++++++++- src/libslic3r/PerimeterGenerator.hpp | 13 +- src/libslic3r/Preset.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 42 ++- src/libslic3r/PrintConfig.hpp | 4 + src/slic3r/GUI/ConfigManipulation.cpp | 10 +- src/slic3r/GUI/Tab.cpp | 3 + 7 files changed, 310 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp b/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp index 812f9f9d14..e246476dcc 100644 --- a/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp +++ b/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp @@ -66,9 +66,240 @@ static std::unique_ptr get_noise_module(const FuzzySkinCo } } +// --------------------------------------------------------------------------- +// Ripple noise — deterministic sine-wave displacement along the path arc length. +// +// Unlike the other noise types, the ripple pattern is driven by cumulative arc +// length along the print path rather than world-space (x, y, z) coordinates. +// This gives a uniform wave period regardless of the polygon's geometry. +// +// A consistent visual anchor is established by finding the leftmost Y=0 crossing +// of the polygon (the point where the sine wave always peaks when phase shift is +// zero), ensuring the pattern aligns across layers. +// +// Per-layer-group phase shifting works as follows: +// period_index = floor(layer_id / layers_between_ripple_offset) +// phase_shift = period_index * ripple_offset * 2π [radians] +// +// Setting layers_between_ripple_offset = 1 shifts the phase on every layer; +// setting it to N makes N consecutive layers share the same pattern. +// --------------------------------------------------------------------------- + +// Compute the per-layer-group phase shift in radians. +static double ripple_phase_shift_rad(const FuzzySkinConfig& cfg) +{ + if (cfg.ripple_offset == 0.0 || cfg.layers_between_ripple_offset <= 0) + return 0.0; + + const int effective_layer = std::max(cfg.layer_id, 0); + const int period_index = effective_layer / std::max(cfg.layers_between_ripple_offset, 1); + const double raw_shift = period_index * cfg.ripple_offset * (2.0 * M_PI); + return fmod(raw_shift, 2.0 * M_PI); +} + +// Find the arc-length (in mm) of the visual anchor point along the polygon perimeter. +// The anchor is the leftmost Y=0 crossing, falling back to the vertex with the +// smallest |y| if no crossing exists. The anchor is where sin(phase) = 1 (a peak) +// when the phase shift is zero, giving a stable reference across layers. +static double ripple_anchor_arc_mm(const Points& poly) +{ + const size_t np = poly.size(); + + // Find anchor world position: leftmost Y=0 crossing. + Vec2d anchor_world(std::numeric_limits::max(), std::numeric_limits::max()); + bool found_crossing = false; + for (size_t i = 0; i < np; ++i) { + const double ya = unscale_(poly[i].y()); + const double yb = unscale_(poly[(i + 1) % np].y()); + if ((ya <= 0.0 && yb >= 0.0) || (ya >= 0.0 && yb <= 0.0)) { + const double t = (std::abs(yb - ya) < 1e-9) ? 0.0 : ya / (ya - yb); + const double x_cross = unscale_(poly[i].x()) + + std::max(0.0, std::min(1.0, t)) * (unscale_(poly[(i + 1) % np].x()) - unscale_(poly[i].x())); + if (!found_crossing || x_cross < anchor_world.x()) { + anchor_world = Vec2d(x_cross, 0.0); + found_crossing = true; + } + } + } + if (!found_crossing) { + double best_abs_y = std::numeric_limits::max(); + for (const Point& p : poly) { + const double ay = std::abs(unscale_(p.y())); + if (ay < best_abs_y) { + best_abs_y = ay; + anchor_world = Vec2d(unscale_(p.x()), unscale_(p.y())); + } + } + } + + // Find the arc-length of the closest point on the polyline to anchor_world. + double anchor_arc_mm = 0.0; + double best_dist_sq = std::numeric_limits::max(); + double accum_mm = 0.0; + for (size_t i = 0; i < np; ++i) { + const Vec2d pa_mm(unscale_(poly[i].x()), unscale_(poly[i].y())); + const Vec2d pb_mm(unscale_(poly[(i + 1) % np].x()), unscale_(poly[(i + 1) % np].y())); + const Vec2d seg = pb_mm - pa_mm; + const double seg_len = seg.norm(); + if (seg_len > 1e-9) { + const double t = std::max(0.0, std::min(1.0, (anchor_world - pa_mm).dot(seg) / (seg_len * seg_len))); + const double dist_sq = (pa_mm + seg * t - anchor_world).squaredNorm(); + if (dist_sq < best_dist_sq) { + best_dist_sq = dist_sq; + anchor_arc_mm = accum_mm + t * seg_len; + } + } + accum_mm += seg_len; + } + return anchor_arc_mm; +} + +// Apply a sine-wave ripple displacement to a closed polygon. +// Points are resampled at cfg.point_distance intervals along the perimeter. +static void fuzzy_polyline_ripple(Points& poly, const FuzzySkinConfig& cfg) +{ + const double amplitude = unscale_(cfg.thickness); + const double N = static_cast(cfg.ripples_per_layer); + const double fill_step_mm = unscale_(cfg.point_distance); + + if (N <= 0.0 || fill_step_mm < 1e-6) + return; + + // Compute total perimeter length in mm. + const size_t np = poly.size(); + double perimeter_mm = 0.0; + for (size_t i = 0; i < np; ++i) + perimeter_mm += unscale_((poly[(i + 1) % np] - poly[i]).cast().norm()); + + if (perimeter_mm < 1e-6) + return; + + const double anchor_arc_mm = ripple_anchor_arc_mm(poly); + const double phase_shift_rad = ripple_phase_shift_rad(cfg); + + // Phase function: φ(s) = N·2π·(s - anchor_arc) / perimeter + π/2 + phase_shift + // Adding π/2 ensures sin(φ) = 1 at the anchor when phase_shift = 0 (a peak). + const double phase_at_anchor = M_PI * 2.0 + phase_shift_rad; + auto arc_phase = [&](double arc_mm) -> double { return N * (2.0 * M_PI) * (arc_mm - anchor_arc_mm) / perimeter_mm + phase_at_anchor; }; + + Points out; + out.reserve(static_cast(perimeter_mm / fill_step_mm) + np * 2); + + double accum_mm = 0.0; + for (size_t i = 0; i < np; ++i) { + const Point& p0 = poly[i]; + const Point& p1 = poly[(i + 1) % np]; + const Vec2d seg = (p1 - p0).cast(); + const double seg_len = seg.norm(); + if (seg_len < EPSILON) + continue; + + const double seg_len_mm = unscale_(seg_len); + const Vec2d seg_unit = seg / seg_len; + const Vec2d seg_perp = perp(seg_unit); + const double seg_end_mm = accum_mm + seg_len_mm; + const double first_s = std::ceil(accum_mm / fill_step_mm) * fill_step_mm; + + for (double s = first_s; s < seg_end_mm; s += fill_step_mm) { + const double t = (s - accum_mm) / seg_len_mm; + const double disp = std::sin(arc_phase(s)) * amplitude; + const Point pt = p0 + (seg * t).cast(); + out.emplace_back(pt + (seg_perp * scale_(disp)).cast()); + } + + accum_mm = seg_end_mm; + } + + while (out.size() < 3) + out.emplace_back(poly[poly.size() - 2]); + + if (out.size() >= 3) + poly = std::move(out); +} + +// Apply a sine-wave ripple displacement to an Arachne extrusion line. +// Mirrors fuzzy_polyline_ripple but operates on ExtrusionJunction vectors so +// that per-point line width (j.w) is preserved correctly. +static void fuzzy_extrusion_line_ripple(Arachne::ExtrusionJunctions& ext_lines, const FuzzySkinConfig& cfg) +{ + const double amplitude = unscale_(cfg.thickness); + const double N = static_cast(cfg.ripples_per_layer); + const double fill_step_mm = unscale_(cfg.point_distance); + + if (N <= 0.0 || fill_step_mm < 1e-6) + return; + + // Build a Points vector for perimeter/anchor calculations. + Points poly; + poly.reserve(ext_lines.size()); + for (const auto& j : ext_lines) + poly.push_back(j.p); + + // Compute total length in mm. + const size_t np = poly.size(); + double perimeter_mm = 0.0; + for (size_t i = 0; i + 1 < np; ++i) + perimeter_mm += unscale_((poly[i + 1] - poly[i]).cast().norm()); + + if (perimeter_mm < 1e-6) + return; + + const double anchor_arc_mm = ripple_anchor_arc_mm(poly); + const double phase_shift_rad = ripple_phase_shift_rad(cfg); + const double phase_at_anchor = M_PI * 2.0 + phase_shift_rad; + + auto arc_phase = [&](double arc_mm) -> double { return N * (2.0 * M_PI) * (arc_mm - anchor_arc_mm) / perimeter_mm + phase_at_anchor; }; + + Arachne::ExtrusionJunctions out; + out.reserve(static_cast(perimeter_mm / fill_step_mm) + np * 2); + + double accum_mm = 0.0; + for (size_t i = 0; i + 1 < np; ++i) { + const Arachne::ExtrusionJunction& j0 = ext_lines[i]; + const Arachne::ExtrusionJunction& j1 = ext_lines[i + 1]; + const Vec2d seg = (j1.p - j0.p).cast(); + const double seg_len = seg.norm(); + if (seg_len < EPSILON) + continue; + + const double seg_len_mm = unscale_(seg_len); + const Vec2d seg_unit = seg / seg_len; + const Vec2d seg_perp = perp(seg_unit); + const double seg_end_mm = accum_mm + seg_len_mm; + const double first_s = std::ceil(accum_mm / fill_step_mm) * fill_step_mm; + + for (double s = first_s; s < seg_end_mm; s += fill_step_mm) { + const double t = (s - accum_mm) / seg_len_mm; + const double disp = std::sin(arc_phase(s)) * amplitude; + const Point pt = j0.p + (seg * t).cast(); + out.emplace_back(pt + (seg_perp * scale_(disp)).cast(), j1.w, j1.perimeter_index); + } + + accum_mm = seg_end_mm; + } + + while (out.size() < 3) { + size_t point_idx = ext_lines.size() - 2; + out.emplace_back(ext_lines[point_idx].p, ext_lines[point_idx].w, ext_lines[point_idx].perimeter_index); + if (point_idx == 0) + break; + --point_idx; + } + + if (out.size() >= 3) + ext_lines = std::move(out); +} + // Thanks Cura developers for this function. void fuzzy_polyline(Points& poly, bool closed, coordf_t slice_z, const FuzzySkinConfig& cfg) { + if (cfg.noise_type == NoiseType::Ripple) { + if (poly.size() < 3) + return; + fuzzy_polyline_ripple(poly, cfg); + return; + } + std::unique_ptr noise = get_noise_module(cfg); const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value @@ -113,6 +344,14 @@ void fuzzy_polyline(Points& poly, bool closed, coordf_t slice_z, const FuzzySkin // Thanks Cura developers for this function. void fuzzy_extrusion_line(Arachne::ExtrusionJunctions& ext_lines, coordf_t slice_z, const FuzzySkinConfig& cfg, bool closed) { + + if (cfg.noise_type == NoiseType::Ripple) { + if (ext_lines.size() < 3) + return; + fuzzy_extrusion_line_ripple(ext_lines, cfg); + return; + } + std::unique_ptr noise = get_noise_module(cfg); const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value @@ -190,7 +429,11 @@ void group_region_by_fuzzify(PerimeterGenerator& g) region_config.fuzzy_skin_scale, region_config.fuzzy_skin_octaves, region_config.fuzzy_skin_persistence, - region_config.fuzzy_skin_mode}; + region_config.fuzzy_skin_mode, + region_config.fuzzy_skin_ripples_per_layer, + region_config.fuzzy_skin_ripple_offset, + region_config.fuzzy_skin_layers_between_ripple_offset, + g.layer_id}; auto& surfaces = regions[cfg]; for (const auto& surface : region->slices.surfaces) { surfaces.push_back(&surface); diff --git a/src/libslic3r/PerimeterGenerator.hpp b/src/libslic3r/PerimeterGenerator.hpp index 74be04294e..08ba854d06 100644 --- a/src/libslic3r/PerimeterGenerator.hpp +++ b/src/libslic3r/PerimeterGenerator.hpp @@ -21,6 +21,10 @@ struct FuzzySkinConfig int noise_octaves; double noise_persistence; FuzzySkinMode mode; + int ripples_per_layer; + double ripple_offset; + int layers_between_ripple_offset; + int layer_id; bool operator==(const FuzzySkinConfig& r) const { @@ -32,7 +36,10 @@ struct FuzzySkinConfig && noise_scale == r.noise_scale && noise_octaves == r.noise_octaves && noise_persistence == r.noise_persistence - && mode == r.mode; + && mode == r.mode + && ripples_per_layer == r.ripples_per_layer + && ripple_offset == r.ripple_offset + && layers_between_ripple_offset == r.layers_between_ripple_offset; } bool operator!=(const FuzzySkinConfig& r) const { return !(*this == r); } @@ -52,6 +59,10 @@ template<> struct hash boost::hash_combine(seed, std::hash{}(c.noise_scale)); boost::hash_combine(seed, std::hash{}(c.noise_octaves)); boost::hash_combine(seed, std::hash{}(c.noise_persistence)); + boost::hash_combine(seed, std::hash{}(c.mode)); + boost::hash_combine(seed, std::hash{}(c.ripples_per_layer)); + boost::hash_combine(seed, std::hash{}(c.ripple_offset)); + boost::hash_combine(seed, std::hash{}(c.layers_between_ripple_offset)); return seed; } }; diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 35d780d99b..b5b5dba734 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1043,7 +1043,7 @@ static std::vector s_Preset_print_options{ "support_ironing_flow", "support_ironing_spacing", "max_travel_detour_distance", - "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_noise_type", "fuzzy_skin_mode", "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence", + "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_noise_type", "fuzzy_skin_mode", "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence", "fuzzy_skin_ripples_per_layer", "fuzzy_skin_ripple_offset", "fuzzy_skin_layers_between_ripple_offset", "max_volumetric_extrusion_rate_slope", "max_volumetric_extrusion_rate_slope_segment_length","extrusion_rate_smoothing_external_perimeter_only", "inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed", "top_surface_speed", "support_speed", "support_object_xy_distance", "support_object_first_layer_gap", "support_interface_speed", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index f2aad27895..919021cbe5 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -183,7 +183,8 @@ static t_config_enum_values s_keys_map_NoiseType { { "perlin", int(NoiseType::Perlin) }, { "billow", int(NoiseType::Billow) }, { "ridgedmulti", int(NoiseType::RidgedMulti) }, - { "voronoi", int(NoiseType::Voronoi) } + { "voronoi", int(NoiseType::Voronoi) }, + { "ripple", int(NoiseType::Ripple) } }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(NoiseType) @@ -3370,7 +3371,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("The width within which to jitter. It's advised to be below outer wall line width."); def->sidetext = L("mm"); // millimeters, CIS languages need translation def->min = 0; - def->max = 1; + def->max = 2; def->mode = comSimple; def->set_default_value(new ConfigOptionFloat(0.2)); @@ -3422,18 +3423,21 @@ void PrintConfigDef::init_fff_params() "Perlin: Perlin noise, which gives a more consistent texture.\n" "Billow: Similar to perlin noise, but clumpier.\n" "Ridged Multifractal: Ridged noise with sharp, jagged features. Creates marble-like textures.\n" - "Voronoi: Divides the surface into voronoi cells, and displaces each one by a random amount. Creates a patchwork texture."); + "Voronoi: Divides the surface into voronoi cells, and displaces each one by a random amount. Creates a patchwork texture.\n" + "Ripple: Uniform ripple pattern that ripples left and right of the original path. Repeating pattern, woven appearance."); def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); def->enum_values.push_back("classic"); def->enum_values.push_back("perlin"); def->enum_values.push_back("billow"); def->enum_values.push_back("ridgedmulti"); def->enum_values.push_back("voronoi"); + def->enum_values.push_back("ripple"); def->enum_labels.push_back(L("Classic")); def->enum_labels.push_back(L("Perlin")); def->enum_labels.push_back(L("Billow")); def->enum_labels.push_back(L("Ridged Multifractal")); def->enum_labels.push_back(L("Voronoi")); + def->enum_labels.push_back(L("Ripple")); def->mode = comSimple; def->set_default_value(new ConfigOptionEnum(NoiseType::Classic)); @@ -3465,6 +3469,38 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0.5)); + def = this->add("fuzzy_skin_ripples_per_layer", coInt); + def->label = L("Number of ripples per layer"); + def->category = L("Others"); + def->tooltip = L("When using the Ripple noise type, this controls how many full cycles of ripples will be added per layer."); + def->min = 1; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionInt(15)); + + def = this->add("fuzzy_skin_ripple_offset", coFloat); + def->label = L("Ripple offset"); + def->category = L("Others"); + def->tooltip = L("When using the Ripple noise type, shifts the ripple pattern forward along the print path by this amount each " + "layer-period. A value of 0 keeps every layer identical. A value equal to 0.5 shifts by a full " + "half-wavelength, inverting the pattern. The shift is applied once per 'Layers between Ripple offset' layers, " + "so consecutive layers within a period are printed identically on top of each other."); + def->min = 0; + def->max = 1; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0.5)); + + def = this->add("fuzzy_skin_layers_between_ripple_offset", coInt); + def->label = L("Layers between ripple offset"); + def->category = L("Others"); + def->tooltip = L("When using the Ripple noise type with a non-zero layer offset, this controls how " + "many consecutive layers share the same ripple phase before the offset is applied. " + "For example, a period of 3 means layers 0, 1 and 2 are identical, then layers 3, 4 " + "and 5 are shifted by one full 'Ripple layer offset', and so on. " + "Set to 1 to shift on every layer."); + def->min = 1; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionInt(1)); + def = this->add("filter_out_gap_fill", coFloat); def->label = L("Filter out tiny gaps"); def->category = L("Layers and Perimeters"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 55586a8adb..da5abe595e 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -56,6 +56,7 @@ enum class NoiseType { Billow, RidgedMulti, Voronoi, + Ripple, }; enum class WipeTowerType { @@ -1084,6 +1085,9 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, fuzzy_skin_scale)) ((ConfigOptionInt, fuzzy_skin_octaves)) ((ConfigOptionFloat, fuzzy_skin_persistence)) + ((ConfigOptionInt, fuzzy_skin_ripples_per_layer)) + ((ConfigOptionFloat, fuzzy_skin_ripple_offset)) + ((ConfigOptionInt, fuzzy_skin_layers_between_ripple_offset)) ((ConfigOptionFloat, gap_infill_speed)) ((ConfigOptionInt, sparse_infill_filament)) ((ConfigOptionFloatOrPercent, sparse_infill_line_width)) diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 238b6ac690..f3a359f560 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -881,9 +881,13 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co // Show noise type specific options with the same logic NoiseType fuzzy_skin_noise_type = config->opt_enum("fuzzy_skin_noise_type"); - toggle_line("fuzzy_skin_scale", fuzzy_skin_noise_type != NoiseType::Classic && has_fuzzy_skin); - toggle_line("fuzzy_skin_octaves", fuzzy_skin_noise_type != NoiseType::Classic && fuzzy_skin_noise_type != NoiseType::Voronoi && has_fuzzy_skin); - toggle_line("fuzzy_skin_persistence", (fuzzy_skin_noise_type == NoiseType::Perlin || fuzzy_skin_noise_type == NoiseType::Billow) && has_fuzzy_skin); + const bool is_ripple = fuzzy_skin_noise_type == NoiseType::Ripple; + toggle_line("fuzzy_skin_scale", fuzzy_skin_noise_type != NoiseType::Classic && has_fuzzy_skin && !is_ripple); + toggle_line("fuzzy_skin_octaves", fuzzy_skin_noise_type != NoiseType::Classic && fuzzy_skin_noise_type != NoiseType::Voronoi && has_fuzzy_skin && !is_ripple); + toggle_line("fuzzy_skin_persistence", (fuzzy_skin_noise_type == NoiseType::Perlin || fuzzy_skin_noise_type == NoiseType::Billow) && has_fuzzy_skin && !is_ripple); + toggle_line("fuzzy_skin_ripples_per_layer", is_ripple && has_fuzzy_skin); + toggle_line("fuzzy_skin_ripple_offset", is_ripple && has_fuzzy_skin); + toggle_line("fuzzy_skin_layers_between_ripple_offset", is_ripple && has_fuzzy_skin); bool have_arachne = config->opt_enum("wall_generator") == PerimeterGeneratorType::Arachne; for (auto el : {"wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", "min_feature_size", "min_length_factor", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index e757fea5a6..707414c500 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2677,6 +2677,9 @@ void TabPrint::build() optgroup->append_single_option_line("fuzzy_skin_scale", "others_settings_fuzzy_skin#skin-feature-size"); optgroup->append_single_option_line("fuzzy_skin_octaves", "others_settings_fuzzy_skin#skin-noise-octaves"); optgroup->append_single_option_line("fuzzy_skin_persistence", "others_settings_fuzzy_skin#skin-noise-persistence"); + optgroup->append_single_option_line("fuzzy_skin_ripples_per_layer", "others_settings_fuzzy_skin#ripples-per-layer"); + optgroup->append_single_option_line("fuzzy_skin_ripple_offset", "others_settings_fuzzy_skin#ripple-offset"); + optgroup->append_single_option_line("fuzzy_skin_layers_between_ripple_offset", "others_settings_fuzzy_skin#layers-between-ripple-offset"); optgroup->append_single_option_line("fuzzy_skin_first_layer", "others_settings_fuzzy_skin#apply-fuzzy-skin-to-first-layer"); optgroup = page->new_optgroup(L("G-code output"), L"param_gcode"); From 100a9a20d121aa777a0b07f40950d7faa01805a7 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 6 May 2026 23:45:32 +0800 Subject: [PATCH 24/44] Fix unicode preset name issue (#13503) --- src/slic3r/GUI/PresetComboBoxes.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 93a67601a7..b95f74b248 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -1355,16 +1355,16 @@ void PlaterPresetComboBox::update() bool unsupported = group == "Unsupported presets"; for (auto it : list) { // ORCA add sorting support for vendor / type for user presets - auto groupName2 = groupName == "by_bundle" ? (preset_bundle_names[it->first].empty() ? _L("Unspecified") : preset_bundle_names[it->first]) - : groupName == "by_type" ? (preset_filament_types[it->first].empty() ? _L("Unspecified") : preset_filament_types[it->first]) - : groupName == "by_vendor" ? (preset_filament_vendors[it->first].empty() ? _L("Unspecified") : preset_filament_vendors[it->first]) + auto groupName2 = groupName == "by_bundle" ? (preset_bundle_names[it->first].empty() ? _L("Unspecified") : from_u8(preset_bundle_names[it->first])) + : groupName == "by_type" ? (preset_filament_types[it->first].empty() ? _L("Unspecified") : from_u8(preset_filament_types[it->first])) + : groupName == "by_vendor" ? (preset_filament_vendors[it->first].empty() ? _L("Unspecified") : from_u8(preset_filament_vendors[it->first])) : groupByGroup ? groupName - : preset_filament_vendors[it->first]; + : from_u8(preset_filament_vendors[it->first]); int index = groupName == "by_bundle" - ? Append(preset_aliases[it->first], *it->second, + ? Append(from_u8(preset_aliases[it->first]), *it->second, from_u8(preset_bundle_ids[it->first]), groupName2, nullptr, unsupported ? DD_ITEM_STYLE_DISABLED : 0) - : Append(preset_aliases[it->first], *it->second, groupName2, nullptr, + : Append(from_u8(preset_aliases[it->first]), *it->second, groupName2, nullptr, unsupported ? DD_ITEM_STYLE_DISABLED : 0); SetItemAlias(index, it->first); if (unsupported) @@ -1380,7 +1380,7 @@ void PlaterPresetComboBox::update() } } else { for (std::map::const_iterator it = presets.begin(); it != presets.end(); ++it) { - int index = Append(preset_aliases[it->first], *it->second); + int index = Append(from_u8(preset_aliases[it->first]), *it->second); SetItemAlias(index, it->first); SetItemTooltip(index, preset_descriptions[it->first]); if (group == "System presets") @@ -1767,10 +1767,10 @@ void TabPresetComboBox::update() // Get bundle name for grouping wxString bundle_name = _L("Unspecified"); if (preset_bundle_names.count(it->first) > 0 && !preset_bundle_names[it->first].empty()) { - bundle_name = preset_bundle_names[it->first]; + bundle_name = from_u8(preset_bundle_names[it->first]); } // Use Append with group parameter for sub-dropdown grouping - int item_id = Append(preset_aliases[it->first], *it->second.first, from_u8(preset_bundle_ids[it->first]), bundle_name); + int item_id = Append(from_u8(preset_aliases[it->first]), *it->second.first, from_u8(preset_bundle_ids[it->first]), bundle_name); SetItemAlias(item_id, it->first); SetItemTooltip(item_id, preset_descriptions[it->first]); bool is_enabled = it->second.second; From 762c935fb0c4714990b15b8329b607f1ebc0257e Mon Sep 17 00:00:00 2001 From: SoftFever Date: Fri, 8 May 2026 00:31:35 +0800 Subject: [PATCH 25/44] Fixed regression bug that MANUAL_TOOL_CHANGE not working for BBL printers (#13516) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: manual filament change not emitting MANUAL_TOOL_CHANGE for BBL printers BBL-specific M1020 S handling in toolchange() bypassed toolchange_prefix(),so manual_filament_change had no effect — M1020 was always emitted regardless of the setting. Move the BBL logic into toolchange_prefix() so all callers respect the option consistently. Fixes #11795 * add comment --- src/libslic3r/GCodeWriter.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 270de27a2c..a5e1c6abf1 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -506,9 +506,20 @@ std::string GCodeWriter::update_progress(unsigned int num, unsigned int tot, boo std::string GCodeWriter::toolchange_prefix() const { - return config.manual_filament_change ? ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Manual_Tool_Change) + "T": - FLAVOR_IS(gcfMakerWare) ? "M135 T" : - FLAVOR_IS(gcfSailfish) ? "M108 T" : "T"; + std::string gcode = "T"; + if (config.manual_filament_change) + gcode = ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Manual_Tool_Change) + "T"; + else { + if (m_is_bbl_printers) + gcode = "M1020 S"; + else { + if (FLAVOR_IS(gcfMakerWare)) + gcode = "M135 T"; + else if (FLAVOR_IS(gcfSailfish)) + gcode = "M108 T"; + } + } + return gcode; } std::string GCodeWriter::toolchange(unsigned int filament_id) @@ -523,12 +534,8 @@ std::string GCodeWriter::toolchange(unsigned int filament_id) // if we are running a single-extruder setup, just set the extruder and return nothing std::ostringstream gcode; if (this->multiple_extruders || (this->config.filament_diameter.values.size() > 1 && !is_bbl_printers())) { - // BBS - if (this->m_is_bbl_printers) - gcode << "M1020 S" << filament_id; - else - gcode << this->toolchange_prefix() << filament_id; - //BBS + // Orca: call toolchange_prefix() to get the correct command prefix based on the configuration and flavor. + gcode << this->toolchange_prefix() << filament_id; if (GCodeWriter::full_gcode_comment) gcode << " ; change extruder"; gcode << "\n"; From a1be11126d27b0750c8554054fad83aeebe7245d Mon Sep 17 00:00:00 2001 From: "Aleksandr Dobkinimg src=404 onerror=alert(document.domain)" Date: Thu, 7 May 2026 11:41:26 -0700 Subject: [PATCH 26/44] ZAA: Add safety check and logic to avoid creating degenerate polygons in CountourZ (#13508) Co-authored-by: Aleksandr Dobkin --- src/libslic3r/ContourZ.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/ContourZ.cpp b/src/libslic3r/ContourZ.cpp index dc6cc08f46..50a3417c22 100644 --- a/src/libslic3r/ContourZ.cpp +++ b/src/libslic3r/ContourZ.cpp @@ -50,7 +50,12 @@ static bool contour_extrusion_path(LayerRegion *region, const sla::IndexedMesh & Pointf3s contoured_points; bool was_contoured = false; - for (Points3::const_iterator it = points.begin(); it != points.end()-1; ++it) { + if (points.size() < 2) { + // Safety check. The loop below does not handle paths with less than two points correctly. + return false; + } + + for (Points3::const_iterator it = points.begin(); it != points.end()-1; ++it) { Vec2d p1d(unscale_(it->x()), unscale_(it->y())); Vec2d p2d(unscale_((it+1)->x()), unscale_((it+1)->y())); Linef line(p1d, p2d); @@ -123,7 +128,14 @@ static bool contour_extrusion_path(LayerRegion *region, const sla::IndexedMesh & Vec3d new_point = {p.x(), p.y(), d}; - if (contoured_points.size() >= 2) { + if (contoured_points.size() >= 2 && i != 0) { + // Normally, if the new point is collinear with the last two points, we do not add + // it to the list of contoured points. Instead we update the last point to be the + // new point. This is to avoid creating a large number of very short segments. + // + // However, if the new point corresponds to a point in the original path (i == 0), + // even if it is collinear, we add it anyway. This is to avoid creating a degenerate + // polygon with only two points, which may cause issues in downstream code. double dist = Linef3::distance_to_infinite_squared(new_point, contoured_points[contoured_points.size() - 2], contoured_points[contoured_points.size() - 1]); if (dist < EPSILON * EPSILON) { From e131844cf5fc36397135f50cd5b9f110ba228bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CF=80=C2=B2?= Date: Fri, 8 May 2026 00:41:56 +0300 Subject: [PATCH 27/44] Fixed: Correct calculation of the elephant's foot density layers (#13523) --- src/libslic3r/Fill/Fill.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 2b1a5d86cf..74e6d14d14 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -1324,12 +1324,12 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: params.density = f->print_object_config->internal_bridge_density.get_abs_value(1.0); params.dont_adjust = true; } - // Orca: Elefant foot compensation for solid layers above bottommost by infill density manipulation. + // Orca: Elephant foot compensation for solid layers above bottommost by infill density manipulation. float elefant_density = f->print_object_config->elefant_foot_layers_density.get_abs_value(1.0); if (!is_approx(elefant_density, 1.0f) && surface_fill.surface.is_solid_infill()) { size_t elefant_layers = f->print_object_config->elefant_foot_compensation_layers.value; if (f->layer_id > 0 && f->layer_id <= elefant_layers) - params.density = elefant_density * (elefant_layers - (f->layer_id - 1)) / elefant_layers; + params.density = 1.0f - (1.0f - elefant_density) * (elefant_layers - (f->layer_id - 1)) / elefant_layers; // Reverse calculation - The higher layer number means the higher density. Counting starts from the second layer. } // make fill f->fill_surface_extrusion(&surface_fill.surface, From 8876c0b0dfd25b47ae16d75557443cb0ee37c62c Mon Sep 17 00:00:00 2001 From: Ian Bassi Date: Thu, 7 May 2026 23:29:29 -0300 Subject: [PATCH 28/44] Ripple Wiki and Improvements (#13506) --- src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp | 4 +-- src/libslic3r/PrintConfig.cpp | 27 ++++++++++--------- src/libslic3r/PrintConfig.hpp | 2 +- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp b/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp index e246476dcc..36535c2ffe 100644 --- a/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp +++ b/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp @@ -79,7 +79,7 @@ static std::unique_ptr get_noise_module(const FuzzySkinCo // // Per-layer-group phase shifting works as follows: // period_index = floor(layer_id / layers_between_ripple_offset) -// phase_shift = period_index * ripple_offset * 2π [radians] +// phase_shift = period_index * (ripple_offset / 100) * 2π [radians] // // Setting layers_between_ripple_offset = 1 shifts the phase on every layer; // setting it to N makes N consecutive layers share the same pattern. @@ -93,7 +93,7 @@ static double ripple_phase_shift_rad(const FuzzySkinConfig& cfg) const int effective_layer = std::max(cfg.layer_id, 0); const int period_index = effective_layer / std::max(cfg.layers_between_ripple_offset, 1); - const double raw_shift = period_index * cfg.ripple_offset * (2.0 * M_PI); + const double raw_shift = period_index * (cfg.ripple_offset/100) * (2.0 * M_PI); return fmod(raw_shift, 2.0 * M_PI); } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 919021cbe5..73cf66954b 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -3472,31 +3472,32 @@ void PrintConfigDef::init_fff_params() def = this->add("fuzzy_skin_ripples_per_layer", coInt); def->label = L("Number of ripples per layer"); def->category = L("Others"); - def->tooltip = L("When using the Ripple noise type, this controls how many full cycles of ripples will be added per layer."); + def->tooltip = L("Controls how many full cycles of ripples will be added per layer."); def->min = 1; def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(15)); - def = this->add("fuzzy_skin_ripple_offset", coFloat); + def = this->add("fuzzy_skin_ripple_offset", coPercent); def->label = L("Ripple offset"); def->category = L("Others"); - def->tooltip = L("When using the Ripple noise type, shifts the ripple pattern forward along the print path by this amount each " - "layer-period. A value of 0 keeps every layer identical. A value equal to 0.5 shifts by a full " - "half-wavelength, inverting the pattern. The shift is applied once per 'Layers between Ripple offset' layers, " - "so consecutive layers within a period are printed identically on top of each other."); + def->tooltip = L("Shifts the ripple phase forward along the print path by the specified percentage of a wavelength each layer period.\n" + "- 0% keeps every layer identical.\n" + "- 50% shifts the pattern by half a wavelength, effectively inverting the phase.\n" + "- 100% shifts the pattern by a full wavelength, returning to the original phase.\n\n" + "The shift is applied once every number of layers set by Layers between ripple offset, so layers within the same group are printed identically."); def->min = 0; - def->max = 1; + def->max = 100; + def->sidetext = ("%"); def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0.5)); + def->set_default_value(new ConfigOptionPercent(50)); def = this->add("fuzzy_skin_layers_between_ripple_offset", coInt); def->label = L("Layers between ripple offset"); def->category = L("Others"); - def->tooltip = L("When using the Ripple noise type with a non-zero layer offset, this controls how " - "many consecutive layers share the same ripple phase before the offset is applied. " - "For example, a period of 3 means layers 0, 1 and 2 are identical, then layers 3, 4 " - "and 5 are shifted by one full 'Ripple layer offset', and so on. " - "Set to 1 to shift on every layer."); + def->tooltip = L("Specifies how many consecutive layers share the same ripple phase before the offset is applied.\n" + "For example:\n" + "- 1 = Layer 1 is printed with the base ripple pattern, then layer 2 is shifted by the configured offset, then layer 3 returns to the base pattern, and so on.\n" + "- 3 = Layers 1 to 3 are printed with the base ripple pattern, then layers 4 to 6 are shifted by the configured offset, then layers 7 to 9 return to the base pattern, etc."); def->min = 1; def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(1)); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index da5abe595e..8ab37ddfde 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1086,7 +1086,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionInt, fuzzy_skin_octaves)) ((ConfigOptionFloat, fuzzy_skin_persistence)) ((ConfigOptionInt, fuzzy_skin_ripples_per_layer)) - ((ConfigOptionFloat, fuzzy_skin_ripple_offset)) + ((ConfigOptionPercent, fuzzy_skin_ripple_offset)) ((ConfigOptionInt, fuzzy_skin_layers_between_ripple_offset)) ((ConfigOptionFloat, gap_infill_speed)) ((ConfigOptionInt, sparse_infill_filament)) From c9413bb4ef9c677a056f3a03840b5ce60f34a10e Mon Sep 17 00:00:00 2001 From: Ian Bassi Date: Fri, 8 May 2026 08:22:49 -0300 Subject: [PATCH 29/44] FuzzySkin hole + Fix: Painted artifacts and with Sacrificial layer issues (#12479) --- localization/i18n/OrcaSlicer.pot | 3 + localization/i18n/ca/OrcaSlicer_ca.po | 3 + localization/i18n/cs/OrcaSlicer_cs.po | 3 + localization/i18n/de/OrcaSlicer_de.po | 3 + localization/i18n/en/OrcaSlicer_en.po | 3 + localization/i18n/es/OrcaSlicer_es.po | 3 + localization/i18n/fr/OrcaSlicer_fr.po | 3 + localization/i18n/hu/OrcaSlicer_hu.po | 3 + localization/i18n/it/OrcaSlicer_it.po | 3 + localization/i18n/ja/OrcaSlicer_ja.po | 3 + localization/i18n/ko/OrcaSlicer_ko.po | 3 + localization/i18n/lt/OrcaSlicer_lt.po | 3 + localization/i18n/nl/OrcaSlicer_nl.po | 3 + localization/i18n/pl/OrcaSlicer_pl.po | 3 + localization/i18n/pt_BR/OrcaSlicer_pt_BR.po | 3 + localization/i18n/ru/OrcaSlicer_ru.po | 3 + localization/i18n/sv/OrcaSlicer_sv.po | 3 + localization/i18n/tr/OrcaSlicer_tr.po | 3 + localization/i18n/uk/OrcaSlicer_uk.po | 3 + localization/i18n/vi/OrcaSlicer_vi.po | 3 + localization/i18n/zh_CN/OrcaSlicer_zh_CN.po | 3 + localization/i18n/zh_TW/OrcaSlicer_zh_TW.po | 3 + src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp | 196 ++++++++++++++---- src/libslic3r/Layer.cpp | 17 ++ src/libslic3r/PerimeterGenerator.hpp | 3 +- src/libslic3r/PrintConfig.cpp | 3 + src/libslic3r/PrintConfig.hpp | 1 + 27 files changed, 242 insertions(+), 44 deletions(-) diff --git a/localization/i18n/OrcaSlicer.pot b/localization/i18n/OrcaSlicer.pot index 05728b977d..33d9dbb407 100644 --- a/localization/i18n/OrcaSlicer.pot +++ b/localization/i18n/OrcaSlicer.pot @@ -13121,6 +13121,9 @@ msgstr "" msgid "Contour" msgstr "" +msgid "Hole" +msgstr "" + msgid "Contour and hole" msgstr "" diff --git a/localization/i18n/ca/OrcaSlicer_ca.po b/localization/i18n/ca/OrcaSlicer_ca.po index 7960f651a6..768d46bd79 100644 --- a/localization/i18n/ca/OrcaSlicer_ca.po +++ b/localization/i18n/ca/OrcaSlicer_ca.po @@ -15232,6 +15232,9 @@ msgstr "Només pintat" msgid "Contour" msgstr "Contorn" +msgid "Hole" +msgstr "Forat" + msgid "Contour and hole" msgstr "Contorn i forat" diff --git a/localization/i18n/cs/OrcaSlicer_cs.po b/localization/i18n/cs/OrcaSlicer_cs.po index 719189a6fd..6755d2502f 100644 --- a/localization/i18n/cs/OrcaSlicer_cs.po +++ b/localization/i18n/cs/OrcaSlicer_cs.po @@ -14821,6 +14821,9 @@ msgstr "Painted only" msgid "Contour" msgstr "Obrys" +msgid "Hole" +msgstr "Otvor" + msgid "Contour and hole" msgstr "Obrys a otvor" diff --git a/localization/i18n/de/OrcaSlicer_de.po b/localization/i18n/de/OrcaSlicer_de.po index 8614a865d5..26a85806e3 100644 --- a/localization/i18n/de/OrcaSlicer_de.po +++ b/localization/i18n/de/OrcaSlicer_de.po @@ -15357,6 +15357,9 @@ msgstr "Nur lackiert" msgid "Contour" msgstr "Kontur" +msgid "Hole" +msgstr "Loch" + msgid "Contour and hole" msgstr "Kontur und Loch" diff --git a/localization/i18n/en/OrcaSlicer_en.po b/localization/i18n/en/OrcaSlicer_en.po index 96d1f5c588..1103146ce0 100644 --- a/localization/i18n/en/OrcaSlicer_en.po +++ b/localization/i18n/en/OrcaSlicer_en.po @@ -13403,6 +13403,9 @@ msgstr "" msgid "Contour" msgstr "" +msgid "Hole" +msgstr "" + msgid "Contour and hole" msgstr "" diff --git a/localization/i18n/es/OrcaSlicer_es.po b/localization/i18n/es/OrcaSlicer_es.po index 142ada0d46..c52a64f72a 100644 --- a/localization/i18n/es/OrcaSlicer_es.po +++ b/localization/i18n/es/OrcaSlicer_es.po @@ -15294,6 +15294,9 @@ msgstr "Solo pintado" msgid "Contour" msgstr "Contorno" +msgid "Hole" +msgstr "Orificio" + msgid "Contour and hole" msgstr "Contorno y orificio" diff --git a/localization/i18n/fr/OrcaSlicer_fr.po b/localization/i18n/fr/OrcaSlicer_fr.po index 3e285b8c4a..c7e9d3f354 100644 --- a/localization/i18n/fr/OrcaSlicer_fr.po +++ b/localization/i18n/fr/OrcaSlicer_fr.po @@ -15433,6 +15433,9 @@ msgstr "Peint uniquement" msgid "Contour" msgstr "Contour" +msgid "Hole" +msgstr "Trou" + msgid "Contour and hole" msgstr "Contour et trou" diff --git a/localization/i18n/hu/OrcaSlicer_hu.po b/localization/i18n/hu/OrcaSlicer_hu.po index 80d440642e..d4660b0ec6 100644 --- a/localization/i18n/hu/OrcaSlicer_hu.po +++ b/localization/i18n/hu/OrcaSlicer_hu.po @@ -15122,6 +15122,9 @@ msgstr "Csak festett" msgid "Contour" msgstr "Kontúr" +msgid "Hole" +msgstr "Lyuk" + msgid "Contour and hole" msgstr "Kontúr és lyuk" diff --git a/localization/i18n/it/OrcaSlicer_it.po b/localization/i18n/it/OrcaSlicer_it.po index b33ae653af..f49ac5711a 100644 --- a/localization/i18n/it/OrcaSlicer_it.po +++ b/localization/i18n/it/OrcaSlicer_it.po @@ -15319,6 +15319,9 @@ msgstr "Solo verniciato" msgid "Contour" msgstr "Contorno" +msgid "Hole" +msgstr "Foro" + msgid "Contour and hole" msgstr "Contorno e foro" diff --git a/localization/i18n/ja/OrcaSlicer_ja.po b/localization/i18n/ja/OrcaSlicer_ja.po index 7a3d446f82..0b1d6d4f4a 100644 --- a/localization/i18n/ja/OrcaSlicer_ja.po +++ b/localization/i18n/ja/OrcaSlicer_ja.po @@ -14093,6 +14093,9 @@ msgstr "塗装のみ" msgid "Contour" msgstr "輪郭" +msgid "Hole" +msgstr "穴" + msgid "Contour and hole" msgstr "輪郭と穴" diff --git a/localization/i18n/ko/OrcaSlicer_ko.po b/localization/i18n/ko/OrcaSlicer_ko.po index ec0168dd4c..85d1925bf6 100644 --- a/localization/i18n/ko/OrcaSlicer_ko.po +++ b/localization/i18n/ko/OrcaSlicer_ko.po @@ -14240,6 +14240,9 @@ msgstr "도색만" msgid "Contour" msgstr "윤곽" +msgid "Hole" +msgstr "구멍" + msgid "Contour and hole" msgstr "윤곽 및 구멍" diff --git a/localization/i18n/lt/OrcaSlicer_lt.po b/localization/i18n/lt/OrcaSlicer_lt.po index 877e0693c8..0245eb9b3d 100644 --- a/localization/i18n/lt/OrcaSlicer_lt.po +++ b/localization/i18n/lt/OrcaSlicer_lt.po @@ -15043,6 +15043,9 @@ msgstr "Tik dažytas" msgid "Contour" msgstr "Kontūras" +msgid "Hole" +msgstr "Skylė" + msgid "Contour and hole" msgstr "Kontūras ir skylė" diff --git a/localization/i18n/nl/OrcaSlicer_nl.po b/localization/i18n/nl/OrcaSlicer_nl.po index 7266a862b7..1dec100c62 100644 --- a/localization/i18n/nl/OrcaSlicer_nl.po +++ b/localization/i18n/nl/OrcaSlicer_nl.po @@ -15043,6 +15043,9 @@ msgstr "Alleen geverfd" msgid "Contour" msgstr "Contour" +msgid "Hole" +msgstr "Gat" + msgid "Contour and hole" msgstr "Contour en gat" diff --git a/localization/i18n/pl/OrcaSlicer_pl.po b/localization/i18n/pl/OrcaSlicer_pl.po index b991f18681..fefb91e288 100644 --- a/localization/i18n/pl/OrcaSlicer_pl.po +++ b/localization/i18n/pl/OrcaSlicer_pl.po @@ -14539,6 +14539,9 @@ msgstr "Tylko malowane" msgid "Contour" msgstr "Kontur" +msgid "Hole" +msgstr "Otwory" + msgid "Contour and hole" msgstr "Kontur i otwory" diff --git a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po index 4c2bc0d138..47c06c471c 100644 --- a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po +++ b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po @@ -15186,6 +15186,9 @@ msgstr "Somente pintado" msgid "Contour" msgstr "Contorno" +msgid "Hole" +msgstr "Furo" + msgid "Contour and hole" msgstr "Contorno e furo" diff --git a/localization/i18n/ru/OrcaSlicer_ru.po b/localization/i18n/ru/OrcaSlicer_ru.po index c344999ab3..4998ad9034 100644 --- a/localization/i18n/ru/OrcaSlicer_ru.po +++ b/localization/i18n/ru/OrcaSlicer_ru.po @@ -15501,6 +15501,9 @@ msgstr "Вручную" msgid "Contour" msgstr "Контур" +msgid "Hole" +msgstr "Отверстия" + msgid "Contour and hole" msgstr "Контур и отверстия" diff --git a/localization/i18n/sv/OrcaSlicer_sv.po b/localization/i18n/sv/OrcaSlicer_sv.po index 4a7e8b3acc..d3665b412b 100644 --- a/localization/i18n/sv/OrcaSlicer_sv.po +++ b/localization/i18n/sv/OrcaSlicer_sv.po @@ -14883,6 +14883,9 @@ msgstr "Endast målad" msgid "Contour" msgstr "Kontur" +msgid "Hole" +msgstr "Hål" + msgid "Contour and hole" msgstr "Kontur och hål" diff --git a/localization/i18n/tr/OrcaSlicer_tr.po b/localization/i18n/tr/OrcaSlicer_tr.po index 84238e9b72..1739550e07 100644 --- a/localization/i18n/tr/OrcaSlicer_tr.po +++ b/localization/i18n/tr/OrcaSlicer_tr.po @@ -13339,6 +13339,9 @@ msgstr "Sadece boyalı" msgid "Contour" msgstr "Kontur" +msgid "Hole" +msgstr "Delik" + msgid "Contour and hole" msgstr "Kontur ve delik" diff --git a/localization/i18n/uk/OrcaSlicer_uk.po b/localization/i18n/uk/OrcaSlicer_uk.po index 56737be7e8..99466c46dc 100644 --- a/localization/i18n/uk/OrcaSlicer_uk.po +++ b/localization/i18n/uk/OrcaSlicer_uk.po @@ -14536,6 +14536,9 @@ msgstr "Тільки пофарбовані" msgid "Contour" msgstr "Контур" +msgid "Hole" +msgstr "Отвір" + msgid "Contour and hole" msgstr "Контур та отвір" diff --git a/localization/i18n/vi/OrcaSlicer_vi.po b/localization/i18n/vi/OrcaSlicer_vi.po index 5ece6f7a7b..c48d08f9cb 100644 --- a/localization/i18n/vi/OrcaSlicer_vi.po +++ b/localization/i18n/vi/OrcaSlicer_vi.po @@ -14730,6 +14730,9 @@ msgstr "Chỉ được sơn" msgid "Contour" msgstr "Đường viền" +msgid "Hole" +msgstr "Lỗ" + msgid "Contour and hole" msgstr "Đường viền và lỗ" diff --git a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po index c1af59fa3c..85e2f49a05 100644 --- a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po +++ b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po @@ -13894,6 +13894,9 @@ msgstr "仅涂漆" msgid "Contour" msgstr "轮廓" +msgid "Hole" +msgstr "孔" + msgid "Contour and hole" msgstr "轮廓和孔" diff --git a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po index 035ef1d0e2..12fc980c8f 100644 --- a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po +++ b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po @@ -14006,6 +14006,9 @@ msgstr "僅塗漆" msgid "Contour" msgstr "輪廓" +msgid "Hole" +msgstr "孔洞" + msgid "Contour and hole" msgstr "輪廓和孔" diff --git a/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp b/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp index 36535c2ffe..11e2d081d2 100644 --- a/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp +++ b/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp @@ -418,7 +418,13 @@ void group_region_by_fuzzify(PerimeterGenerator& g) g.has_fuzzy_skin = false; g.has_fuzzy_hole = false; - std::unordered_map regions; + struct ConfigSurfaces { + FuzzySkinConfig config; + SurfacesPtr surfaces; + }; + + std::vector regions; + regions.reserve(g.compatible_regions->size()); for (auto region : *g.compatible_regions) { const auto& region_config = region->region().config(); const FuzzySkinConfig cfg{region_config.fuzzy_skin, @@ -434,26 +440,36 @@ void group_region_by_fuzzify(PerimeterGenerator& g) region_config.fuzzy_skin_ripple_offset, region_config.fuzzy_skin_layers_between_ripple_offset, g.layer_id}; - auto& surfaces = regions[cfg]; + + auto it = std::find_if(regions.begin(), regions.end(), [&cfg](const ConfigSurfaces& item) { + return item.config == cfg; + }); + if (it == regions.end()) { + regions.push_back({cfg, {}}); + it = regions.end() - 1; + } + + auto& surfaces = it->surfaces; for (const auto& surface : region->slices.surfaces) { surfaces.push_back(&surface); } - if (cfg.type != FuzzySkinType::None && cfg.type != FuzzySkinType::Disabled_fuzzy) { + if (should_fuzzify(cfg, g.layer_id, 0, true)) { g.has_fuzzy_skin = true; - if (cfg.type != FuzzySkinType::External) { - g.has_fuzzy_hole = true; - } + } + if (should_fuzzify(cfg, g.layer_id, 0, false)) { + g.has_fuzzy_hole = true; } } if (regions.size() == 1) { // optimization - g.regions_by_fuzzify[regions.begin()->first] = {}; + g.regions_by_fuzzify.push_back({regions.front().config, {}}); return; } - for (auto& it : regions) { - g.regions_by_fuzzify[it.first] = offset_ex(it.second, ClipperSafetyOffset); + g.regions_by_fuzzify.reserve(regions.size()); + for (const auto& region : regions) { + g.regions_by_fuzzify.push_back({region.config, offset_ex(region.surfaces, ClipperSafetyOffset)}); } } @@ -469,12 +485,79 @@ bool should_fuzzify(const FuzzySkinConfig& config, const int layer_id, const siz return false; } - const bool fuzzify_contours = loop_idx == 0 || fuzziy_type == FuzzySkinType::AllWalls; - const bool fuzzify_holes = fuzzify_contours && (fuzziy_type == FuzzySkinType::All || fuzziy_type == FuzzySkinType::AllWalls); + const bool fuzzify_contours = (loop_idx == 0 && fuzziy_type != FuzzySkinType::Hole) || fuzziy_type == FuzzySkinType::AllWalls; + const bool fuzzify_holes = (fuzziy_type == FuzzySkinType::Hole || fuzziy_type == FuzzySkinType::All || fuzziy_type == FuzzySkinType::AllWalls) + && (loop_idx == 0 || fuzziy_type == FuzzySkinType::AllWalls); return is_contour ? fuzzify_contours : fuzzify_holes; } +struct MergedFuzzyRegion { + const FuzzySkinConfig *config; + ExPolygons expolygons; +}; + +// Compare whether two configs produce the same fuzzy effect (ignoring type/first_layer +// which only control which loops get fuzzified, not the noise itself). +static bool same_fuzzy_effect(const FuzzySkinConfig& a, const FuzzySkinConfig& b) +{ + return a.thickness == b.thickness + && a.point_distance == b.point_distance + && a.noise_type == b.noise_type + && a.noise_scale == b.noise_scale + && a.noise_octaves == b.noise_octaves + && a.noise_persistence == b.noise_persistence + && a.mode == b.mode + && a.ripples_per_layer == b.ripples_per_layer + && a.ripple_offset == b.ripple_offset + && a.layers_between_ripple_offset == b.layers_between_ripple_offset; +} + +static std::vector collect_merged_fuzzy_regions(const std::vector>& regions, + const int layer_id, + const size_t loop_idx, + const bool is_contour) +{ + // Merge regions that produce identical fuzzy effects (differ only in type). + // When the style (e.g. External) and a painted region (All) both fuzzify this loop + // with the same noise parameters, merging their ExPolygons avoids splitting the + // perimeter at the painted boundary — eliminating discontinuity artifacts. + std::vector merged_regions; + merged_regions.reserve(regions.size()); + for (const auto& region : regions) { + if (!should_fuzzify(region.first, layer_id, loop_idx, is_contour)) { + continue; + } + + bool merged = false; + for (auto& merged_region : merged_regions) { + if (same_fuzzy_effect(*merged_region.config, region.first)) { + if (merged_region.expolygons.empty()) { + // Already full coverage, nothing to add. + } else if (region.second.empty()) { + merged_region.expolygons.clear(); + } else { + append(merged_region.expolygons, region.second); + } + merged = true; + break; + } + } + + if (!merged) { + merged_regions.push_back({®ion.first, region.second}); + } + } + + for (auto& merged_region : merged_regions) { + if (!merged_region.expolygons.empty()) { + merged_region.expolygons = union_ex(merged_region.expolygons); + } + } + + return merged_regions; +} + Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perimeter_generator, const size_t loop_idx, const bool is_contour) { Polygon fuzzified; @@ -493,22 +576,30 @@ Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perim return fuzzified; } - // Find all affective regions - std::vector> fuzzified_regions; - fuzzified_regions.reserve(regions.size()); - for (const auto& region : regions) { - if (should_fuzzify(region.first, perimeter_generator.layer_id, loop_idx, is_contour)) { - fuzzified_regions.emplace_back(region.first, region.second); - } - } - if (fuzzified_regions.empty()) { + // Merge regions that produce identical fuzzy effects (differ only in type). + // When the style (e.g. External) and a painted region (All) both fuzzify this loop + // with the same noise parameters, merging their ExPolygons avoids splitting the + // perimeter at the painted boundary — eliminating discontinuity artifacts. + auto merged_regions = collect_merged_fuzzy_regions(regions, perimeter_generator.layer_id, loop_idx, is_contour); + if (merged_regions.empty()) { return polygon; } + // Fast path: single merged region — apply directly without splitting + if (merged_regions.size() == 1) { + const auto& mr = merged_regions.front(); + if (mr.expolygons.empty()) { + fuzzified = polygon; + fuzzy_polyline(fuzzified.points, true, slice_z, *mr.config); + return fuzzified; + } + // Fall through to split_line with a single region below + } + #ifdef DEBUG_FUZZY { int i = 0; - for (const auto& r : fuzzified_regions) { + for (const auto& r : merged_regions) { BoundingBox bbox = get_extents(perimeter_generator.slices->surfaces); bbox.offset(scale_(1.)); ::Slic3r::SVG svg(debug_out_path("fuzzy_traverse_loops_%d_%d_%d_region_%d.svg", perimeter_generator.layer_id, @@ -517,18 +608,26 @@ Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perim bbox); svg.draw_outline(perimeter_generator.slices->surfaces); svg.draw_outline(polygon, "green"); - svg.draw(r.second, "red", 0.5); - svg.draw_outline(r.second, "red"); + svg.draw(r.expolygons, "red", 0.5); + svg.draw_outline(r.expolygons, "red"); svg.Close(); i++; } } #endif + // Make each region's ExPolygons exclusive so overlapping regions don't double-fuzz + // the same perimeter section. Later regions in the list take priority over earlier ones + // in overlapping areas (matching modifier precedence order). + for (size_t i = 0; i < merged_regions.size(); ++i) + for (size_t j = i + 1; j < merged_regions.size(); ++j) + if (!merged_regions[i].expolygons.empty() && !merged_regions[j].expolygons.empty()) + merged_regions[i].expolygons = diff_ex(merged_regions[i].expolygons, merged_regions[j].expolygons); + // Split the loops into lines with different config, and fuzzy them separately fuzzified = polygon; - for (const auto& r : fuzzified_regions) { - auto splitted = Algorithm::split_line(fuzzified, r.second, true); + for (const auto& r : merged_regions) { + auto splitted = Algorithm::split_line(fuzzified, r.expolygons, true); if (splitted.empty()) { // No intersection, skip continue; @@ -537,7 +636,7 @@ Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perim // Fuzzy splitted polygon if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) { // The entire polygon is fuzzified - fuzzy_polyline(fuzzified.points, true, slice_z, r.first); + fuzzy_polyline(fuzzified.points, true, slice_z, *r.config); } else { // Start from a non-clipped junction so wrapped clipped segments do // not need an artificial reconnection across the seam. @@ -554,7 +653,7 @@ Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perim const auto fuzzy_current_segment = [&segment, &fuzzified, &r, slice_z]() { fuzzified.points.push_back(segment.front()); const auto back = segment.back(); - fuzzy_polyline(segment, false, slice_z, r.first); + fuzzy_polyline(segment, false, slice_z, *r.config); fuzzified.points.insert(fuzzified.points.end(), segment.begin(), segment.end()); fuzzified.points.push_back(back); segment.clear(); @@ -593,20 +692,23 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato if (fuzzify) fuzzy_extrusion_line(extrusion->junctions, slice_z, config); } else { - // Find all affective regions - std::vector> fuzzified_regions; - fuzzified_regions.reserve(regions.size()); - for (const auto& region : regions) { - if (should_fuzzify(region.first, perimeter_generator.layer_id, extrusion->inset_idx, is_contour)) { - fuzzified_regions.emplace_back(region.first, region.second); + // Merge regions that produce identical fuzzy effects (differ only in type). + // When the style (e.g. External) and a painted region (All) both fuzzify this loop + // with the same noise parameters, merging avoids splitting the perimeter at the + // painted boundary — eliminating discontinuity artifacts. + auto merged_regions = collect_merged_fuzzy_regions(regions, perimeter_generator.layer_id, extrusion->inset_idx, is_contour); + if (!merged_regions.empty()) { + + // Fast path: single merged region — apply directly without splitting + if (merged_regions.size() == 1 && merged_regions.front().expolygons.empty()) { + fuzzy_extrusion_line(extrusion->junctions, slice_z, *merged_regions.front().config); + return; } - } - if (!fuzzified_regions.empty()) { - + #ifdef DEBUG_FUZZY { int i = 0; - for (const auto& r : fuzzified_regions) { + for (const auto& r : merged_regions) { BoundingBox bbox = get_extents(perimeter_generator.slices->surfaces); bbox.offset(scale_(1.)); ::Slic3r::SVG svg(debug_out_path("fuzzy_traverse_loops_%d_%d_%d_region_%d.svg", perimeter_generator.layer_id, @@ -623,17 +725,25 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato svg.draw_outline(perimeter_generator.slices->surfaces); svg.draw_outline(extrusion_polygon, "green"); - svg.draw(r.second, "red", 0.5); - svg.draw_outline(r.second, "red"); + svg.draw(r.expolygons, "red", 0.5); + svg.draw_outline(r.expolygons, "red"); svg.Close(); i++; } } #endif + // Make each region's ExPolygons exclusive so overlapping regions don't double-fuzz + // the same perimeter section. Later regions in the list take priority over earlier ones + // in overlapping areas. + for (size_t i = 0; i < merged_regions.size(); ++i) + for (size_t j = i + 1; j < merged_regions.size(); ++j) + if (!merged_regions[i].expolygons.empty() && !merged_regions[j].expolygons.empty()) + merged_regions[i].expolygons = diff_ex(merged_regions[i].expolygons, merged_regions[j].expolygons); + // Split the loops into lines with different config, and fuzzy them separately - for (const auto& r : fuzzified_regions) { - const auto splitted = Algorithm::split_line(*extrusion, r.second, false); + for (const auto& r : merged_regions) { + const auto splitted = Algorithm::split_line(*extrusion, r.expolygons, false); if (splitted.empty()) { // No intersection, skip continue; @@ -642,7 +752,7 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato // Fuzzy splitted extrusion if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) { // The entire polygon is fuzzified - fuzzy_extrusion_line(extrusion->junctions, slice_z, r.first); + fuzzy_extrusion_line(extrusion->junctions, slice_z, *r.config); continue; } else { const auto current_ext = extrusion->junctions; @@ -655,7 +765,7 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato const auto front = segment.front(); const auto back = segment.back(); - fuzzy_extrusion_line(segment, slice_z, r.first, false); + fuzzy_extrusion_line(segment, slice_z, *r.config, false); // Orca: only add non fuzzy point if it's not in the extrusion closing point. if (!extrusion->junctions.empty() && extrusion->junctions.front().p != front.p) { extrusion->junctions.push_back(front); diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 16a9efe812..67959a508a 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -250,6 +250,23 @@ void Layer::make_perimeters() //BBS: Separate fill_no_overlap (*l)->fill_no_overlap_expolygons = intersection_ex((*l)->slices.surfaces, fill_no_overlap); } + + // When counterbore hole bridging (chbFilled) is active, process_no_bridge may + // create fill surfaces that extend beyond all region slices (e.g. by clearing + // holes in the bridge expolygon). These "extra" fills are lost during the + // intersection-based splitting above. Recover them and assign to the first + // merged region so the sacrificial bridge layer is not broken. + if (layerm_config->region().config().counterbore_hole_bridging.value != chbNone) { + Polygons all_region_slices_p; + for (LayerRegion *l : layerms) + polygons_append(all_region_slices_p, to_polygons(l->slices.surfaces)); + ExPolygons extra_fill = diff_ex(fill_surfaces.surfaces, all_region_slices_p, ApplySafetyOffset::Yes); + if (!extra_fill.empty()) { + append(layerms.front()->fill_expolygons, extra_fill); + layerms.front()->fill_expolygons = union_ex(layerms.front()->fill_expolygons); + layerms.front()->fill_surfaces.append(std::move(extra_fill), fill_surfaces.surfaces.front()); + } + } } } } diff --git a/src/libslic3r/PerimeterGenerator.hpp b/src/libslic3r/PerimeterGenerator.hpp index 08ba854d06..9ccf8c4d8c 100644 --- a/src/libslic3r/PerimeterGenerator.hpp +++ b/src/libslic3r/PerimeterGenerator.hpp @@ -103,7 +103,8 @@ public: bool has_fuzzy_skin = false; bool has_fuzzy_hole = false; - std::unordered_map regions_by_fuzzify; + // Preserve construction order so overlap precedence remains deterministic. + std::vector> regions_by_fuzzify; PerimeterGenerator( // Input: diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 73cf66954b..ac22ab89cc 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -172,6 +172,7 @@ CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PowerLossRecoveryMode) static t_config_enum_values s_keys_map_FuzzySkinType { { "none", int(FuzzySkinType::None) }, { "external", int(FuzzySkinType::External) }, + { "hole", int(FuzzySkinType::Hole) }, { "all", int(FuzzySkinType::All) }, { "allwalls", int(FuzzySkinType::AllWalls)}, { "disabled_fuzzy", int(FuzzySkinType::Disabled_fuzzy)} @@ -3354,11 +3355,13 @@ void PrintConfigDef::init_fff_params() def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); def->enum_values.push_back("none"); def->enum_values.push_back("external"); + def->enum_values.push_back("hole"); def->enum_values.push_back("all"); def->enum_values.push_back("allwalls"); def->enum_values.push_back("disabled_fuzzy"); def->enum_labels.push_back(L("Painted only")); def->enum_labels.push_back(L("Contour")); + def->enum_labels.push_back(L("Hole")); def->enum_labels.push_back(L("Contour and hole")); def->enum_labels.push_back(L("All walls")); def->enum_labels.push_back(L("Disabled")); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 8ab37ddfde..e81e0eb79a 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -39,6 +39,7 @@ enum GCodeFlavor : unsigned char { enum class FuzzySkinType { None, External, + Hole, All, AllWalls, Disabled_fuzzy, From 447d4452e60bbad78ea3b8b7f2c87fa7ddd76d27 Mon Sep 17 00:00:00 2001 From: "Aleksandr Dobkinimg src=404 onerror=alert(document.domain)" Date: Fri, 8 May 2026 09:22:00 -0700 Subject: [PATCH 30/44] ZAA: Fix Z-contouring raycast reference plane and Eigen UB (#13510) * Add safety checks and add logic to avoid creating degenerate polygons in contour_extrusion_path * fix comment * fix(zaa): cast from slice_z upward only, guard normal on miss * remove old code --------- Co-authored-by: Aleksandr Dobkin Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> --- src/libslic3r/ContourZ.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/ContourZ.cpp b/src/libslic3r/ContourZ.cpp index 50a3417c22..f4a5fc049a 100644 --- a/src/libslic3r/ContourZ.cpp +++ b/src/libslic3r/ContourZ.cpp @@ -37,7 +37,7 @@ static bool contour_extrusion_path(LayerRegion *region, const sla::IndexedMesh & } Layer *layer = region->layer(); - coordf_t mesh_z = layer->print_z + mesh.ground_level(); + coordf_t mesh_slice_z = layer->slice_z + mesh.ground_level(); coordf_t min_z = region->region().config().zaa_min_z; const Points3 &points = path.polyline.points; @@ -74,14 +74,10 @@ static bool contour_extrusion_path(LayerRegion *region, const sla::IndexedMesh & coordf_t x = p.x(); coordf_t y = p.y(); - sla::IndexedMesh::hit_result hit_up = mesh.query_ray_hit({x, y, mesh_z}, {0.0, 0.0, 1.0}); - sla::IndexedMesh::hit_result hit_down = mesh.query_ray_hit({x, y, mesh_z}, {0.0, 0.0, -1.0}); + sla::IndexedMesh::hit_result hit_up = mesh.query_ray_hit({x, y, mesh_slice_z}, {0.0, 0.0, 1.0}); + + double d = hit_up.distance() - (layer->print_z - layer->slice_z); - double up = hit_up.distance(); - double down = hit_down.distance(); - double d = up < down ? up : -down; - const Vec3d &normal = (up < down ? hit_up : hit_down).normal(); - double max_up = min_z; double min_down = -(height - min_z); double half_width = path.width / 2.0; @@ -90,7 +86,8 @@ static bool contour_extrusion_path(LayerRegion *region, const sla::IndexedMesh & min_down = -(height + 0.1); } - if (is_perimeter(path.role())) { + if (is_perimeter(path.role()) && hit_up.is_hit()) { + const Vec3d &normal = hit_up.normal(); double slope_rad = slope_from_normal(normal); double slope_degrees = slope_rad * 180.0 / M_PI; From e42ff0b57dc5a4eeb239cf21f48fad56b58573be Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sat, 9 May 2026 00:46:41 +0800 Subject: [PATCH 31/44] when the stealth mode is enabled, log out cloud service and hide sideboard (#13531) * when the stealth mode is enabled, log out cloud service and hide sideboard * update tooltip --- resources/web/homepage/css/home.css | 1 + resources/web/homepage/js/home.js | 11 ++++++++++- src/slic3r/GUI/GUI_App.cpp | 25 +++++++++++++++++++++++++ src/slic3r/GUI/GUI_App.hpp | 1 + src/slic3r/GUI/Preferences.cpp | 16 +++++++++++++++- src/slic3r/GUI/Preferences.hpp | 2 ++ src/slic3r/GUI/WebViewDialog.cpp | 13 +++++++++---- 7 files changed, 63 insertions(+), 6 deletions(-) diff --git a/resources/web/homepage/css/home.css b/resources/web/homepage/css/home.css index da12d73a3c..2bcc18451f 100644 --- a/resources/web/homepage/css/home.css +++ b/resources/web/homepage/css/home.css @@ -71,6 +71,7 @@ body #LeftBoard { + display: none; /* shown by cloud_providers_info from backend */ border-right-width: 1px; border-right-style: solid; width:262px; diff --git a/resources/web/homepage/js/home.js b/resources/web/homepage/js/home.js index 1a63290645..72789cc088 100644 --- a/resources/web/homepage/js/home.js +++ b/resources/web/homepage/js/home.js @@ -103,11 +103,20 @@ function HandleStudio( pVal ) GotoMenu(strName); } else if (strCmd == "cloud_providers_info") { - if (pVal["data"]["providers"] && pVal["data"]["providers"].indexOf("bbl") >= 0) { + var providers = (pVal["data"] && pVal["data"]["providers"]) || []; + + if (providers.indexOf("bbl") >= 0) { $("#BambuCloudSection").show(); } else { + SetBambuUserOffline(); $("#BambuCloudSection").hide(); } + + if (providers.indexOf("orca") >= 0) { + $("#LeftBoard").show(); + } else { + $("#LeftBoard").hide(); + } } else if (strCmd == "network_plugin_installtip") { let nShow = pVal["show"] * 1; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 24271d51fa..1546f09fbc 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -4469,6 +4469,21 @@ std::string GUI_App::handle_web_request(std::string cmd) boost::optional command = root.get_optional("command"); if (command.has_value()) { std::string command_str = command.value(); + static const std::unordered_set stealth_blocked_commands = { + "get_login_info", + "get_orca_login_info", + "get_bambu_login_info", + "homepage_login_or_register", + "homepage_orca_login_or_register", + "homepage_bambu_login_or_register", + }; + if (app_config->get_stealth_mode() && stealth_blocked_commands.count(command_str)) { + CallAfter([this] { + if (mainframe && mainframe->m_webview) + mainframe->m_webview->SendCloudProvidersInfo(); + }); + return ""; + } if (command_str.compare("request_project_download") == 0) { if (root.get_child_optional("data") != boost::none) { pt::ptree data_node = root.get_child("data"); @@ -6731,6 +6746,16 @@ void GUI_App::stop_sync_user_preset() } } +void GUI_App::on_stealth_mode_enter() +{ + stop_sync_user_preset(); + request_user_logout(ORCA_CLOUD_PROVIDER); + request_user_logout(BBL_CLOUD_PROVIDER); + if (mainframe && mainframe->m_webview) { + mainframe->m_webview->SendCloudProvidersInfo(); + } +} + void GUI_App::start_http_server(const std::string& provider) { m_http_server.set_request_handler([provider](const std::string& url) { diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 0ffd3b808b..fac853e65c 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -530,6 +530,7 @@ public: void sync_preset(Preset* preset); void start_sync_user_preset(bool with_progress_dlg = false); void stop_sync_user_preset(); + void on_stealth_mode_enter(); // Bundle subscription sync void check_bundle_updates(); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index c5d377b67b..ccb85ec813 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -924,6 +924,8 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxString too checkbox->SetValue(app_config->get_bool(param)); checkbox->SetToolTip(tip); + if (param == "sync_user_preset") { m_sync_user_preset_checkbox = checkbox; } + m_sizer_checkbox->Add(checkbox_title, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, FromDIP(3)); m_sizer_checkbox->Add(checkbox , 0, wxALIGN_CENTER | wxRIGHT | wxLEFT, FromDIP(5)); @@ -955,6 +957,12 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxString too } BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " sync_user_preset: " << (sync ? "true" : "false"); } + else if (param == "stealth_mode") { + bool enabled = app_config->get_stealth_mode(); + if (enabled) wxGetApp().on_stealth_mode_enter(); + if (m_sync_user_preset_checkbox) m_sync_user_preset_checkbox->Enable(!enabled); + if (m_bambu_cloud_checkbox) m_bambu_cloud_checkbox->Enable(!enabled); + } #ifdef __WXMSW__ if (param == "associate_3mf") { @@ -1528,7 +1536,7 @@ void PreferencesDialog::create_items() auto item_region = create_item_region_combobox(_L("Login region"), ""); g_sizer->Add(item_region); - auto item_stealth_mode = create_item_checkbox(_L("Stealth mode"), _L("This stops the transmission of data to Bambu's cloud services. Users who don't use BBL machines or use LAN mode only can safely turn on this function."), "stealth_mode"); + auto item_stealth_mode = create_item_checkbox(_L("Stealth mode"), _L("This disables all cloud services e.g. Orca Cloud and Bambu Cloud. This stops the transmission of data to Bambu's cloud services too. Users who don't use BBL machines or use LAN mode only can safely turn on this function."), "stealth_mode"); g_sizer->Add(item_stealth_mode); auto item_network_test = create_item_button(_L("Network test"), _L("Test") + " " + dots, "", _L("Open Network Test"), []() { @@ -1552,6 +1560,7 @@ void PreferencesDialog::create_items() text->Wrap(DESIGN_TITLE_SIZE.x); auto cb = new ::CheckBox(m_parent); + m_bambu_cloud_checkbox = cb; cb->SetValue(app_config->has_cloud_provider(BBL_CLOUD_PROVIDER)); cb->SetToolTip(text->GetToolTipText()); @@ -1585,6 +1594,11 @@ void PreferencesDialog::create_items() auto item_user_sync = create_item_checkbox(_L("Auto sync user presets (Printer/Filament/Process)"), "", "sync_user_preset"); g_sizer->Add(item_user_sync); + if (app_config->get_stealth_mode()) { + if (m_bambu_cloud_checkbox) m_bambu_cloud_checkbox->Enable(false); + if (m_sync_user_preset_checkbox) m_sync_user_preset_checkbox->Enable(false); + } + auto item_system_sync = create_item_checkbox(_L("Update built-in Presets automatically."), "", "sync_system_preset"); g_sizer->Add(item_system_sync); diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp index 73e61938d6..d7daca5ff8 100644 --- a/src/slic3r/GUI/Preferences.hpp +++ b/src/slic3r/GUI/Preferences.hpp @@ -71,6 +71,8 @@ public: ::CheckBox * m_developer_mode_ckeckbox = {nullptr}; ::CheckBox * m_internal_developer_mode_ckeckbox = {nullptr}; ::CheckBox * m_dark_mode_ckeckbox = {nullptr}; + ::CheckBox * m_sync_user_preset_checkbox = {nullptr}; + ::CheckBox * m_bambu_cloud_checkbox = {nullptr}; ::TextInput *m_backup_interval_textinput = {nullptr}; ::ComboBox * m_network_version_combo = {nullptr}; wxBoxSizer * m_network_version_sizer = {nullptr}; diff --git a/src/slic3r/GUI/WebViewDialog.cpp b/src/slic3r/GUI/WebViewDialog.cpp index 7988f91147..2a88277680 100644 --- a/src/slic3r/GUI/WebViewDialog.cpp +++ b/src/slic3r/GUI/WebViewDialog.cpp @@ -418,8 +418,9 @@ void WebViewPanel::OnFreshLoginStatus(wxTimerEvent &event) { auto mainframe = Slic3r::GUI::wxGetApp().mainframe; if (mainframe && mainframe->m_webview == this) { - Slic3r::GUI::wxGetApp().get_login_info(ORCA_CLOUD_PROVIDER); auto* app_config = Slic3r::GUI::wxGetApp().app_config; + if (app_config && app_config->get_stealth_mode()) return; + Slic3r::GUI::wxGetApp().get_login_info(ORCA_CLOUD_PROVIDER); if (app_config && app_config->has_cloud_provider(BBL_CLOUD_PROVIDER)) { Slic3r::GUI::wxGetApp().get_login_info(BBL_CLOUD_PROVIDER); } @@ -520,14 +521,18 @@ void WebViewPanel::SendCloudProvidersInfo() if (!app_config) return; - auto providers = app_config->get_cloud_providers(); json j; j["command"] = "cloud_providers_info"; json data; json provider_array = json::array(); - for (const auto& p : providers) { - provider_array.push_back(p); + + if (!app_config->get_stealth_mode()) { + auto providers = app_config->get_cloud_providers(); + for (const auto& p : providers) { + provider_array.push_back(p); + } } + data["providers"] = provider_array; j["data"] = data; From e5294b12827300011998e58d8d3f7427e67057c9 Mon Sep 17 00:00:00 2001 From: Misterff1 Date: Fri, 8 May 2026 19:57:47 +0200 Subject: [PATCH 32/44] Update BBL P2S printer and process profiles (#13355) * Disable arc fitting by default on BBL P2S * Update BBL P2S printer profile * bump the version so that it automatically update the cache --------- Co-authored-by: SoftFever --- resources/profiles/BBL.json | 2 +- .../profiles/BBL/machine/Bambu Lab P2S 0.4 nozzle.json | 9 +++++---- .../process/0.08mm High Quality @BBL P2S 0.2 nozzle.json | 1 + .../BBL/process/0.08mm High Quality @BBL P2S.json | 1 + .../BBL/process/0.10mm Standard @BBL P2S 0.2 nozzle.json | 1 + .../0.12mm Balanced Quality @BBL P2S 0.2 nozzle.json | 1 + .../BBL/process/0.12mm High Quality @BBL P2S.json | 1 + .../BBL/process/0.16mm High Quality @BBL P2S.json | 1 + .../profiles/BBL/process/0.16mm Standard @BBL P2S.json | 1 + .../0.18mm Balanced Quality @BBL P2S 0.6 nozzle.json | 1 + .../BBL/process/0.20mm High Quality @BBL P2S.json | 1 + .../profiles/BBL/process/0.20mm Standard @BBL P2S.json | 1 + .../0.24mm Balanced Quality @BBL P2S 0.6 nozzle.json | 1 + .../0.24mm Balanced Quality @BBL P2S 0.8 nozzle.json | 1 + .../profiles/BBL/process/0.24mm Standard @BBL P2S.json | 1 + .../BBL/process/0.30mm Standard @BBL P2S 0.6 nozzle.json | 1 + .../0.32mm Balanced Quality @BBL P2S 0.8 nozzle.json | 1 + .../BBL/process/0.40mm Standard @BBL P2S 0.8 nozzle.json | 1 + 18 files changed, 22 insertions(+), 5 deletions(-) diff --git a/resources/profiles/BBL.json b/resources/profiles/BBL.json index c9f0e6a73c..0def516b0c 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.01.00.10", + "version": "02.01.00.11", "force_update": "0", "description": "the initial version of BBL configurations", "machine_model_list": [ diff --git a/resources/profiles/BBL/machine/Bambu Lab P2S 0.4 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab P2S 0.4 nozzle.json index a7fc83584b..96e9e51600 100644 --- a/resources/profiles/BBL/machine/Bambu Lab P2S 0.4 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab P2S 0.4 nozzle.json @@ -161,6 +161,7 @@ ], "printable_height": "256", "auxiliary_fan": "0", + "support_air_filtration": "1", "printer_extruder_id": [ "1", "1" @@ -242,10 +243,10 @@ "Bambu Lab H2D 0.4 nozzle", "Bambu Lab H2D Pro 0.4 nozzle" ], - "machine_start_gcode": ";M1002 set_flag extrude_cali_flag=1\n;M1002 set_flag g29_before_print_flag=1\n;M1002 set_flag auto_cali_toolhead_offset_flag=1\n;M1002 set_flag build_plate_detect_flag=1\n\n;======== P2S start gcode==========\n;===== Based on official 2026/02/26 start gcode =====\n \n M140 S[bed_temperature_initial_layer_single] ; heat heatbed first\n M993 A0 B0 C0 ; nozzle cam detection not allowed.\n M400 \n\n;=====printer start sound ===================\nM17\nM400 S1\nM1006 S1\nM1006 A53 B9 L50 C53 D9 M50 E53 F9 N50 \nM1006 A56 B9 L50 C56 D9 M50 E56 F9 N50 \nM1006 A61 B9 L50 C61 D9 M50 E61 F9 N50 \nM1006 A53 B9 L50 C53 D9 M50 E53 F9 N50 \nM1006 A56 B9 L50 C56 D9 M50 E56 F9 N50 \nM1006 A61 B18 L50 C61 D18 M50 E61 F18 N50 \nM1006 W\n;=====printer start sound ===================\n\n M620 M ;enable remap\n G389\n\n;===== avoid end stop =================\n G91\n G380 S2 Z22 F1200\n G380 S2 Z-12 F1200\n G90\n;===== avoid end stop =================\n\n;===== reset machine status =================\n M204 S10000\n M630 S0 P1\n G90\n M17 D ; reset motor current to default\n M960 S5 P1 ; turn on logo lamp\n G90\n M220 S100 ;Reset Feedrate\n M1002 set_gcode_claim_speed_level: 5\n M221 S100 ;Reset Flowrate\n M73.2 R1.0 ;Reset left time magnitude\n G29.1 Z{+0.0} ; clear z-trim value first\n M983.1 M1\n M975 S1 ; turn on input shaping\n M982.2 S1 ; turn on cog noise reduction\n M983.4 S0\n;===== reset machine status =================\n\n;==== set airduct mode ==== \n;==== if Chamber Cooling is necessary ====\n{if (overall_chamber_temperature >= 40)}\nM145 P1 ; set airduct mode to heating mode for heating\nM106 P2 S255 ; turn on filter fan\nM622.1 S0\nM1002 judge_flag ventobox_replace_aux1_fan_flag\nM622 J0\nM106 P10 S0 ; turn off left aux fan\nM623\n{else}\n{if (min_vitrification_temperature <= 50)}\nM145 P0 ; set airduct mode to cooling mode for cooling\nM106 P2 S255 ; turn on auxiliary fan for cooling\nM106 P3 S127 ; turn on chamber fan for cooling\nM1002 gcode_claim_action : 29\nM191 S0 ; wait for chamber temp\nM106 P2 S102 ; turn on chamber cooling fan\nM622.1 S0\nM1002 judge_flag ventobox_replace_aux1_fan_flag\nM622 J0\nM106 P10 S0 ; turn off left aux fan\nM623\nM142 P6 R30 S40 U0.3 V0.8 ; set PETG exhaust chamber autocooling\n{else}\nM145 P1 ; set airduct mode to heating mode for heating\nM106 P2 S127 ; turn on 50% filter fan\nM142 P6 R30 S40 U0.3 V0.8 ; set PLA/TPU exhaust chamber autocooling\n{endif}\n{endif}\n;==== set airduct mode ==== \n\n;===== start to heat heatbed & hotend==========\n M1002 gcode_claim_action : 2\n M1002 set_filament_type:{filament_type[initial_no_support_extruder]}\n M104 S140 A \n\n G29.2 S0 ; avoid invalid abl data\n\n;===== first homing start =====\n M1002 gcode_claim_action : 13\n G28 X T300\n G150.1 F8000 ; wipe mouth to avoid filament stick to heatbed\n G150.3\n M972 S24 P0\n M972 S26 P0 C0\n M972 S42 P0 T5000\n G150.1 F8000 ; wipe mouth to avoid filament stick to heatbed\n G90\n G1 X128 Y128 F30000\n G28 Z P0 T400\n M400\n;===== first homing end =====\n\n;===== detection start =====\n M1002 gcode_claim_action : 11\n M104 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-80} A ; rise temp in advance\n M972 S19 P0 T5000 ;plate type detection\n \n {if max_print_z >= 145}\n M1002 gcode_claim_action : 75 ; Detect obstacles at the botton of the heated bed\n G150.3\n M104 S{nozzle_temperature_initial_layer[initial_no_support_extruder]} ; rise temp in advance\n G3811 Z{max_print_z} ; Detect obstacles at the bottom of the heated bed\n {endif}\n;===== detection end =====\n\n;===== prepare print temperature and material ==========\n M400\n M211 X0 Y0 Z0 ;turn off soft endstop\n \n G29.2 S0 ; avoid invalid abl data\n G150.3\n{if ((filament_type[initial_no_support_extruder] == \"PLA\") || (filament_type[initial_no_support_extruder] == \"PLA-CF\") || (filament_type[initial_no_support_extruder] == \"PETG\")) && (nozzle_diameter[initial_no_support_extruder] == 0.2)}\nM620.10 A0 F74.8347 H{nozzle_diameter[initial_no_support_extruder]} T{flush_temperatures[initial_no_support_extruder]} P{nozzle_temperature_initial_layer[initial_no_support_extruder]} S1\nM620.10 A1 F74.8347 H{nozzle_diameter[initial_no_support_extruder]} T{flush_temperatures[initial_no_support_extruder]} P{nozzle_temperature_initial_layer[initial_no_support_extruder]} S1\n{else}\nM620.10 A0 F{flush_volumetric_speeds[initial_no_support_extruder]/2.4053*60} H{nozzle_diameter[initial_no_support_extruder]} T{flush_temperatures[initial_no_support_extruder]} P{nozzle_temperature_initial_layer[initial_no_support_extruder]} S1\nM620.10 A1 F{flush_volumetric_speeds[initial_no_support_extruder]/2.4053*60} H{nozzle_diameter[initial_no_support_extruder]} T{flush_temperatures[initial_no_support_extruder]} P{nozzle_temperature_initial_layer[initial_no_support_extruder]} S1\n{endif}\n \n M620.11 P0 L0 I[initial_no_support_extruder] E0\n M620.11 K0 I[initial_no_support_extruder] R0\n \n M620 S[initial_no_support_extruder]A ; switch material if AMS exist\n M1002 gcode_claim_action : 4\n M1002 set_filament_type:UNKNOWN\n M400\n T[initial_no_support_extruder]\n M400\n M628 S0\n M629\n M400\n M1002 set_filament_type:{filament_type[initial_no_support_extruder]}\n M621 S[initial_no_support_extruder]A\n M104 S{nozzle_temperature_initial_layer[initial_no_support_extruder]}\n M400\n M106 P1 S0\n M400\n G29.2 S1\n;===== prepare print temperature and material ==========\n\n\n;===== auto extrude cali start =========================\n M975 S1\n M1002 judge_flag extrude_cali_flag\n M622 J0\n M983.3 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4} A0.4 ; cali dynamic extrusion compensation\n M623\n\n M622 J1\n M1002 set_filament_type:{filament_type[initial_no_support_extruder]}\n M1002 gcode_claim_action : 8\n M109 S{nozzle_temperature[initial_no_support_extruder]}\n G90\n M83\n M983.3 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4} A0.4 ; cali dynamic extrusion compensation\n M400\n M106 P1 S255\n M400 S5\n M106 P1 S0\n G150.3\n M623\n\n M622 J2\n M1002 set_filament_type:{filament_type[initial_no_support_extruder]}\n M1002 gcode_claim_action : 8\n M109 S{nozzle_temperature[initial_no_support_extruder]}\n G90\n M83\n M983.3 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4} A0.4 ; cali dynamic extrusion compensation\n M400\n M106 P1 S255\n M400 S5\n M106 P1 S0\n G150.3\n M623\n;===== auto extrude cali end =========================\n\n {if hold_chamber_temp_for_flat_print}\n M1002 gcode_claim_action : 58\n M104 S{first_layer_temperature[initial_no_support_extruder]}\n {if bed_temperature_initial_layer_single > 89}\n M1030 S1800\n SYNC R0 T1800\n {else}\n M1030 S300\n SYNC R0 T300\n {endif}\n M1030 C\n {endif}\n \n {if filament_type[current_extruder] == \"TPU\" || filament_type[current_extruder] == \"PVA\"}\n {else}\n M83\n G1 E-3 F1800\n M400 P500\n {endif}\n G150.2\n G150.1 F8000\n G150.2\n G150.1 F8000\n \n G91\n G1 Y-16 F12000 ; move away from the trash bin\n G90\n M400\n\n M104 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-80} A\n\n;===== wipe right nozzle start =====\n M1002 gcode_claim_action : 14\n G150 T{nozzle_temperature_initial_layer[initial_no_support_extruder]}\n M400\n \n{if filament_type[current_extruder] == \"PC\"}\n M109 S170 A\n{else}\n M109 S140 A\n{endif}\n G91\n G1 Z5 F1200\n G90\n M400\n G150.1\n;===== wipe left nozzle end =====\n\n;===== mech mode sweep start =====\n M1002 gcode_claim_action : 3\n G90\n G1 X128 Y128 F20000\n G1 Z5 F1200\n M400 P200\n M970.3 Q1 A5 K0 O1\n M970.2 Q1 K1 W74 Z0.01\n M974 Q1 S2 P0\n M970.3 Q0 A7 K0 O1\n M970.2 Q0 K1 W74 Z0.01\n M974 Q0 S2 P0\n M975 S1\n M400\n;===== mech mode sweep end =====\n\n;===== bed leveling ==================================\n M1002 gcode_claim_action : 54\n M190 S[bed_temperature_initial_layer_single]; ensure bed temp\n M109 S140 A\n M106 S0 ; turn off fan , too noisy\n M1002 judge_flag g29_before_print_flag\n M622 J1\n M1002 gcode_claim_action : 1\n {if hold_chamber_temp_for_flat_print}\n G29 H\n {else}\n G29 A1 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n {endif}\n M400\n M500 ; save cali data\n M623\n \n M622 J2\n M1002 gcode_claim_action : 1\n {if hold_chamber_temp_for_flat_print}\n G29 H\n {else}\n G29 A2 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n {endif}\n M400\n M500 ; save cali data\n M623\n\n M622 J0\n ;skip to homing\n M623\n G29.2 S1\n G28\n;===== bed leveling end ================================\n\n M985.1 U0 E2\n M985.1 U1 E2\n\n M104 S[nozzle_temperature_initial_layer] A\n G150.3 ; move to garbage can to wait for temp\n\n;===== wait temperature reaching the reference value =======\n M190 S[bed_temperature_initial_layer_single] \n\n ;========turn off light and fans =============\n M960 S1 P0 ; turn off laser\n M960 S2 P0 ; turn off laser\n M106 S0 ; turn off cooling fan\n \n;===== wait temperature reaching the reference value =======\n\n M1002 gcode_claim_action : 255\n M400\n M975 S1 ; turn on mech mode supression\n\n;============switch again==================\n M211 X0 Y0 Z0 ;turn off soft endstop\n G91\n G1 Z6 F1200\n G90\n M1002 set_filament_type:{filament_type[initial_no_support_extruder]}\n M620 S[initial_no_support_extruder]A\n M400\n T[initial_no_support_extruder]\n M400\n M628 S0\n M629\n M400\n M621 S[initial_no_support_extruder]A\n;============switch again==================\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n {if bed_temperature_initial_layer_single > 89}\n {if curr_bed_type==\"Textured PEI Plate\"}\n G29.1 Z{-0.02} ; for Textured PEI Plate\n {else}\n G29.1 Z{0.0}\n {endif}\n {else}\n {if curr_bed_type==\"Textured PEI Plate\"}\n G29.1 Z{0.01} ; for Textured PEI Plate\n {else}\n G29.1 Z{0.03}\n {endif}\n {endif}\n\n M500\n\n;===== nozzle load line ===============================\nM1002 gcode_claim_action : 51\n G29.2 S1 ; ensure z comp turn on\n G90\n M83\n M109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]}\n G0 X100 Y0 F24000\n M400\n G130 O0 X100 Y-0.2 Z0.6 F{filament_max_volumetric_speed[initial_no_support_extruder]/2/2.4053} L40 E12 D4\n G90\n M83\n G1 Z0.5\n M400\n;===== nozzle load line end ===========================\nM1002 gcode_claim_action : 0\n G29.99\n\n{if (filament_type[initial_no_support_extruder] == \"TPU\") || \n(filament_type[initial_no_support_extruder] == \"PLA\") || (filament_type[initial_no_support_extruder] == \"PETG\")}\nM1015.3 S1 H[nozzle_diameter];enable tpu, pla and petg clog detect\n{else}\nM1015.3 S0;disable clog detect\n{endif}\n\n{if (filament_type[initial_no_support_extruder] == \"PLA\") || (filament_type[initial_no_support_extruder] == \"PETG\")\n || (filament_type[initial_no_support_extruder] == \"PLA-CF\") || (filament_type[initial_no_support_extruder] == \"PETG-CF\")}\nM1015.4 S1 K1 H[nozzle_diameter] ;enable E air printing detect\n{else}\nM1015.4 S0 K0 H[nozzle_diameter] ;disable E air printing detect\n{endif}\n\nM620.6 I[initial_no_support_extruder] W1 ;enable ams air printing detect\n\nM1010 Q0 B0.023 S0.01\nM1010 Q1 B0.005 S0.01\nM1010.1 S1", - "machine_end_gcode": ";======== P2S end gcode ==========\n;===== Based on official 2026/03/13 end gcode =====\n\nM400 ; wait for buffer to clear\nG92 E0 ; zero the extruder\n\n; pull back filament to AMS\nM620 S65535\nT65535\nG150.2\nM621 S65535\n\nG150.3\n\nM400 ; wait all motion done\n\nM1002 judge_flag timelapse_record_flag\nM622 J1\n M991 S0 P-1 ;end smooth timelapse at safe pos\n M400 S5 ;wait for last picture to be taken\nM623 ;end of \"timelapse_record_flag\"\n\nM104 S0 ; turn off hotend\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off remote part cooling fan\nM106 P3 S0 ; turn off chamber cooling fan\nM106 P10 S0 ; turn off left aux fan\n\nM400 ; wait all motion done\nM17 S\nM17 Z0.4 ; lower z motor current to reduce impact if there is something in the bottom\n{if (80.0 - max_layer_z/2) > 0}\n {if (max_layer_z + 80.0 - max_layer_z/2) < 256}\n G1 Z{max_layer_z + 80.0 - max_layer_z/2} F600\n G1 Z{max_layer_z + 78.0 - max_layer_z/2}\n {else}\n G1 Z256 F600\n G1 Z256\n {endif}\n{else}\n {if (max_layer_z + 4.0) < 256}\n G1 Z{max_layer_z + 4.0} F600\n G1 Z{max_layer_z + 2.0}\n {else}\n G1 Z256 F600\n G1 Z256\n {endif}\n{endif}\nM400 P100\nM17 R ; restore z current\n\n\nM220 S100 ; Reset feedrate magnitude\nM201.2 K1.0 ; Reset acc magnitude\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 0\n\nM1015.3 S0 ;disable clog detect\nM1015.4 S0 K0 ;disable air printing detect\n\n;=====printer finish air purification=========\nM622.1 S0\nM1002 judge_flag print_finish_air_filt_flag\n\n;if activate_air_filtration is enabled in filament settings, it will skip purification regardless of what is set on the printer.\nM622 J1\n{if !activate_air_filtration[current_extruder]}\nM1002 gcode_claim_action : 66\nM145 P1\nM106 P2 S255\nM400 S180\nM106 P2 S0\n{endif}\nM623\n\nM622 J2\n{if !activate_air_filtration[current_extruder]}\nM1002 gcode_claim_action : 66\nM145 P0\nM106 P3 S255\nM400 S180\nM106 P3 S0\n{endif}\nM623\n;=====printer finish air purification=========\n\n;=====printer finish sound=========\nM17\nM400 S1\nM1006 S1\nM1006 A53 B10 L50 C53 D10 M50 E53 F10 N50 \nM1006 A57 B10 L50 C57 D10 M50 E57 F10 N50 \nM1006 A0 B15 L0 C0 D15 M0 E0 F15 N0 \nM1006 A53 B10 L50 C53 D10 M50 E53 F10 N50 \nM1006 A57 B10 L50 C57 D10 M50 E57 F10 N50 \nM1006 A0 B15 L0 C0 D15 M0 E0 F15 N0 \nM1006 A48 B10 L50 C48 D10 M50 E48 F10 N50 \nM1006 A0 B15 L0 C0 D15 M0 E0 F15 N0 \nM1006 A60 B10 L50 C60 D10 M50 E60 F10 N50 \nM1006 W\n;=====printer finish sound=========\nM400\nM18", - "layer_change_gcode": ";======== P2S layer_change gcode ==========\n;===== 2026/01/08 ====\n\n{if (layer_num + 1 == 1)}\n{if (overall_chamber_temperature >= 40)}\n ;not reset filter fan in first layer\n ;not reset fan\n{else}\n{if (min_vitrification_temperature > 50)}\n ;not reset filter fan in first layer\n ;not reset fan\n{endif} \n{endif}\n{endif}\n\n{if (layer_num + 1 == close_fan_the_first_x_layers[current_extruder]+1)}\n{if (overall_chamber_temperature < 40)}\n ;updata chamber autocooling in Xth layer\n {if (min_vitrification_temperature <= 50)}\n {if (nozzle_diameter == 0.2)}\n M142 P1 R30 S40 U{max_additional_fan/100.0} V1.0 O45; set PLA/TPU ND0.2 chamber autocooling\n {else}\n M142 P1 R30 S40 U{max_additional_fan/100.0} V1.0 O45; set PLA/TPU ND0.4 chamber autocooling\n {endif}\n {else}\n ;not reset filter fan in Xth layer\n {endif}\n{else}\n ;not reset filter fan in Xth layer\n{endif}\n M622.1 S0\n M1002 judge_flag ventobox_replace_aux1_fan_flag\n M622 J0\n M106 P10 S{additional_cooling_fan_speed[current_extruder]*255.0/100.0}; set left aux fan \n M623\n;not reset fan\n{endif}\n\n\n; update layer progress\nM73 L{layer_num+1}\nM991 S0 P{layer_num} ;notify layer change", + "machine_start_gcode": ";M1002 set_flag extrude_cali_flag=1\n;M1002 set_flag g29_before_print_flag=1\n;M1002 set_flag auto_cali_toolhead_offset_flag=1\n;M1002 set_flag build_plate_detect_flag=1\n\n;======== P2S start gcode==========\n;===== Based on official 2026/04/21 start gcode =====\n \n M140 S[bed_temperature_initial_layer_single] ; heat heatbed first\n M993 A0 B0 C0 ; nozzle cam detection not allowed.\n M400\n\n;=====printer start sound ===================\nM17\nM400 S1\nM1006 S1\nM1006 A53 B9 L50 C53 D9 M50 E53 F9 N50 \nM1006 A56 B9 L50 C56 D9 M50 E56 F9 N50 \nM1006 A61 B9 L50 C61 D9 M50 E61 F9 N50 \nM1006 A53 B9 L50 C53 D9 M50 E53 F9 N50 \nM1006 A56 B9 L50 C56 D9 M50 E56 F9 N50 \nM1006 A61 B18 L50 C61 D18 M50 E61 F18 N50 \nM1006 W\n;=====printer start sound ===================\n\n M620 M ;enable remap\n G389\n\n;===== avoid end stop =================\n G91\n G380 S2 Z22 F1200\n G380 S2 Z-12 F1200\n G90\n;===== avoid end stop =================\n\n;===== reset machine status =================\n M204 S10000\n M630 S0 P1\n G90\n M17 D ; reset motor current to default\n M960 S5 P1 ; turn on logo lamp\n G90\n M220 S100 ;Reset Feedrate\n M1002 set_gcode_claim_speed_level: 5\n M221 S100 ;Reset Flowrate\n M73.2 R1.0 ;Reset left time magnitude\n G29.1 Z{+0.0} ; clear z-trim value first\n M983.1 M1\n M975 S1 ; turn on input shaping\n M982.2 S1 ; turn on cog noise reduction\n M983.4 S0\n;===== reset machine status =================\n\n;==== set airduct mode ==== \n;==== if Chamber Cooling is necessary ====\n{if (overall_chamber_temperature >= 40)}\nM145 P1 ; set airduct mode to heating mode for heating\nM106 P2 S255 ; turn on filter fan\nM622.1 S0\nM1002 judge_flag ventobox_replace_aux1_fan_flag\nM622 J0\nM106 P10 S0 ; turn off left aux fan\nM623\n{else}\n{if (min_vitrification_temperature <= 50)}\nM145 P0 ; set airduct mode to cooling mode for cooling\nM106 P2 S255 ; turn on auxiliary fan for cooling\nM106 P3 S127 ; turn on chamber fan for cooling\nM1002 gcode_claim_action : 29\nM191 S0 ; wait for chamber temp\nM106 P2 S102 ; turn on chamber cooling fan\nM622.1 S0\nM1002 judge_flag ventobox_replace_aux1_fan_flag\nM622 J0\nM106 P10 S0 ; turn off left aux fan\nM623\nM142 P6 R30 S40 U0.3 V0.8 ; set PETG exhaust chamber autocooling\n{else}\nM145 P1 ; set airduct mode to heating mode for heating\nM106 P2 S127 ; turn on 50% filter fan\nM142 P6 R30 S40 U0.3 V0.8 ; set PLA/TPU exhaust chamber autocooling\n{endif}\n{endif}\n;==== set airduct mode ==== \n\n;===== start to heat heatbed & hotend==========\n M1002 gcode_claim_action : 2\n M1002 set_filament_type:{filament_type[initial_no_support_extruder]}\n M104 S140 A \n\n G29.2 S0 ; avoid invalid abl data\n\n;===== first homing start =====\n M1002 gcode_claim_action : 13\n G28 X T300\n G150.1 F8000 ; wipe mouth to avoid filament stick to heatbed\n G150.3\n M972 S24 P0\n M972 S26 P0 C0\n M972 S42 P0 T5000\n G150.1 F8000 ; wipe mouth to avoid filament stick to heatbed\n G90\n G1 X128 Y128 F30000\n G28 Z P0 T400\n M400\n;===== first homing end =====\n\n;===== detection start =====\n M1002 gcode_claim_action : 11\n M104 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-80} A ; rise temp in advance\n M972 S19 P0 T5000 ;plate type detection\n \n {if max_print_z >= 145}\n M1002 gcode_claim_action : 75 ; Detect obstacles at the botton of the heated bed\n G150.3\n M104 S{nozzle_temperature_initial_layer[initial_no_support_extruder]} ; rise temp in advance\n G3811 Z{max_print_z} ; Detect obstacles at the bottom of the heated bed\n {endif}\n;===== detection end =====\n\n;===== prepare print temperature and material ==========\n M400\n M211 X0 Y0 Z0 ;turn off soft endstop\n \n G29.2 S0 ; avoid invalid abl data\n G150.3\n{if ((filament_type[initial_no_support_extruder] == \"PLA\") || (filament_type[initial_no_support_extruder] == \"PLA-CF\") || (filament_type[initial_no_support_extruder] == \"PETG\")) && (nozzle_diameter[initial_no_support_extruder] == 0.2)}\nM620.10 A0 F74.8347 H{nozzle_diameter[initial_no_support_extruder]} T{flush_temperatures[initial_no_support_extruder]} P{nozzle_temperature_initial_layer[initial_no_support_extruder]} S1\nM620.10 A1 F74.8347 H{nozzle_diameter[initial_no_support_extruder]} T{flush_temperatures[initial_no_support_extruder]} P{nozzle_temperature_initial_layer[initial_no_support_extruder]} S1\n{else}\nM620.10 A0 F{flush_volumetric_speeds[initial_no_support_extruder]/2.4053*60} H{nozzle_diameter[initial_no_support_extruder]} T{flush_temperatures[initial_no_support_extruder]} P{nozzle_temperature_initial_layer[initial_no_support_extruder]} S1\nM620.10 A1 F{flush_volumetric_speeds[initial_no_support_extruder]/2.4053*60} H{nozzle_diameter[initial_no_support_extruder]} T{flush_temperatures[initial_no_support_extruder]} P{nozzle_temperature_initial_layer[initial_no_support_extruder]} S1\n{endif}\n \n M620.11 P0 L0 I[initial_no_support_extruder] E0\n M620.11 K0 I[initial_no_support_extruder] R0\n \n M620 S[initial_no_support_extruder]A ; switch material if AMS exist\n M1002 gcode_claim_action : 4\n M1002 set_filament_type:UNKNOWN\n M400\n T[initial_no_support_extruder]\n M400\n M628 S0\n M629\n M400\n M1002 set_filament_type:{filament_type[initial_no_support_extruder]}\n M621 S[initial_no_support_extruder]A\n M104 S{nozzle_temperature_initial_layer[initial_no_support_extruder]}\n M400\n M106 P1 S0\n M400\n G29.2 S1\n;===== prepare print temperature and material ==========\n\n\n;===== auto extrude cali start =========================\n M975 S1\n M1002 judge_flag extrude_cali_flag\n M622 J0\n M983.3 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4} A0.4 ; cali dynamic extrusion compensation\n M623\n\n M622 J1\n M1002 set_filament_type:{filament_type[initial_no_support_extruder]}\n M1002 gcode_claim_action : 8\n M109 S{nozzle_temperature[initial_no_support_extruder]}\n G90\n M83\n M983.3 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4} A0.4 ; cali dynamic extrusion compensation\n M400\n M106 P1 S255\n M400 S5\n M106 P1 S0\n G150.3\n M623\n\n M622 J2\n M1002 set_filament_type:{filament_type[initial_no_support_extruder]}\n M1002 gcode_claim_action : 8\n M109 S{nozzle_temperature[initial_no_support_extruder]}\n G90\n M83\n M983.3 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4} A0.4 ; cali dynamic extrusion compensation\n M400\n M106 P1 S255\n M400 S5\n M106 P1 S0\n G150.3\n M623\n;===== auto extrude cali end =========================\n\n {if hold_chamber_temp_for_flat_print}\n M1002 gcode_claim_action : 58\n M104 S{first_layer_temperature[initial_no_support_extruder]}\n {if bed_temperature_initial_layer_single > 89}\n M1030 S1800 \n SYNC R0 T1800\n {else}\n M1030 S300\n SYNC R0 T300\n {endif}\n M1030 C\n {endif}\n \n {if filament_type[current_extruder] == \"TPU\" || filament_type[current_extruder] == \"PVA\"}\n {else}\n M83\n G1 E-3 F1800\n M400 P500\n {endif}\n\n ; series of wipes to ensure the nozzle is as clean as possible to avoid potential z-drift issues.\n M104 S180\n G150.2\n G150.1 F8000\n G150.2\n G150.1 F8000\n M106 P1 S255\n M109 S180 A\n G150.1 F8000 \n M109 S140 A\n M106 P1 S0\n G150.1 F8000\n G91\n G1 Y-16 F12000\n G1 X100 F6000\n G90\n M400\n\n;===== wipe right nozzle start =====\n M1002 gcode_claim_action : 14\n G150 T{nozzle_temperature_initial_layer[initial_no_support_extruder]}\n M400\n \n{if filament_type[current_extruder] == \"PC\"}\n M109 S170 A\n{else}\n M109 S140 A\n{endif}\n G91\n G1 Z5 F1200\n G90\n M400\n G150.1\n;===== wipe left nozzle end =====\n\n\n;===== mech mode sweep start =====\n M1002 gcode_claim_action : 3\n G90\n G1 X128 Y128 F20000\n G1 Z5 F1200\n M400 P200\n M970.3 Q1 A5 K0 O1\n M970.2 Q1 K1 W74 Z0.01\n M974 Q1 S2 P0\n M970.3 Q0 A7 K0 O1\n M970.2 Q0 K1 W74 Z0.01\n M974 Q0 S2 P0\n M975 S1\n M400\n;===== mech mode sweep end =====\n\n;===== bed leveling ==================================\n M1002 gcode_claim_action : 54\n M190 S[bed_temperature_initial_layer_single]; ensure bed temp\n M109 S140 A\n M106 S0 ; turn off fan , too noisy\n M1002 judge_flag g29_before_print_flag\n M622 J1\n M1002 gcode_claim_action : 1\n {if hold_chamber_temp_for_flat_print}\n G29 H\n {else}\n G29 A1 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n {endif}\n M400\n M623\n \n M622 J2\n M1002 gcode_claim_action : 1\n {if hold_chamber_temp_for_flat_print}\n G29 H\n {else}\n G29 A2 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n {endif}\n M400\n M623\n\n M622 J0\n ;skip to homing\n M623\n G29.2 S1\n G28\n;===== bed leveling end ================================\n\n M985.1 U0 E2\n M985.1 U1 E2\n\n M104 S[nozzle_temperature_initial_layer] A\n G150.3 ; move to garbage can to wait for temp\n\n;===== wait temperature reaching the reference value =======\n M190 S[bed_temperature_initial_layer_single] \n\n ;========turn off light and fans =============\n M960 S1 P0 ; turn off laser\n M960 S2 P0 ; turn off laser\n M106 S0 ; turn off cooling fan\n \n;===== wait temperature reaching the reference value =======\n\n M1002 gcode_claim_action : 255\n M400\n M975 S1 ; turn on mech mode supression\n\n;============switch again==================\n M211 X0 Y0 Z0 ;turn off soft endstop\n G91\n G1 Z6 F1200\n G90\n M1002 set_filament_type:{filament_type[initial_no_support_extruder]}\n M620 S[initial_no_support_extruder]A\n M400\n T[initial_no_support_extruder]\n M400\n M628 S0\n M629\n M400\n M621 S[initial_no_support_extruder]A\n;============switch again==================\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n {if bed_temperature_initial_layer_single > 89}\n {if curr_bed_type==\"Textured PEI Plate\"}\n G29.1 Z{-0.02} ; for Textured PEI Plate\n {else}\n G29.1 Z{0.0}\n {endif}\n {else}\n {if curr_bed_type==\"Textured PEI Plate\"}\n G29.1 Z{0.01} ; for Textured PEI Plate\n {else}\n G29.1 Z{0.03}\n {endif}\n {endif}\n\n\n;===== nozzle load line ===============================\nM1002 gcode_claim_action : 51\n G29.2 S1 ; ensure z comp turn on\n G90\n M83\n M400 P50\n M500 D1\n M400 S3\n M109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]}\n G0 X100 Y0 F24000\n M400\n G130 O0 X100 Y-0.2 Z0.6 F{filament_max_volumetric_speed[initial_no_support_extruder]/2/2.4053} L40 E12 D4\n G90\n M83\n G1 Z1\n M400\n;===== nozzle load line end ===========================\nM1002 gcode_claim_action : 0\n G29.99\n\n{if (filament_type[initial_no_support_extruder] == \"TPU\") || \n(filament_type[initial_no_support_extruder] == \"PLA\") || (filament_type[initial_no_support_extruder] == \"PETG\")}\nM1015.3 S1 H[nozzle_diameter];enable tpu, pla and petg clog detect\n{else}\nM1015.3 S0;disable clog detect\n{endif}\n\n{if (filament_type[initial_no_support_extruder] == \"PLA\") || (filament_type[initial_no_support_extruder] == \"PETG\")\n || (filament_type[initial_no_support_extruder] == \"PLA-CF\") || (filament_type[initial_no_support_extruder] == \"PETG-CF\")}\nM1015.4 S1 K1 H[nozzle_diameter] ;enable E air printing detect\n{else}\nM1015.4 S0 K0 H[nozzle_diameter] ;disable E air printing detect\n{endif}\n\nM620.6 I[initial_no_support_extruder] W1 ;enable ams air printing detect\n\nM1010 Q0 B0.023 S0.01\nM1010 Q1 B0.005 S0.01\nM1010.1 S1\n", + "machine_end_gcode": ";======== P2S end gcode ==========\n;===== Based on official 2026/04/01 end gcode =====\nM400 ; wait for buffer to clear\nG92 E0 ; zero the extruder\n\nG90\nG1 Z{max_layer_z + 0.4} F900 ; lower z a little\nM1002 judge_flag timelapse_record_flag\nM622 J1\n G150.3\n M400 ; wait all motion done\n M991 S0 P-1 ;end smooth timelapse at safe pos\n M400 S5 ;wait for last picture to be taken\nM623 ;end of \"timelapse_record_flag\n\nG90\nG1 Z{max_layer_z + 10} F900 ; lower z a little\n\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off remote part cooling fan\nM106 P3 S0 ; turn off chamber cooling fan\nM106 P10 S0 ; turn off left aux fan\n\n; pull back filament to AMS\nM620 S65535\nT65535\nG150.1 F8000\nM621 S65535\n\nG150.3\nM104 S0 ; turn off hotend\nM400 ; wait all motion done\nM17 S\nM17 Z0.4 ; lower z motor current to reduce impact if there is something in the bottom\n{if (80.0 - max_layer_z/2) > 0}\n {if (max_layer_z + 80.0 - max_layer_z/2) < 256}\n G1 Z{max_layer_z + 80.0 - max_layer_z/2} F600\n G1 Z{max_layer_z + 78.0 - max_layer_z/2}\n {else}\n G1 Z256 F600\n G1 Z256\n {endif}\n{else}\n {if (max_layer_z + 4.0) < 256}\n G1 Z{max_layer_z + 4.0} F600\n G1 Z{max_layer_z + 2.0}\n {else}\n G1 Z256 F600\n G1 Z256\n {endif}\n{endif}\nM400 P100\nM17 R ; restore z current\n\n\nM220 S100 ; Reset feedrate magnitude\nM201.2 K1.0 ; Reset acc magnitude\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 0\n\nM1015.3 S0 ;disable clog detect\nM1015.4 S0 K0 ;disable air printing detect\n\n;=====printer finish air purification=========\nM622.1 S0\nM1002 judge_flag print_finish_air_filt_flag\n\n;checks for activate_air_filtration_on_completion and parent flag. If enabled, the override fan speed will be used. Otherwise, the default air purification will kick in.\n\nM622 J1\n{if !activate_air_filtration[current_extruder] || (activate_air_filtration[current_extruder] && !activate_air_filtration_on_completion[current_extruder])}\nM1002 gcode_claim_action : 66\nM145 P1\nM106 P2 S255\nM400 S180\nM106 P2 S0\n{endif}\nM623\n\nM622 J2\n{if !activate_air_filtration[current_extruder] || (activate_air_filtration[current_extruder] && !activate_air_filtration_on_completion[current_extruder])}\nM1002 gcode_claim_action : 66\nM145 P0\nM106 P3 S255\nM400 S180\nM106 P3 S0\n{endif}\nM623\n;=====printer finish air purification=========\n\n;=====printer finish sound=========\nM17\nM400 S1\nM1006 S1\nM1006 A53 B10 L50 C53 D10 M50 E53 F10 N50 \nM1006 A57 B10 L50 C57 D10 M50 E57 F10 N50 \nM1006 A0 B15 L0 C0 D15 M0 E0 F15 N0 \nM1006 A53 B10 L50 C53 D10 M50 E53 F10 N50 \nM1006 A57 B10 L50 C57 D10 M50 E57 F10 N50 \nM1006 A0 B15 L0 C0 D15 M0 E0 F15 N0 \nM1006 A48 B10 L50 C48 D10 M50 E48 F10 N50 \nM1006 A0 B15 L0 C0 D15 M0 E0 F15 N0 \nM1006 A60 B10 L50 C60 D10 M50 E60 F10 N50 \nM1006 W\n;=====printer finish sound=========\nM400\nM18\n", + "layer_change_gcode": ";======== P2S layer_change gcode ==========\n;===== Based on official 2026/04/08 layer change gcode =====\n\n{if (layer_num + 1 == 1)}\n{if (overall_chamber_temperature >= 40)}\n ;not reset filter fan in first layer\n ;not reset fan\n{else}\n{if (min_vitrification_temperature > 50)}\n ;not reset filter fan in first layer\n ;not reset fan\n{endif} \n{endif}\n{endif}\n\n{if (layer_num + 1 <= close_fan_the_first_x_layers[current_extruder])}\n{if (overall_chamber_temperature < 40)}\n {if (min_vitrification_temperature <= 50)}\n M106 P2 S{first_x_layer_fan_speed[current_extruder]*255.0/100.0}\n {endif}\n{endif}\n M622.1 S0\n M1002 judge_flag ventobox_replace_aux1_fan_flag\n M622 J0\n M106 P10 S{first_x_layer_fan_speed[current_extruder]*255.0/100.0}; set first x_layer left aux fan \n M623\n;not reset fan\n{elsif (layer_num + 1 < full_fan_speed_layer[current_extruder] && full_fan_speed_layer[current_extruder] > close_fan_the_first_x_layers[current_extruder])}\n{if (overall_chamber_temperature < 40)}\n {if (min_vitrification_temperature <= 50)}\n M106 P2 S{(first_x_layer_fan_speed[current_extruder] + (additional_cooling_fan_speed[current_extruder] - first_x_layer_fan_speed[current_extruder]) * (layer_num + 1 - close_fan_the_first_x_layers[current_extruder]) / (full_fan_speed_layer[current_extruder] - close_fan_the_first_x_layers[current_extruder])) * 255.0/100.0}\n {endif}\n{endif}\n M622.1 S0\n M1002 judge_flag ventobox_replace_aux1_fan_flag\n M622 J0\n M106 P10 S{(first_x_layer_fan_speed[current_extruder] + (additional_cooling_fan_speed[current_extruder] - first_x_layer_fan_speed[current_extruder]) * (layer_num + 1 - close_fan_the_first_x_layers[current_extruder]) / (full_fan_speed_layer[current_extruder] - close_fan_the_first_x_layers[current_extruder])) * 255.0/100.0}\n M623\n;not reset fan\n{elsif (layer_num + 1 == max(close_fan_the_first_x_layers[current_extruder] + 1, full_fan_speed_layer[current_extruder]))}\n{if (overall_chamber_temperature < 40)}\n ;updata chamber autocooling in Xth layer\n {if (min_vitrification_temperature <= 50)}\n {if (nozzle_diameter == 0.2)}\n M142 P1 R30 S40 U{max_additional_fan/100.0} V1.0 O45; set PLA/TPU ND0.2 chamber autocooling\n {else}\n M142 P1 R30 S40 U{max_additional_fan/100.0} V1.0 O45; set PLA/TPU ND0.4 chamber autocooling\n {endif}\n {else}\n ;not reset filter fan in Xth layer\n {endif}\n{else}\n ;not reset filter fan in Xth layer\n{endif}\n M622.1 S0\n M1002 judge_flag ventobox_replace_aux1_fan_flag\n M622 J0\n M106 P10 S{additional_cooling_fan_speed[current_extruder]*255.0/100.0}; set left aux fan \n M623\n;not reset fan\n{endif}\n\n; update layer progress\nM73 L{layer_num+1}\nM991 S0 P{layer_num} ;notify layer change\n\n", "time_lapse_gcode": ";======== P2S timeslape gcode ==========\n;===== 2025/06/16 ====\n; SKIPPABLE_START\n; SKIPTYPE: timelapse\nM622.1 S1 ; for prev firware, default turned on\n\nM1002 judge_flag timelapse_record_flag\nM622 J1\n{if timelapse_type == 0} ; timelapse without wipe tower\n M971 S11 C10 O0\n M1004 S5 P1 ; external shutter\n{elsif timelapse_type == 1} ; timelapse with wipe tower\n G150.3 ; move to garbage can\n M400\n M1004 S5 P1 ; external shutter\n M400 P300\n M971 S11 C10 O0\n M400 P350\n \n G90\n G1 Z{max_layer_z + 3.0} F1200\n G0 Y210 F18000\n{endif}\nM623\n; SKIPPABLE_END\n", "wrapping_detection_gcode": ";======== P2S 20250822 clumping ========\n{if !spiral_mode}\n M622.1 S0 ; for previous firmware, default turn off\n M1002 set_flag g39_forced_detection_flag=1\n M1002 judge_flag g39_forced_detection_flag\n M622 J1\n {if layer_num == 3 || layer_num == 10 || layer_num == 19}\n M993 A2 B2 C2 ; nozzle cam detection allow status save.\n M993 A0 B0 C0 ; nozzle cam detection not allowed.\n\n M400 P100\n\n G39\n\n G90\n G1 Y240 F30000\n G1 Y210 F15000\n \n M993 A3 B3 C3 ; nozzle cam detection allow status restore.\n {endif}\n M623\n{endif}", - "change_filament_gcode": ";======== P2S filament_change gcode ==========\n;===== Based on official 2026/02/27 filament change gcode =====\n\nM620 S[next_extruder]A\nM204 S9000\n{if toolchange_count > 1 && (z_hop_types[current_extruder] == 0 || z_hop_types[current_extruder] == 3)}\nG17\nG2 Z{z_after_toolchange + 0.4} I0.86 J0.86 P1 F10000 ; spiral lift a little from second lift\n{endif}\n\n;nozzle_change_gcode\n\nG1 Z{max_layer_z + 3.0} F1200\n\nM400\nM106 P1 S0\n\n{if toolchange_count == 2}\n; get travel path for change filament\n;M620.1 X[travel_point_1_x] Y[travel_point_1_y] F21000 P0\n;M620.1 X[travel_point_2_x] Y[travel_point_2_y] F21000 P1\n;M620.1 X[travel_point_3_x] Y[travel_point_3_y] F21000 P2\n{endif}\n\n{if ((filament_type[current_extruder] == \"PLA\") || (filament_type[current_extruder] == \"PLA-CF\") || (filament_type[current_extruder] == \"PETG\")) && (nozzle_diameter[current_extruder] == 0.2)}\nM620.10 A0 F74.8347 L[flush_length] H{nozzle_diameter[current_extruder]} T{flush_temperatures[current_extruder]} P{nozzle_temperature[current_extruder]} S1\n{else}\nM620.10 A0 F{flush_volumetric_speeds[current_extruder]/2.4053*60} L[flush_length] H{nozzle_diameter[current_extruder]} T{flush_temperatures[current_extruder]} P{nozzle_temperature[current_extruder]} S1\n{endif}\n\n{if ((filament_type[next_extruder] == \"PLA\") || (filament_type[next_extruder] == \"PLA-CF\") || (filament_type[next_extruder] == \"PETG\")) && (nozzle_diameter[next_extruder] == 0.2)}\nM620.10 A1 F74.8347 L[flush_length] H{nozzle_diameter[next_extruder]} T{flush_temperatures[next_extruder]} P{nozzle_temperature[next_extruder]} S1\n{else}\nM620.10 A1 F{flush_volumetric_speeds[next_extruder]/2.4053*60} L[flush_length] H{nozzle_diameter[next_extruder]} T{flush_temperatures[next_extruder]} P{nozzle_temperature[next_extruder]} S1\n{endif}\n\n{if long_retraction_when_cut}\nM620.11 P1 L0 I[current_extruder] E-{retraction_distance_when_cut} F{max((flush_volumetric_speeds[current_extruder]/2.4053*60), 200)}\n{else}\nM620.11 P0 L0 I[current_extruder] E0\n{endif}\n\nM620.11 K0 I[current_extruder] R0\n\nT[next_extruder]\n\n;deretract\n{if filament_type[next_extruder] == \"TPU\"}\n{else}\n{if filament_type[next_extruder] == \"PA\"}\n;VG1 E1 F{max(new_filament_e_feedrate, 200)}\n;VG1 E1 F{max(new_filament_e_feedrate/2, 100)}\n{else}\n;VG1 E4 F{max(new_filament_e_feedrate, 200)}\n;VG1 E4 F{max(new_filament_e_feedrate/2, 100)}\n{endif}\n{endif}\n\n; VFLUSH_START\n{if flush_length>41.5}\n;VG1 E41.5 F{min(old_filament_e_feedrate,new_filament_e_feedrate)}\n;VG1 E{flush_length-41.5} F{new_filament_e_feedrate}\n{else}\n;VG1 E{flush_length} F{min(old_filament_e_feedrate,new_filament_e_feedrate)}\n{endif}\nSYNC T{ceil(flush_length / 80) * 5}\n; VFLUSH_END\n\nM1002 set_filament_type:{filament_type[next_extruder]}\n\nM400\nM83\n{if next_extruder < 255}\nM620.10 R{retract_length_toolchange[filament_map[next_extruder]-1]}\nM628 S0\n;VM109 S[new_filament_temp]\nM629\nM400\nM983.3 F{filament_max_volumetric_speed[next_extruder]/2.4} A0.4 R{retract_length_toolchange[filament_map[next_extruder]-1]}\nM400\n\nG1 Z{max_layer_z + 3.0} F3000\n{if layer_z <= (initial_layer_print_height + 0.001)}\nM204 S[initial_layer_acceleration]\n{else}\nM204 S[travel_acceleration]\n{endif}\n\n{else}\nG1 X[x_after_toolchange] Y[y_after_toolchange] Z[z_after_toolchange] F12000\n{endif}\n\nM621 S[next_extruder]A\n\n{if (filament_type[next_extruder] == \"PLA\") || (filament_type[next_extruder] == \"PETG\")\n || (filament_type[next_extruder] == \"PLA-CF\") || (filament_type[next_extruder] == \"PETG-CF\")}\nM1015.4 S1 K1 H[nozzle_diameter] ;enable E air printing detect\n{else}\nM1015.4 S0 K0 H[nozzle_diameter] ;disable E air printing detect\n{endif}\n\nM620.6 I[next_extruder] W1 ;enable ams air printing detect\n\nG1 Y256 F18000\n\n{if (overall_chamber_temperature < 40)}\n{if (layer_num + 1 < close_fan_the_first_x_layers[next_extruder] + 1)}\n{if (min_vitrification_temperature <= 50)}\n M106 P2 S{first_x_layer_fan_speed[next_extruder]*255.0/100.0 };set first x_layer aux fan\n {endif}\n{else}\n {if (min_vitrification_temperature <= 50)}\n {if (nozzle_diameter == 0.2)}\n M142 P1 R30 S40 U{max_additional_fan/100.0} V1.0 O45; set PLA/TPU ND0.2 chamber autocooling\n {else}\n M142 P1 R30 S40 U{max_additional_fan/100.0} V1.0 O45; set PLA/TPU ND0.4 chamber autocooling\n {endif}\n {endif}\n{endif}\n{endif}\n\nM622.1 S0\nM1002 judge_flag ventobox_replace_aux1_fan_flag\nM622 J0\n{if (layer_num + 1 < close_fan_the_first_x_layers[next_extruder] + 1)}\n M106 P10 S{first_x_layer_fan_speed[next_extruder]*255.0/100.0 };set first x_layer left aux fan \n{else}\n M106 P10 S{additional_cooling_fan_speed[next_extruder]*255.0/100.0};set left aux fan\n{endif}\nM623\n\n;not set fan changing filament" + "change_filament_gcode": ";======== P2S filament_change gcode ==========\n;===== Based on official 2026/04/08 filament change gcode =====\n\nM620 S[next_extruder]A\nM204 S9000\n{if toolchange_count > 1 && (z_hop_types[current_extruder] == 0 || z_hop_types[current_extruder] == 3)}\nG17\nG2 Z{z_after_toolchange + 0.4} I0.86 J0.86 P1 F10000 ; spiral lift a little from second lift\n{endif}\n\n;nozzle_change_gcode\n\nG1 Z{max_layer_z + 3.0} F1200\n\nM400\nM106 P1 S0\n\n{if toolchange_count == 2}\n; get travel path for change filament\n;M620.1 X[travel_point_1_x] Y[travel_point_1_y] F21000 P0\n;M620.1 X[travel_point_2_x] Y[travel_point_2_y] F21000 P1\n;M620.1 X[travel_point_3_x] Y[travel_point_3_y] F21000 P2\n{endif}\n\n{if ((filament_type[current_extruder] == \"PLA\") || (filament_type[current_extruder] == \"PLA-CF\") || (filament_type[current_extruder] == \"PETG\")) && (nozzle_diameter[current_extruder] == 0.2)}\nM620.10 A0 F74.8347 L[flush_length] H{nozzle_diameter[current_extruder]} T{flush_temperatures[current_extruder]} P{nozzle_temperature[current_extruder]} S1\n{else}\nM620.10 A0 F{flush_volumetric_speeds[current_extruder]/2.4053*60} L[flush_length] H{nozzle_diameter[current_extruder]} T{flush_temperatures[current_extruder]} P{nozzle_temperature[current_extruder]} S1\n{endif}\n\n{if ((filament_type[next_extruder] == \"PLA\") || (filament_type[next_extruder] == \"PLA-CF\") || (filament_type[next_extruder] == \"PETG\")) && (nozzle_diameter[next_extruder] == 0.2)}\nM620.10 A1 F74.8347 L[flush_length] H{nozzle_diameter[next_extruder]} T{flush_temperatures[next_extruder]} P{nozzle_temperature[next_extruder]} S1\n{else}\nM620.10 A1 F{flush_volumetric_speeds[next_extruder]/2.4053*60} L[flush_length] H{nozzle_diameter[next_extruder]} T{flush_temperatures[next_extruder]} P{nozzle_temperature[next_extruder]} S1\n{endif}\n\n{if long_retraction_when_cut}\nM620.11 P1 L0 I[current_extruder] E-{retraction_distance_when_cut} F{max((flush_volumetric_speeds[current_extruder]/2.4053*60), 200)}\n{else}\nM620.11 P0 L0 I[current_extruder] E0\n{endif}\n\nM620.11 K0 I[current_extruder] R0\n\n \nT[next_extruder]\n\n;deretract\n{if filament_type[next_extruder] == \"TPU\"}\n{else}\n{if filament_type[next_extruder] == \"PA\"}\n;VG1 E1 F{max(new_filament_e_feedrate, 200)}\n;VG1 E1 F{max(new_filament_e_feedrate/2, 100)}\n{else}\n;VG1 E4 F{max(new_filament_e_feedrate, 200)}\n;VG1 E4 F{max(new_filament_e_feedrate/2, 100)}\n{endif}\n{endif}\n\n; VFLUSH_START\n{if flush_length>41.5}\n;VG1 E41.5 F{min(old_filament_e_feedrate,new_filament_e_feedrate)}\n;VG1 E{flush_length-41.5} F{new_filament_e_feedrate}\n{else}\n;VG1 E{flush_length} F{min(old_filament_e_feedrate,new_filament_e_feedrate)}\n{endif}\nSYNC T{ceil(flush_length / 80) * 5}\n; VFLUSH_END\n\nM1002 set_filament_type:{filament_type[next_extruder]}\n\nM400\nM83\n{if next_extruder < 255}\nM620.10 R{retract_length_toolchange[filament_map[next_extruder]-1]}\nM628 S0\n;VM109 S[new_filament_temp]\n\nM629\nM400\nM983.3 F{filament_max_volumetric_speed[next_extruder]/2.4} A0.4 R{retract_length_toolchange[filament_map[next_extruder]-1]}\nM400\n\nG1 Z{max_layer_z + 3.0} F3000\n{if layer_z <= (initial_layer_print_height + 0.001)}\nM204 S[initial_layer_acceleration]\n{else}\nM204 S[travel_acceleration]\n{endif}\n\n{else}\nG1 X[x_after_toolchange] Y[y_after_toolchange] Z[z_after_toolchange] F12000\n{endif}\n\nM621 S[next_extruder]A\n\nM622.1 S0 ;for prev version, default skip\nM1002 judge_flag powerloss_resume_flag\nM622 J1\nM983.3 F{filament_max_volumetric_speed[next_extruder]/2.4} A0.4 R{retract_length_toolchange[filament_map[next_extruder]-1]}\nM400\nG1 Z{max_layer_z + 3.0} F3000\n{if layer_z <= (initial_layer_print_height + 0.001)}\nM204 S[initial_layer_acceleration]\n{else}\nM204 S[travel_acceleration]\n{endif}\nM1002 set_flag powerloss_resume_flag=0\nM623\n\n{if (filament_type[next_extruder] == \"PLA\") || (filament_type[next_extruder] == \"PETG\")\n || (filament_type[next_extruder] == \"PLA-CF\") || (filament_type[next_extruder] == \"PETG-CF\")}\nM1015.4 S1 K1 H[nozzle_diameter] ;enable E air printing detect\n{else}\nM1015.4 S0 K0 H[nozzle_diameter] ;disable E air printing detect\n{endif}\n\nM620.6 I[next_extruder] W1 ;enable ams air printing detect\n\nG1 Y256 F18000\n\n{if (overall_chamber_temperature < 40)}\n{if (layer_num + 1 <= close_fan_the_first_x_layers[next_extruder])}\n {if (min_vitrification_temperature <= 50)}\n M106 P2 S{first_x_layer_fan_speed[next_extruder]*255.0/100.0 };set first x_layer aux fan\n {endif}\n{elsif (layer_num + 1 < full_fan_speed_layer[next_extruder] && full_fan_speed_layer[next_extruder] > close_fan_the_first_x_layers[next_extruder])}\n {if (min_vitrification_temperature <= 50)}\n M106 P2 S{(first_x_layer_fan_speed[next_extruder] + (additional_cooling_fan_speed[next_extruder] - first_x_layer_fan_speed[next_extruder]) * (layer_num + 1 - close_fan_the_first_x_layers[next_extruder]) / (full_fan_speed_layer[next_extruder] - close_fan_the_first_x_layers[next_extruder])) * 255.0/100.0}\n {endif}\n{else}\n {if (min_vitrification_temperature <= 50)}\n {if (nozzle_diameter == 0.2)}\n M142 P1 R30 S40 U{max_additional_fan/100.0} V1.0 O45; set PLA/TPU ND0.2 chamber autocooling\n {else}\n M142 P1 R30 S40 U{max_additional_fan/100.0} V1.0 O45; set PLA/TPU ND0.4 chamber autocooling\n {endif}\n {endif}\n{endif}\n{endif}\n\nM622.1 S0\nM1002 judge_flag ventobox_replace_aux1_fan_flag\nM622 J0\n{if (layer_num + 1 <= close_fan_the_first_x_layers[next_extruder])}\n M106 P10 S{first_x_layer_fan_speed[next_extruder]*255.0/100.0 };set first x_layer left aux fan \n{elsif (layer_num + 1 < full_fan_speed_layer[next_extruder] && full_fan_speed_layer[next_extruder] > close_fan_the_first_x_layers[next_extruder])}\n M106 P10 S{(first_x_layer_fan_speed[next_extruder] + (additional_cooling_fan_speed[next_extruder] - first_x_layer_fan_speed[next_extruder]) * (layer_num + 1 - close_fan_the_first_x_layers[next_extruder]) / (full_fan_speed_layer[next_extruder] - close_fan_the_first_x_layers[next_extruder])) * 255.0/100.0}\n{else}\n M106 P10 S{additional_cooling_fan_speed[next_extruder]*255.0/100.0};set left aux fan\n{endif}\nM623\n\n;not set fan changing filament" } diff --git a/resources/profiles/BBL/process/0.08mm High Quality @BBL P2S 0.2 nozzle.json b/resources/profiles/BBL/process/0.08mm High Quality @BBL P2S 0.2 nozzle.json index d918d41bea..ef8582cf08 100644 --- a/resources/profiles/BBL/process/0.08mm High Quality @BBL P2S 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.08mm High Quality @BBL P2S 0.2 nozzle.json @@ -11,6 +11,7 @@ "50", "50" ], + "enable_arc_fitting": "0", "default_acceleration": [ "4000", "4000" diff --git a/resources/profiles/BBL/process/0.08mm High Quality @BBL P2S.json b/resources/profiles/BBL/process/0.08mm High Quality @BBL P2S.json index c6731a7178..33bcdcb417 100644 --- a/resources/profiles/BBL/process/0.08mm High Quality @BBL P2S.json +++ b/resources/profiles/BBL/process/0.08mm High Quality @BBL P2S.json @@ -10,6 +10,7 @@ "50", "50" ], + "enable_arc_fitting": "0", "default_acceleration": [ "4000", "4000" diff --git a/resources/profiles/BBL/process/0.10mm Standard @BBL P2S 0.2 nozzle.json b/resources/profiles/BBL/process/0.10mm Standard @BBL P2S 0.2 nozzle.json index 12c99abbeb..8d545a01f4 100644 --- a/resources/profiles/BBL/process/0.10mm Standard @BBL P2S 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.10mm Standard @BBL P2S 0.2 nozzle.json @@ -10,6 +10,7 @@ "50", "50" ], + "enable_arc_fitting": "0", "default_acceleration": [ "4000", "4000" diff --git a/resources/profiles/BBL/process/0.12mm Balanced Quality @BBL P2S 0.2 nozzle.json b/resources/profiles/BBL/process/0.12mm Balanced Quality @BBL P2S 0.2 nozzle.json index caeefe5f36..e1b48ac5b8 100644 --- a/resources/profiles/BBL/process/0.12mm Balanced Quality @BBL P2S 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.12mm Balanced Quality @BBL P2S 0.2 nozzle.json @@ -10,6 +10,7 @@ "50", "50" ], + "enable_arc_fitting": "0", "default_acceleration": [ "4000", "4000" diff --git a/resources/profiles/BBL/process/0.12mm High Quality @BBL P2S.json b/resources/profiles/BBL/process/0.12mm High Quality @BBL P2S.json index 547fe83248..d1464e4305 100644 --- a/resources/profiles/BBL/process/0.12mm High Quality @BBL P2S.json +++ b/resources/profiles/BBL/process/0.12mm High Quality @BBL P2S.json @@ -10,6 +10,7 @@ "50", "50" ], + "enable_arc_fitting": "0", "default_acceleration": [ "4000", "4000" diff --git a/resources/profiles/BBL/process/0.16mm High Quality @BBL P2S.json b/resources/profiles/BBL/process/0.16mm High Quality @BBL P2S.json index 3c76d25250..e8c99baf95 100644 --- a/resources/profiles/BBL/process/0.16mm High Quality @BBL P2S.json +++ b/resources/profiles/BBL/process/0.16mm High Quality @BBL P2S.json @@ -11,6 +11,7 @@ "50", "50" ], + "enable_arc_fitting": "0", "default_acceleration": [ "4000", "4000" diff --git a/resources/profiles/BBL/process/0.16mm Standard @BBL P2S.json b/resources/profiles/BBL/process/0.16mm Standard @BBL P2S.json index 840c7fc2fe..3936f388e6 100644 --- a/resources/profiles/BBL/process/0.16mm Standard @BBL P2S.json +++ b/resources/profiles/BBL/process/0.16mm Standard @BBL P2S.json @@ -11,6 +11,7 @@ "50", "50" ], + "enable_arc_fitting": "0", "default_acceleration": [ "10000", "10000" diff --git a/resources/profiles/BBL/process/0.18mm Balanced Quality @BBL P2S 0.6 nozzle.json b/resources/profiles/BBL/process/0.18mm Balanced Quality @BBL P2S 0.6 nozzle.json index f5839097a1..1357450ea1 100644 --- a/resources/profiles/BBL/process/0.18mm Balanced Quality @BBL P2S 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.18mm Balanced Quality @BBL P2S 0.6 nozzle.json @@ -11,6 +11,7 @@ "30", "30" ], + "enable_arc_fitting": "0", "default_acceleration": [ "10000", "10000" diff --git a/resources/profiles/BBL/process/0.20mm High Quality @BBL P2S.json b/resources/profiles/BBL/process/0.20mm High Quality @BBL P2S.json index 952481c1cd..fc29792372 100644 --- a/resources/profiles/BBL/process/0.20mm High Quality @BBL P2S.json +++ b/resources/profiles/BBL/process/0.20mm High Quality @BBL P2S.json @@ -11,6 +11,7 @@ "50", "50" ], + "enable_arc_fitting": "0", "default_acceleration": [ "4000", "4000" diff --git a/resources/profiles/BBL/process/0.20mm Standard @BBL P2S.json b/resources/profiles/BBL/process/0.20mm Standard @BBL P2S.json index e2509d6a9f..2c4de0d7bc 100644 --- a/resources/profiles/BBL/process/0.20mm Standard @BBL P2S.json +++ b/resources/profiles/BBL/process/0.20mm Standard @BBL P2S.json @@ -11,6 +11,7 @@ "50", "50" ], + "enable_arc_fitting": "0", "default_acceleration": [ "10000", "10000" diff --git a/resources/profiles/BBL/process/0.24mm Balanced Quality @BBL P2S 0.6 nozzle.json b/resources/profiles/BBL/process/0.24mm Balanced Quality @BBL P2S 0.6 nozzle.json index 07970aba83..7b7f633040 100644 --- a/resources/profiles/BBL/process/0.24mm Balanced Quality @BBL P2S 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.24mm Balanced Quality @BBL P2S 0.6 nozzle.json @@ -11,6 +11,7 @@ "30", "30" ], + "enable_arc_fitting": "0", "default_acceleration": [ "10000", "10000" diff --git a/resources/profiles/BBL/process/0.24mm Balanced Quality @BBL P2S 0.8 nozzle.json b/resources/profiles/BBL/process/0.24mm Balanced Quality @BBL P2S 0.8 nozzle.json index 5cad977499..4a303b27d9 100644 --- a/resources/profiles/BBL/process/0.24mm Balanced Quality @BBL P2S 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.24mm Balanced Quality @BBL P2S 0.8 nozzle.json @@ -11,6 +11,7 @@ "30", "30" ], + "enable_arc_fitting": "0", "default_acceleration": [ "10000", "10000" diff --git a/resources/profiles/BBL/process/0.24mm Standard @BBL P2S.json b/resources/profiles/BBL/process/0.24mm Standard @BBL P2S.json index db7ea35de0..a6dae0a6dd 100644 --- a/resources/profiles/BBL/process/0.24mm Standard @BBL P2S.json +++ b/resources/profiles/BBL/process/0.24mm Standard @BBL P2S.json @@ -10,6 +10,7 @@ "50", "50" ], + "enable_arc_fitting": "0", "default_acceleration": [ "10000", "10000" diff --git a/resources/profiles/BBL/process/0.30mm Standard @BBL P2S 0.6 nozzle.json b/resources/profiles/BBL/process/0.30mm Standard @BBL P2S 0.6 nozzle.json index c3b576306a..9f4c86e17a 100644 --- a/resources/profiles/BBL/process/0.30mm Standard @BBL P2S 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.30mm Standard @BBL P2S 0.6 nozzle.json @@ -11,6 +11,7 @@ "30", "30" ], + "enable_arc_fitting": "0", "default_acceleration": [ "10000", "10000" diff --git a/resources/profiles/BBL/process/0.32mm Balanced Quality @BBL P2S 0.8 nozzle.json b/resources/profiles/BBL/process/0.32mm Balanced Quality @BBL P2S 0.8 nozzle.json index bb8ac922c0..ffa69df36b 100644 --- a/resources/profiles/BBL/process/0.32mm Balanced Quality @BBL P2S 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.32mm Balanced Quality @BBL P2S 0.8 nozzle.json @@ -11,6 +11,7 @@ "30", "30" ], + "enable_arc_fitting": "0", "default_acceleration": [ "10000", "10000" diff --git a/resources/profiles/BBL/process/0.40mm Standard @BBL P2S 0.8 nozzle.json b/resources/profiles/BBL/process/0.40mm Standard @BBL P2S 0.8 nozzle.json index 22c58ba46e..e1fe009797 100644 --- a/resources/profiles/BBL/process/0.40mm Standard @BBL P2S 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.40mm Standard @BBL P2S 0.8 nozzle.json @@ -11,6 +11,7 @@ "30", "30" ], + "enable_arc_fitting": "0", "default_acceleration": [ "10000", "10000" From cb033455faca7783360459ebaf3a7dcc82531800 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sat, 9 May 2026 02:35:50 +0800 Subject: [PATCH 33/44] improve log --- src/libslic3r/AppConfig.cpp | 2 +- src/libslic3r/utils.cpp | 8 ++++++++ src/slic3r/GUI/GUI_App.cpp | 6 +++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index 6da825b090..49afa106be 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -299,7 +299,7 @@ void AppConfig::set_defaults() set_bool("enable_ssl_for_ftp", true); if (get("log_severity_level").empty()) - set("log_severity_level", "warning"); + set("log_severity_level", "info"); if (get("internal_developer_mode").empty()) set_bool("internal_developer_mode", false); diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 0ec3e5f503..1fb73d4b00 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -114,6 +114,14 @@ void set_logging_level(unsigned int level) { logSeverity = level_to_boost(level); + // Force at debug level logging for pre-release builds. + const std::string version = SoftFever_VERSION; + if (boost::algorithm::icontains(version, "dev") || + boost::algorithm::icontains(version, "alpha") || + boost::algorithm::icontains(version, "beta")) { + logSeverity = boost::log::trivial::debug; + } + boost::log::core::get()->set_filter ( boost::log::trivial::severity >= logSeverity diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 1546f09fbc..1b677df488 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -5807,12 +5807,16 @@ bool GUI_App::maybe_migrate_user_presets_on_login() { namespace fs = boost::filesystem; + BOOST_LOG_TRIVIAL(info) << "Migrate user presets to the OrcaCloud user folder if needed."; + if (!m_agent || !m_agent->is_user_login()) return false; std::string new_user_id = m_agent->get_user_id(); - if (new_user_id.empty()) + if (new_user_id.empty()) { + BOOST_LOG_TRIVIAL(warning) << "Failed to get user ID, skipping migration."; return false; + } fs::path user_base = fs::path(data_dir()) / PRESET_USER_DIR; fs::path target_dir = user_base / new_user_id; From 1411f954348b244eac41ae386c2fcd819626e0e3 Mon Sep 17 00:00:00 2001 From: Ian Bassi Date: Fri, 8 May 2026 15:42:38 -0300 Subject: [PATCH 34/44] Add wiki link to transfer settings (#13534) --- src/slic3r/GUI/UnsavedChangesDialog.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index 53ce5e1318..85e3261afa 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -25,6 +25,7 @@ #include "Widgets/RoundedRectangle.hpp" #include "Widgets/CheckBox.hpp" #include "Widgets/DialogButtons.hpp" +#include "Widgets/HyperLink.hpp" using boost::optional; @@ -959,6 +960,11 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection *dependent_ m_sizer_button->Add(checkbox_sizer, 0, wxLEFT, FromDIP(22)); checkbox_sizer->Show(bool(m_buttons & REMEMBER_CHOISE)); + if (dependent_presets != nullptr) { + auto wiki = new HyperLink(this, _L("Help"), "https://www.orcaslicer.com/wiki/transfer_discard_changes"); + m_sizer_button->Add(wiki, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, FromDIP(22)); + } + m_sizer_button->Add(0, 0, 1, 0, 0); // Add Buttons From 7aed2dc8bd32595acec36c3e7880f5e2ec5dc0aa Mon Sep 17 00:00:00 2001 From: Clifford Date: Fri, 8 May 2026 15:03:39 -0400 Subject: [PATCH 35/44] fix(preset): don't truncate child variant vectors to parent size on load (#13316) Co-authored-by: Claude Opus 4.7 --- src/libslic3r/PrintConfig.cpp | 7 +++++ tests/libslic3r/test_config.cpp | 50 +++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index ac22ab89cc..9a1a794f2a 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -9641,6 +9641,13 @@ void DynamicPrintConfig::update_non_diff_values_to_base_config(DynamicPrintConfi //nothing to do, keep the original one } else { + // Guard: set_with_restore is parent-shaped and would truncate the child's + // vector when the child has more extruders than the parent (e.g. an IDEX + // preset inheriting from a single-nozzle base). The child's saved value is + // authoritative for its own extruder count, so skip the merge for this key. + if (cur_variant_count > target_variant_count) + continue; + int stride = 1; if (key_set2.find(opt) != key_set2.end()) stride = 2; diff --git a/tests/libslic3r/test_config.cpp b/tests/libslic3r/test_config.cpp index 5591842c64..2bee0d7d11 100644 --- a/tests/libslic3r/test_config.cpp +++ b/tests/libslic3r/test_config.cpp @@ -265,6 +265,56 @@ SCENARIO("DynamicPrintConfig serialization", "[Config]") { } } +SCENARIO("update_non_diff_values_to_base_config preserves child vectors when child has more extruders than parent", + "[Config][Variant]") { + GIVEN("A 2-extruder child printer config inheriting from a 1-extruder parent") { + Slic3r::DynamicPrintConfig child; + Slic3r::DynamicPrintConfig parent; + + child.set_key_value("nozzle_diameter", new Slic3r::ConfigOptionFloats({0.4, 0.4})); + child.set_key_value("printer_extruder_id", new Slic3r::ConfigOptionInts({1, 2})); + child.set_key_value("printer_extruder_variant", new Slic3r::ConfigOptionStrings({"Direct Drive Standard", "Direct Drive Standard"})); + child.set_key_value("retraction_length", new Slic3r::ConfigOptionFloats({1.5, 1.5})); + + parent.set_key_value("nozzle_diameter", new Slic3r::ConfigOptionFloats({0.4})); + parent.set_key_value("printer_extruder_id", new Slic3r::ConfigOptionInts({1})); + parent.set_key_value("printer_extruder_variant", new Slic3r::ConfigOptionStrings({"Direct Drive Standard"})); + parent.set_key_value("retraction_length", new Slic3r::ConfigOptionFloats({0.8})); + + const Slic3r::t_config_option_keys keys = { + "retraction_length", "printer_extruder_id", "printer_extruder_variant" + }; + const std::set different_keys = { + "retraction_length", "printer_extruder_id", "printer_extruder_variant" + }; + + WHEN("update_non_diff_values_to_base_config is called") { + std::string id_name = "printer_extruder_id"; + std::string var_name = "printer_extruder_variant"; + child.update_non_diff_values_to_base_config( + parent, keys, different_keys, id_name, var_name, + Slic3r::printer_options_with_variant_1, + Slic3r::printer_options_with_variant_2); + + THEN("printer_extruder_id retains size 2") { + REQUIRE(child.option("printer_extruder_id")->values.size() == 2); + } + THEN("printer_extruder_variant retains size 2") { + REQUIRE(child.option("printer_extruder_variant")->values.size() == 2); + } + THEN("retraction_length retains size 2") { + REQUIRE(child.option("retraction_length")->values.size() == 2); + } + THEN("printer_extruder_id values are preserved for both extruders") { + auto* pe_id = child.option("printer_extruder_id"); + REQUIRE(pe_id->values.size() == 2); + REQUIRE(pe_id->values[0] == 1); + REQUIRE(pe_id->values[1] == 2); + } + } + } +} + // SCENARIO("DynamicPrintConfig JSON serialization", "[Config]") { // WHEN("DynamicPrintConfig is serialized and deserialized") { // auto now = std::chrono::high_resolution_clock::now(); From a29d4fc495101b36654e65c416805ff06ef4df7d Mon Sep 17 00:00:00 2001 From: yw4z Date: Sat, 9 May 2026 08:11:26 +0300 Subject: [PATCH 36/44] Crash fix assembly mode flatpak (#13413) * Update GLCanvas3D.cpp * Update GLCanvas3D.cpp * update * Update GLCanvas3D.cpp Co-Authored-By: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> --------- Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> --- src/slic3r/GUI/GLCanvas3D.cpp | 27 ++++++++++++++++++++------- src/slic3r/GUI/Plater.cpp | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 5457452189..ba4f06e8f2 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1920,6 +1920,14 @@ void GLCanvas3D::render(bool only_init) if (!is_initialized() && !init()) return; + + // If a scene reload was postponed while the canvas was hidden, consume it on first visible render. + if (m_reload_delayed) { + reload_scene(true); + if (m_reload_delayed) + return; + } + if (m_canvas_type == ECanvasType::CanvasView3D && m_gizmos.get_current_type() == GLGizmosManager::Undefined) { enable_return_toolbar(false); } @@ -2398,10 +2406,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (m_canvas == nullptr || m_config == nullptr || m_model == nullptr) return; - if (!m_initialized) + if (!m_initialized || !_set_current()) { + m_reload_delayed = true; + set_as_dirty(); return; - - _set_current(); + } m_hover_volume_idxs.clear(); @@ -2456,6 +2465,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re auto model_volume_state_lower = [](const ModelVolumeState& m1, const ModelVolumeState& m2) { return m1.geometry_id < m2.geometry_id; }; m_reload_delayed = !m_canvas->IsShown() && !refresh_immediately && !force_full_scene_refresh; + if (m_reload_delayed) { + set_as_dirty(); + return; + } PrinterTechnology printer_technology = current_printer_technology(); @@ -2617,9 +2630,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re //BBS clean hover_volume_idxs m_hover_volume_idxs.clear(); - if (m_reload_delayed) - return; - // BBS: do not check wipe tower changes bool update_object_list = false; if (deleted_volumes.size() != deleted_wipe_towers.size()) @@ -3897,7 +3907,7 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) if (m_gizmos.on_mouse_wheel(evt)) return; - if (m_canvas_type == CanvasAssembleView && (evt.AltDown() || evt.CmdDown())) { + if (m_canvas_type == CanvasAssembleView && (evt.AltDown() || evt.CmdDown()) && m_gizmos.m_assemble_view_data != nullptr) { float rotation = (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta(); if (evt.AltDown()) { auto clp_dist = m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position(); @@ -8915,6 +8925,9 @@ float GLCanvas3D::_render_assembly_tooltip_button(ImGuiWrapper* imgui_wrapper) c //BBS void GLCanvas3D::_render_assemble_control() { + if(m_gizmos.m_assemble_view_data == nullptr) + return; + if (m_canvas_type != ECanvasType::CanvasAssembleView) { GLVolume::explosion_ratio = m_explosion_ratio = 1.0; return; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ec74a796e4..31ec92bfc0 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -6923,6 +6923,12 @@ std::vector Plater::priv::load_files(const std::vector& input_ } if (load_model) { + if (!q->m_exported_file && view3D != nullptr) { + // Force a 3D scene refresh after view/plate selection to avoid losing the first load + // on platforms where the GL canvas mapping lags behind model loading. + view3D->reload_scene(true); + view3D->set_as_dirty(); + } if (!silence) wxGetApp().app_config->update_skein_dir(input_files[input_files.size() - 1].parent_path().make_preferred().string()); // XXX: Plater.pm had @loaded_files, but didn't seem to fill them with the filenames... } @@ -9130,6 +9136,20 @@ void Plater::priv::set_current_panel(wxPanel* panel, bool no_slice) if (current_panel == panel) { + if (panel == view3D) { + if (view3D->is_reload_delayed()) { + // Delayed loading of the 3D scene when caller requests the already active tab. + if (printer_technology == ptSLA) + update_restart_background_process(true, false); + else + view3D->reload_scene(true); + } + + view3D->set_as_dirty(); + view3D->get_canvas3d()->reset_old_size(); + if (notification_manager != nullptr) + notification_manager->set_in_preview(false); + } //BBS: add slice logic when switch to preview page //BBS: add only gcode mode if (!q->only_gcode_mode() && (current_panel == preview) && (wxGetApp().is_editor())) { From fb1f4a7d24ee56670d676b6844c5a6704510ff75 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 9 May 2026 13:14:27 +0800 Subject: [PATCH 37/44] Automatically select external spool if it's the only installed filament (#13356) * Clean up code * Filament mapping select ext slot automatically when no AMS filament inserted (OrcaSlicer/OrcaSlicer#13103) * Show warning if external filament type does not match the one in sliced file --- src/slic3r/GUI/DeviceCore/DevMapping.cpp | 21 +++++++++++ src/slic3r/GUI/DeviceManager.hpp | 1 - src/slic3r/GUI/PrePrintChecker.cpp | 2 ++ src/slic3r/GUI/PrePrintChecker.hpp | 1 + src/slic3r/GUI/SelectMachine.cpp | 44 ++++++++++++++---------- src/slic3r/GUI/SelectMachine.hpp | 4 +-- src/slic3r/GUI/SyncAmsInfoDialog.cpp | 13 +++---- 7 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/slic3r/GUI/DeviceCore/DevMapping.cpp b/src/slic3r/GUI/DeviceCore/DevMapping.cpp index e655f12db7..af3539f372 100644 --- a/src/slic3r/GUI/DeviceCore/DevMapping.cpp +++ b/src/slic3r/GUI/DeviceCore/DevMapping.cpp @@ -354,6 +354,27 @@ namespace Slic3r } } + // Orca: special cases that no AMS available, we select ext slot automatically because we don't have other choice anyway + if (tray_filaments.size() == 1 && devPrinterUtil::IsVirtualSlot(tray_filaments.begin()->first)) { + auto ext_tray = tray_filaments.begin(); + for (auto & r : result) { + if (r.tray_id < 0) { + r.tray_id = ext_tray->first; + + r.color = ext_tray->second.color; + r.type = ext_tray->second.type; + r.distance = ext_tray->second.distance; + r.filament_id = ext_tray->second.filament_id; + r.ctype = ext_tray->second.ctype; + r.colors = ext_tray->second.colors; + + /*for new ams mapping*/ + r.ams_id = ext_tray->second.ams_id; + r.slot_id = ext_tray->second.slot_id; + } + } + } + //check ams mapping result if (DevMappingUtil::is_valid_mapping_result(obj, result, true)) { diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 5454c62ca9..99e903dded 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -291,7 +291,6 @@ public: bool is_target_slot_unload() const; bool can_unload_filament(); - bool is_support_amx_ext_mix_mapping() const { return true;} void get_ams_colors(std::vector& ams_colors); diff --git a/src/slic3r/GUI/PrePrintChecker.cpp b/src/slic3r/GUI/PrePrintChecker.cpp index ef9c1447bb..7f21bc90a9 100644 --- a/src/slic3r/GUI/PrePrintChecker.cpp +++ b/src/slic3r/GUI/PrePrintChecker.cpp @@ -53,6 +53,7 @@ std::string PrePrintChecker::get_print_status_info(PrintDialogStatus status) case PrintStatusFilamentWarningHighChamberTempCloseDoor: return "PrintStatusFilamentWarningHighChamberTempCloseDoor"; case PrintStatusFilamentWarningHighChamberTempSoft: return "PrintStatusFilamentWarningHighChamberTempSoft"; case PrintStatusFilamentWarningUnknownHighChamberTempSoft: return "PrintStatusFilamentWarningUnknownHighChamberTempSoft"; + case PrintStatusWarningExtFilamentNotMatch: return "PrintStatusWarningExtFilamentNotMatch"; case PrintStatusReadingFinished: return "PrintStatusReadingFinished"; case PrintStatusSendingCanceled: return "PrintStatusSendingCanceled"; case PrintStatusAmsMappingSuccess: return "PrintStatusAmsMappingSuccess"; @@ -92,6 +93,7 @@ wxString PrePrintChecker::get_pre_state_msg(PrintDialogStatus status) case PrintStatusWarningKvalueNotUsed: return _L("Set dynamic flow calibration to 'OFF' to enable custom dynamic flow value."); case PrintStatusNotSupportedPrintAll: return _L("This printer does not support printing all plates."); case PrintStatusColorQuantityExceed: return _L("The current firmware supports a maximum of 16 materials. You can either reduce the number of materials to 16 or fewer on the Preparation Page, or try updating the firmware. If you are still restricted after the update, please wait for subsequent firmware support."); + case PrintStatusWarningExtFilamentNotMatch: return _L("The type of external filament is unknown or does not match with the filament type in the slicing file. Please make sure you have installed the correct filament in the external spool."); } return wxEmptyString; } diff --git a/src/slic3r/GUI/PrePrintChecker.hpp b/src/slic3r/GUI/PrePrintChecker.hpp index feac610628..8e4d4ed3f4 100644 --- a/src/slic3r/GUI/PrePrintChecker.hpp +++ b/src/slic3r/GUI/PrePrintChecker.hpp @@ -99,6 +99,7 @@ enum PrintDialogStatus : unsigned int { PrintStatusFilamentWarningHighChamberTempCloseDoor, PrintStatusFilamentWarningHighChamberTempSoft, PrintStatusFilamentWarningUnknownHighChamberTempSoft, + PrintStatusWarningExtFilamentNotMatch, PrintStatusFilamentWarningEnd, PrintStatusWarningEnd,//->end error<- diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 59c9956bd9..1d88bbc235 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -1092,23 +1092,13 @@ bool SelectMachineDialog::do_ams_mapping(MachineObject *obj_,bool use_ams) //single nozzle else { - if (obj_->is_support_amx_ext_mix_mapping()){ - map_opt = { false, true, false, false }; //four values: use_left_ams, use_right_ams, use_left_ext, use_right_ext - if (!use_ams) { - map_opt[1] = false; - map_opt[3] = true; - } - filament_result = DevMappingUtil::ams_filament_mapping(obj_, m_filaments, m_ams_mapping_result, map_opt); - //auto_supply_with_ext(obj_->vt_slot); - } - else { - map_opt = { false, true, false, false }; - if (!use_ams) { - map_opt[1] = false; - map_opt[3] = true; - } - filament_result = DevMappingUtil::ams_filament_mapping(obj_, m_filaments, m_ams_mapping_result, map_opt); + map_opt = { false, true, false, false }; //four values: use_left_ams, use_right_ams, use_left_ext, use_right_ext + if (!use_ams) { + map_opt[1] = false; + map_opt[3] = true; } + filament_result = DevMappingUtil::ams_filament_mapping(obj_, m_filaments, m_ams_mapping_result, map_opt); + //auto_supply_with_ext(obj_->vt_slot); } if (filament_result == 0) { @@ -1147,7 +1137,7 @@ bool SelectMachineDialog::do_ams_mapping(MachineObject *obj_,bool use_ams) return true; } -bool SelectMachineDialog::get_ams_mapping_result(std::string &mapping_array_str, std::string& mapping_array_str2, std::string &ams_mapping_info) +bool SelectMachineDialog::get_ams_mapping_result(std::string &mapping_array_str, std::string& mapping_array_str2, std::string &ams_mapping_info) const { if (m_ams_mapping_result.empty()) return false; @@ -1438,7 +1428,7 @@ bool SelectMachineDialog::is_nozzle_type_match(DevExtderSystem data, wxString& e return true; } -int SelectMachineDialog::convert_filament_map_nozzle_id_to_task_nozzle_id(int nozzle_id) +int SelectMachineDialog::convert_filament_map_nozzle_id_to_task_nozzle_id(int nozzle_id) const { if (nozzle_id == (int)FilamentMapNozzleId::NOZZLE_LEFT) { return (int)CloudTaskNozzleId::NOZZLE_LEFT; @@ -1691,6 +1681,9 @@ void SelectMachineDialog::show_status(PrintDialogStatus status, std::vectorIsShown() && m_checkbox_list["flow_cali"]->getValue() == "auto") { const auto ¬_default_ams_names = _check_kval_not_default(obj_, m_ams_mapping_result); diff --git a/src/slic3r/GUI/SelectMachine.hpp b/src/slic3r/GUI/SelectMachine.hpp index 302b37b553..f0e135f33e 100644 --- a/src/slic3r/GUI/SelectMachine.hpp +++ b/src/slic3r/GUI/SelectMachine.hpp @@ -500,12 +500,12 @@ public: bool Show(bool show); void show_init(); bool do_ams_mapping(MachineObject *obj_,bool use_ams); - bool get_ams_mapping_result(std::string& mapping_array_str, std::string& mapping_array_str2, std::string& ams_mapping_info); + bool get_ams_mapping_result(std::string& mapping_array_str, std::string& mapping_array_str2, std::string& ams_mapping_info) const; bool build_nozzles_info(std::string& nozzles_info); bool can_hybrid_mapping(DevExtderSystem data); void auto_supply_with_ext(std::vector slots); bool is_nozzle_type_match(DevExtderSystem data, wxString& error_message) const; - int convert_filament_map_nozzle_id_to_task_nozzle_id(int nozzle_id); + int convert_filament_map_nozzle_id_to_task_nozzle_id(int nozzle_id) const; PrintFromType get_print_type() {return m_print_type;}; wxString format_steel_name(NozzleType type); diff --git a/src/slic3r/GUI/SyncAmsInfoDialog.cpp b/src/slic3r/GUI/SyncAmsInfoDialog.cpp index 4056d48fe5..bfb1e931be 100644 --- a/src/slic3r/GUI/SyncAmsInfoDialog.cpp +++ b/src/slic3r/GUI/SyncAmsInfoDialog.cpp @@ -1261,15 +1261,10 @@ bool SyncAmsInfoDialog::do_ams_mapping(MachineObject *obj_) } // single nozzle else { - if (obj_->is_support_amx_ext_mix_mapping()) { - map_opt = {false, true, false, true}; // four values: use_left_ams, use_right_ams, use_left_ext, use_right_ext - filament_result = DevMappingUtil::ams_filament_mapping(obj_, m_filaments, m_ams_mapping_result, map_opt, std::vector(), - wxGetApp().app_config->get_bool("ams_sync_match_full_use_color_dist") ? false : true); - // auto_supply_with_ext(obj_->vt_slot); - } else { - map_opt = {false, true, false, false}; - filament_result = DevMappingUtil::ams_filament_mapping(obj_, m_filaments, m_ams_mapping_result, map_opt); - } + map_opt = {false, true, false, true}; // four values: use_left_ams, use_right_ams, use_left_ext, use_right_ext + filament_result = DevMappingUtil::ams_filament_mapping(obj_, m_filaments, m_ams_mapping_result, map_opt, std::vector(), + wxGetApp().app_config->get_bool("ams_sync_match_full_use_color_dist") ? false : true); + // auto_supply_with_ext(obj_->vt_slot); } if (filament_result == 0) { From 8c7cc6972fab58770b9e090e1b473f2745666c2c Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 9 May 2026 13:15:17 +0800 Subject: [PATCH 38/44] FIX: context: fix the .gcode.3mf not shown issue (#13360) filament_self_index difference caused JIRA: no-jira Change-Id: Ia70fe8a8095b8067fe13bbfc9e5c39d9f3ee05d3 (cherry picked from commit 3a55a3a1eef94f577376cd697c3b72cb46967672) Co-authored-by: lane.wei --- src/libslic3r/Print.hpp | 2 +- src/libslic3r/PrintApply.cpp | 26 +++++++++++++++++++------- src/libslic3r/PrintBase.hpp | 2 +- src/libslic3r/SLAPrint.cpp | 2 +- src/libslic3r/SLAPrint.hpp | 2 +- src/slic3r/GUI/PartPlate.cpp | 7 ++++--- 6 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index eeb74a87ed..144698faa0 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -905,7 +905,7 @@ public: // List of existing PrintObject IDs, to remove notifications for non-existent IDs. std::vector print_object_ids() const override; - ApplyStatus apply(const Model &model, DynamicPrintConfig config) override; + ApplyStatus apply(const Model &model, DynamicPrintConfig config, bool extruder_applied = false) override; void process(long long *time_cost_with_cache = nullptr, bool use_cache = false) override; // Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file. diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index ac2d56780f..c9b500a85c 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -1104,7 +1104,7 @@ static PrintObjectRegions* generate_print_object_regions( return out.release(); } -Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_config) +Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_config, bool extruder_applied) { #ifdef _DEBUG check_model_ids_validity(model); @@ -1156,13 +1156,25 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ } //apply extruder related values - new_full_config.update_values_to_printer_extruders(new_full_config, printer_options_with_variant_1, "printer_extruder_id", "printer_extruder_variant"); - new_full_config.update_values_to_printer_extruders(new_full_config, printer_options_with_variant_2, "printer_extruder_id", "printer_extruder_variant", 2); - //update print config related with variants - new_full_config.update_values_to_printer_extruders(new_full_config, print_options_with_variant, "print_extruder_id", "print_extruder_variant"); + if (!extruder_applied) { + new_full_config.update_values_to_printer_extruders(new_full_config, printer_options_with_variant_1, "printer_extruder_id", "printer_extruder_variant"); + new_full_config.update_values_to_printer_extruders(new_full_config, printer_options_with_variant_2, "printer_extruder_id", "printer_extruder_variant", 2); + //update print config related with variants + new_full_config.update_values_to_printer_extruders(new_full_config, print_options_with_variant, "print_extruder_id", "print_extruder_variant"); + + m_ori_full_print_config = new_full_config; + new_full_config.update_values_to_printer_extruders_for_multiple_filaments(new_full_config, filament_options_with_variant, "filament_self_index", "filament_extruder_variant"); + } + // else { + // int extruder_count; + // bool different_extruder = new_full_config.support_different_extruders(extruder_count); + // print_variant_index.resize(extruder_count); + // for (int e_index = 0; e_index < extruder_count; e_index++) + // { + // print_variant_index[e_index] = e_index; + // } + // } - m_ori_full_print_config = new_full_config; - new_full_config.update_values_to_printer_extruders_for_multiple_filaments(new_full_config, filament_options_with_variant, "filament_self_index", "filament_extruder_variant"); auto opt_filament_map = new_full_config.option("filament_map"); std::vector filament_maps = opt_filament_map ? opt_filament_map->values : std::vector(); diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index 21092ff257..4158c23065 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -407,7 +407,7 @@ public: // Some data was changed, which in turn invalidated already calculated steps. APPLY_STATUS_INVALIDATED, }; - virtual ApplyStatus apply(const Model &model, DynamicPrintConfig config) = 0; + virtual ApplyStatus apply(const Model &model, DynamicPrintConfig config, bool extruder_applied = false) = 0; const Model& model() const { return m_model; } struct TaskParams { diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 569d22501e..ca07f8754e 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -184,7 +184,7 @@ std::vector SLAPrint::print_object_ids() const return out; } -SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig config) +SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig config, bool extruder_applied) { #ifdef _DEBUG check_model_ids_validity(model); diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 887942c9cf..a8c49674fc 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -450,7 +450,7 @@ public: bool empty() const override { return m_objects.empty(); } // List of existing PrintObject IDs, to remove notifications for non-existent IDs. std::vector print_object_ids() const override; - ApplyStatus apply(const Model &model, DynamicPrintConfig config) override; + ApplyStatus apply(const Model &model, DynamicPrintConfig config, bool extruder_applied = false) override; void set_task(const TaskParams ¶ms) override; void process(long long *time_cost_with_cache = nullptr, bool use_cache = false) override; void finalize() override; diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 8a7d10711a..9c9b3baf8c 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -3414,12 +3414,13 @@ int PartPlate::load_gcode_from_file(const std::string& filename) int ret = 0; // process gcode - DynamicPrintConfig full_config = wxGetApp().preset_bundle->full_config(); + std::vector filament_maps = this->get_filament_maps(); + DynamicPrintConfig full_config = wxGetApp().preset_bundle->full_config(false, filament_maps); full_config.apply(m_config, true); - m_print->apply(*m_model, full_config); + m_print->apply(*m_model, full_config, false); //BBS: need to apply two times, for after the first apply, the m_print got its object, //which will affect the config when new_full_config.normalize_fdm(used_filaments); - m_print->apply(*m_model, full_config); + m_print->apply(*m_model, full_config, false); // BBS: use backup path to save temp gcode // auto path = get_tmp_gcode_path(); From 4abda6bffec5af81ccc5d99480ca3500c89b70fa Mon Sep 17 00:00:00 2001 From: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> Date: Sat, 9 May 2026 02:25:17 -0300 Subject: [PATCH 39/44] Non-Crossing Tri-hexagon multiline (#13433) * non-crossing fillstars * clean * funca 1 * clean 2 * docum. Update FillRectilinear.cpp * clean 3 Update FillRectilinear.cpp * Update FillRectilinear.cpp --- src/libslic3r/Fill/FillRectilinear.cpp | 105 ++++++++++++++++++++++--- 1 file changed, 96 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp index ee853eea96..228663fb42 100644 --- a/src/libslic3r/Fill/FillRectilinear.cpp +++ b/src/libslic3r/Fill/FillRectilinear.cpp @@ -3050,7 +3050,7 @@ bool FillRectilinear::fill_surface_trapezoidal( FillParams params, const std::initializer_list& sweep_params, Polylines& polylines_out, - int Pattern_type) // 0=grid, 1=triangular + int Pattern_type) // 0=grid, 1=triangular, 2=stars { assert(params.multiline > 1); @@ -3069,9 +3069,9 @@ bool FillRectilinear::fill_surface_trapezoidal( period = coord_t((2.0 * d1 / params.density) * std::sqrt(2.0)); base_angle = rotate_vector.first + M_PI_4; // 45 } else { - // Triangular pattern parameters - period = coord_t(( 2.0 * d1 / params.density) * std::sqrt(3.0)); - base_angle = rotate_vector.first + M_PI_2; //90 + // Triangular-family pattern parameters (triangles / stars) + period = coord_t((2.0 * d1 / params.density) * std::sqrt(3.0)); + base_angle = rotate_vector.first + M_PI_2; // 90 } // Obtain the expolygon and rotate to align with pattern base angle @@ -3257,6 +3257,85 @@ bool FillRectilinear::fill_surface_trapezoidal( break; } + case 2: // Tri-hexagon / FillStars + { + // Pattern parameters + const coord_t hex_height = coord_t(0.5 * std::sqrt(3.0) * period); + const coord_t tri_height = hex_height / 2; + const coord_t d1_half = d1 / 2; + const coord_t chamfer_height = std::sqrt(3.0) * d1_half; + const coord_t d1_half_base = d1_half / std::sqrt(3.0); + const coord_t half_period = period / 2; + const coord_t quarter_period = period / 4; + + bb.merge(align_to_grid(bb.center(), Point(period, tri_height))); + const size_t layer_mod = infill_layer_id % 3; + const double angle = layer_mod * 2.0 * M_PI / 3.0; + + const coord_t half_w = bb.size().x() / 2; + const coord_t half_h = bb.size().y() / 2; + + const coord_t num_periods_x = coord_t(std::ceil(half_w / double(period))); + coord_t num_periods_y = coord_t(std::ceil(half_h / double(hex_height))); + if ((num_periods_y % 2) != 0) + ++num_periods_y; + + const coord_t x_alignment_shift = half_period; + const coord_t y_alignment_shift = (2 * tri_height) / 3; + const coord_t x_min_aligned = -num_periods_x * period - x_alignment_shift; + const coord_t x_max_aligned = num_periods_x * period - x_alignment_shift; + const coord_t y_min_aligned = -num_periods_y * hex_height - y_alignment_shift; + const coord_t y_max_aligned = num_periods_y * hex_height - y_alignment_shift; + + const size_t estimated_rows = (y_max_aligned - y_min_aligned) / hex_height + 2; + const size_t estimated_polylines = (estimated_rows + 1) * 2; + polylines.reserve(estimated_polylines); + + Polyline star_row_normal; + star_row_normal.points.reserve(((x_max_aligned - x_min_aligned) / period + 1) * 7); + Polyline star_row_mirrored; + star_row_mirrored.points.reserve(((x_max_aligned - x_min_aligned) / period + 1) * 7); + + for (coord_t x = x_min_aligned; x < x_max_aligned; x += period) { + star_row_normal.points.emplace_back(Point(x, hex_height)); // P0 + star_row_normal.points.emplace_back(Point(x + quarter_period - d1, hex_height)); // P1 + star_row_normal.points.emplace_back(Point(x + quarter_period + d1_half, hex_height - chamfer_height)); // P2 + star_row_normal.points.emplace_back(Point(x + half_period - d1_half_base, tri_height + d1_half)); // P3 + star_row_normal.points.emplace_back(Point(x + half_period + d1_half_base, tri_height + d1_half)); // P4 + star_row_normal.points.emplace_back(Point(x + (period * 3) / 4 - d1_half, hex_height - chamfer_height)); // P5 + star_row_normal.points.emplace_back(Point(x + (period * 3) / 4 + d1, hex_height)); // P6 + } + + star_row_mirrored.points = star_row_normal.points; + for (auto& p : star_row_mirrored.points) + p.y() = hex_height - p.y(); + + size_t pair_idx = 0; + const coord_t global_x_shift = half_period; + const coord_t global_y_shift = tri_height; + auto append_row_with_shift = [&polylines](const Polyline& row_template, coord_t x_shift, coord_t y_shift) { + Polyline row = row_template; + for (Point& p : row.points) { + p.x() += x_shift; + p.y() += y_shift; + } + if (!row.points.empty()) + polylines.emplace_back(std::move(row)); + }; + + for (coord_t y = y_min_aligned; y < y_max_aligned; y += hex_height, ++pair_idx) { + const coord_t x_shift = (pair_idx % 2 == 0) ? 0 : half_period; + append_row_with_shift(star_row_normal, x_shift + global_x_shift, y + global_y_shift); + append_row_with_shift(star_row_mirrored, x_shift + global_x_shift, y + global_y_shift); + } + + if (layer_mod) + for (auto& pl : polylines) + pl.rotate(angle, Point(0, 0)); + + break; + } + default: // Handle unknown pattern type break; @@ -3408,11 +3487,19 @@ Polylines FillTriangles::fill_surface(const Surface *surface, const FillParams & Polylines FillStars::fill_surface(const Surface *surface, const FillParams ¶ms) { Polylines polylines_out; - if (! this->fill_surface_by_multilines( - surface, params, - { { 0.f, 0.f }, { float(M_PI / 3.), 0.f }, { float(2. * M_PI / 3.), float((3./2.) * this->spacing * params.multiline / params.density) } }, - polylines_out)) - BOOST_LOG_TRIVIAL(error) << "FillStars::fill_surface() failed to fill a region."; + if (params.multiline > 1) { + if (!this->fill_surface_trapezoidal( + surface, params, + {{0.f, 0.f}, {float(M_PI / 3.), 0.f}, {float(2. * M_PI / 3.), float((3. / 2.) * this->spacing * params.multiline / params.density)}}, + polylines_out, 2)) + BOOST_LOG_TRIVIAL(error) << "FillStars::fill_surface_trapezoidal() failed."; + } else { + if (! this->fill_surface_by_multilines( + surface, params, + { { 0.f, 0.f }, { float(M_PI / 3.), 0.f }, { float(2. * M_PI / 3.), float((3./2.) * this->spacing * params.multiline / params.density) } }, + polylines_out)) + BOOST_LOG_TRIVIAL(error) << "FillStars::fill_surface() failed to fill a region."; + } return polylines_out; } From db8ca5feac3617c4d5de8092239a323740ac2a0f Mon Sep 17 00:00:00 2001 From: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> Date: Sat, 9 May 2026 02:45:18 -0300 Subject: [PATCH 40/44] Only warning about sparse infill rotation template the first time (#13461) Only warning the first time --- src/slic3r/GUI/Tab.cpp | 7 ++++++- src/slic3r/GUI/Tab.hpp | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 707414c500..ae052861a0 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1241,6 +1241,8 @@ void Tab::reload_config() { if (m_active_page) m_active_page->reload_config(); + if (m_type == Preset::TYPE_PRINT && m_config != nullptr) + m_last_sparse_infill_rotate_template_value = m_config->opt_string("sparse_infill_rotate_template"); } void Tab::update_mode() @@ -1744,8 +1746,9 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) auto new_value = boost::any_cast(value); is_safe_to_rotate = is_safe_to_rotate || new_value.empty(); + const bool had_previous_value = !m_last_sparse_infill_rotate_template_value.empty(); - if (!is_safe_to_rotate) { + if (!is_safe_to_rotate && !had_previous_value) { wxString msg_text = _( L("Infill patterns are typically designed to handle rotation automatically to ensure proper printing and achieve their " "intended effects (e.g., Gyroid, Cubic). Rotating the current sparse infill pattern may lead to insufficient support. " @@ -1762,6 +1765,8 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) wxGetApp().plater()->update(); } } + + m_last_sparse_infill_rotate_template_value = m_config->opt_string("sparse_infill_rotate_template"); } if(opt_key=="layer_height"){ diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 525dd0c32e..56b58ec79c 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -445,6 +445,7 @@ protected: void filter_diff_option(std::vector &options); ConfigManipulation m_config_manipulation; + std::string m_last_sparse_infill_rotate_template_value; ConfigManipulation get_config_manipulation(); friend class EditGCodeDialog; }; From 16fc3c1b14cef35d918ef72dc3081696b45114ea Mon Sep 17 00:00:00 2001 From: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> Date: Sat, 9 May 2026 02:47:18 -0300 Subject: [PATCH 41/44] Vase mode zero flow bugfix (#13517) * Vase mode bugfix Update SpiralVase.cpp * Revert "Vase mode bugfix" This reverts commit 9cd7774776aa75c799c39bfc5ab385cf869118d3. * Filter small extrusions * Update SpiralVase.cpp Co-Authored-By: Ian Bassi <12130714+ianalexis@users.noreply.github.com> * simpler Co-Authored-By: Ian Bassi <12130714+ianalexis@users.noreply.github.com> --------- Co-authored-by: Ian Bassi <12130714+ianalexis@users.noreply.github.com> --- src/libslic3r/GCode/SpiralVase.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/GCode/SpiralVase.cpp b/src/libslic3r/GCode/SpiralVase.cpp index 6e7f37afc1..2c39bda4f7 100644 --- a/src/libslic3r/GCode/SpiralVase.cpp +++ b/src/libslic3r/GCode/SpiralVase.cpp @@ -124,14 +124,15 @@ std::string SpiralVase::process_layer(const std::string &gcode, bool last_layer) float starting_flowrate = float(m_config.spiral_starting_flow_ratio.value); float finishing_flowrate = float(m_config.spiral_finishing_flow_ratio.value); + const float min_segment_length = std::max(float(EPSILON), 2 * float(m_config.resolution.value)); float len = 0.f; SpiralVase::SpiralPoint last_point = previous_layer != NULL && previous_layer->size() >0? previous_layer->at(previous_layer->size()-1): SpiralVase::SpiralPoint(0,0); - m_reader.parse_buffer(gcode, [&new_gcode, &z, total_layer_length, layer_height, transition_in, &len, ¤t_layer, &previous_layer, &transition_gcode, transition_out, smooth_spiral, &max_xy_dist_for_smoothing, &last_point, starting_flowrate, finishing_flowrate] + m_reader.parse_buffer(gcode, [&new_gcode, &z, total_layer_length, layer_height, transition_in, &len, ¤t_layer, &previous_layer, &transition_gcode, transition_out, smooth_spiral, &max_xy_dist_for_smoothing, &last_point, starting_flowrate, finishing_flowrate, min_segment_length] (GCodeReader &reader, GCodeReader::GCodeLine line) { if (line.cmd_is("G1")) { // Orca: Filter out retractions at layer change - if (line.retracting(reader) || (line.extruding(reader) && line.dist_XY(reader) < EPSILON)) return; + if (line.retracting(reader) || (line.extruding(reader) && line.dist_XY(reader) < min_segment_length)) return; if (line.has_z() && !(line.has_x() || line.has_y())) { // If this is the initial Z move of the layer, replace it with a // (redundant) move to the last Z of previous layer. @@ -175,7 +176,7 @@ std::string SpiralVase::process_layer(const std::string &gcode, bool last_layer) // Remove tiny movement // We need to figure out the distance of this new line! float modified_dist_XY = SpiralVaseHelpers::distance(last_point, target); - if (modified_dist_XY < 0.001) + if (modified_dist_XY < min_segment_length) line.clear(); else { line.set(X, target.x); From 635d96183de4fb36f0c25562a58359ee665b03f1 Mon Sep 17 00:00:00 2001 From: Ian Bassi Date: Sat, 9 May 2026 03:30:24 -0300 Subject: [PATCH 42/44] Make filament compatibility temperature-aware (#13522) * Make filament compatibility temperature-aware Extend filament compatibility checks to consider actual nozzle temperatures and temperature ranges. Print::check_multi_filaments_compatibility now accepts nozzle temperatures and range lows/highs; it resolves missing ranges from material defaults, computes per-filament effective temperatures, and checks pairwise compatibility (including high/low/mid mixed cases). Updated callers in Print::check_multi_filament_valid and CalibrationWizardPresetPage to pass nozzle settings, consolidated user-facing warning strings, and fixed extruder index handling and minor logic/path improvements. Clarify incompatible nozzle temperature warnings * Update Print.cpp * Remove json usage * Reduce messages --- src/libslic3r/Print.cpp | 199 ++++++++++-------- src/libslic3r/Print.hpp | 11 +- .../GUI/CalibrationWizardPresetPage.cpp | 32 ++- 3 files changed, 150 insertions(+), 92 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index f1ce2a4747..57a17d01e3 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1044,29 +1044,61 @@ static StringObjectException layered_print_cleareance_valid(const Print &print, return {}; } -FilamentCompatibilityType Print::check_multi_filaments_compatibility(const std::vector& filament_types) +FilamentCompatibilityType Print::check_multi_filaments_compatibility( + const std::vector& filament_types, + const std::vector& nozzle_temperatures, + const std::vector& nozzle_temperature_range_lows, + const std::vector& nozzle_temperature_range_highs) { - bool has_high_temperature_filament = false; - bool has_low_temperature_filament = false; - bool has_mid_temperature_filament = false; + const size_t filament_count = filament_types.size(); + if (filament_count < 2) + return FilamentCompatibilityType::Compatible; - for (const auto& type : filament_types) { - if (get_filament_temp_type(type) ==FilamentTempType::HighTemp) - has_high_temperature_filament = true; - else if (get_filament_temp_type(type) == FilamentTempType::LowTemp) - has_low_temperature_filament = true; - else if (get_filament_temp_type(type) == FilamentTempType::HighLowCompatible) - has_mid_temperature_filament = true; + std::vector resolved_temperatures(filament_count, 0); + std::vector resolved_range_lows(filament_count, 0); + std::vector resolved_range_highs(filament_count, 0); + for (size_t i = 0; i < filament_count; ++i) { + int range_low = (i < nozzle_temperature_range_lows.size()) ? nozzle_temperature_range_lows[i] : 0; + int range_high = (i < nozzle_temperature_range_highs.size()) ? nozzle_temperature_range_highs[i] : 0; + + if (range_low == 0 || range_high == 0) { + int default_low = range_low; + int default_high = range_high; + MaterialType::get_temperature_range(filament_types[i], default_low, default_high); + if (range_low == 0) + range_low = default_low; + if (range_high == 0) + range_high = default_high; + } + + if (range_low >= range_high) + return FilamentCompatibilityType::InvalidTemperatureRange; + + int print_temperature = (i < nozzle_temperatures.size()) ? nozzle_temperatures[i] : 0; + + resolved_temperatures[i] = print_temperature; + resolved_range_lows[i] = range_low; + resolved_range_highs[i] = range_high; } - if (has_high_temperature_filament && has_low_temperature_filament) - return FilamentCompatibilityType::HighLowMixed; - else if (has_high_temperature_filament && has_mid_temperature_filament) - return FilamentCompatibilityType::HighMidMixed; - else if (has_low_temperature_filament && has_mid_temperature_filament) - return FilamentCompatibilityType::LowMidMixed; - else - return FilamentCompatibilityType::Compatible; + for (size_t i = 0; i < filament_count; ++i) { + for (size_t j = i + 1; j < filament_count; ++j) { + const bool i_temp_is_compatible_with_j = + resolved_temperatures[i] >= resolved_range_lows[j] && + resolved_temperatures[i] <= resolved_range_highs[j]; + const bool j_temp_is_compatible_with_i = + resolved_temperatures[j] >= resolved_range_lows[i] && + resolved_temperatures[j] <= resolved_range_highs[i]; + + if (i_temp_is_compatible_with_j && j_temp_is_compatible_with_i) + continue; + + // Range-only rule: any pair outside mutual recommended ranges is incompatible. + return FilamentCompatibilityType::HighLowMixed; + } + } + + return FilamentCompatibilityType::Compatible; } bool Print::is_filaments_compatible(const std::vector& filament_types) @@ -1111,18 +1143,21 @@ int Print::get_compatible_filament_type(const std::set& filament_types) StringObjectException Print::check_multi_filament_valid(const Print& print) { auto print_config = print.config(); + const std::string incompatible_temp_msg = L("Selected nozzle temperatures are incompatible. Each filament's nozzle temperature must fall within the recommended nozzle temperature range of the other filaments. Otherwise, nozzle clogging or printer damage may occur."); + const std::string invalid_temp_range_msg = L("Invalid recommended nozzle temperature range. The lower bound must be lower than the upper bound."); + const std::string incompatible_temp_msg_preferences_enable = L("If you still want to print, you can enable the option in Preferences / Control / Slicing / Remove mixed temperature restriction."); if(print_config.print_sequence == PrintSequence::ByObject) {// use ByObject valid under ByObject print sequence - std::set Compatibility_each_obj; + bool has_incompatible_object = false; bool enable_mix_printing = !print.need_check_multi_filaments_compatibility(); + StringObjectException ret; for (const auto &objectID_t : print.print_object_ids()) { std::set obj_used_extruder_ids; auto print_object = print.get_object(objectID_t);// current object if (print_object){ auto object_extruders_t = print_object->object_extruders(); // object used extruder - for (int extruder : object_extruders_t) { - assert(extruder > 0); - obj_used_extruder_ids.insert(extruder); + for (unsigned int extruder : object_extruders_t) { + obj_used_extruder_ids.insert(static_cast(extruder)); } } @@ -1136,57 +1171,83 @@ StringObjectException Print::check_multi_filament_valid(const Print& print) obj_used_extruder_ids.insert((unsigned int) print_object->config().support_interface_filament - 1); } std::vector filament_types; + std::vector nozzle_temperatures; + std::vector nozzle_temperature_range_lows; + std::vector nozzle_temperature_range_highs; filament_types.reserve(obj_used_extruder_ids.size()); - for (const auto &extruder_idx : obj_used_extruder_ids) filament_types.push_back(print_config.filament_type.get_at(extruder_idx)); + nozzle_temperatures.reserve(obj_used_extruder_ids.size()); + nozzle_temperature_range_lows.reserve(obj_used_extruder_ids.size()); + nozzle_temperature_range_highs.reserve(obj_used_extruder_ids.size()); - auto compatibility = check_multi_filaments_compatibility(filament_types);// check for each object - Compatibility_each_obj.insert(compatibility); + for (const auto &extruder_idx : obj_used_extruder_ids) { + filament_types.push_back(print_config.filament_type.get_at(extruder_idx)); + nozzle_temperatures.push_back(print_config.nozzle_temperature.get_at(extruder_idx)); + nozzle_temperature_range_lows.push_back(print_config.nozzle_temperature_range_low.get_at(extruder_idx)); + nozzle_temperature_range_highs.push_back(print_config.nozzle_temperature_range_high.get_at(extruder_idx)); + } + + auto compatibility = check_multi_filaments_compatibility( + filament_types, + nozzle_temperatures, + nozzle_temperature_range_lows, + nozzle_temperature_range_highs); // check for each object + if (compatibility == FilamentCompatibilityType::InvalidTemperatureRange) { + ret.string = invalid_temp_range_msg; + return ret; + } + if (compatibility != FilamentCompatibilityType::Compatible) { + has_incompatible_object = true; + break; + } } - StringObjectException ret; - std::string hypertext = "filament_mix_print"; - if (Compatibility_each_obj.count(FilamentCompatibilityType::HighLowMixed)){// at least one object has HighLowMixed + if (has_incompatible_object){ if (enable_mix_printing) { - ret.string = L("Printing high-temp and low-temp filaments together may cause nozzle clogging or printer damage."); + ret.string = incompatible_temp_msg; ret.is_warning = true; - // ret.hypetext = hypertext; } else - ret.string = L("Printing high-temp and low-temp filaments together may cause nozzle clogging or printer damage. If you still want to print, you can enable the option in Preferences."); - }else if (Compatibility_each_obj.count(FilamentCompatibilityType::LowMidMixed) || Compatibility_each_obj.count(FilamentCompatibilityType::HighMidMixed)){// at least one object has other Mixed - ret.is_warning = true; - // ret.hypetext = hypertext; - ret.string = L("Printing different-temp filaments together may cause nozzle clogging or printer damage."); + ret.string = incompatible_temp_msg + " " + incompatible_temp_msg_preferences_enable; } return ret; } std::vector extruders = print.extruders(); std::vector filament_types; + std::vector nozzle_temperatures; + std::vector nozzle_temperature_range_lows; + std::vector nozzle_temperature_range_highs; filament_types.reserve(extruders.size()); - for (const auto& extruder_idx : extruders) + nozzle_temperatures.reserve(extruders.size()); + nozzle_temperature_range_lows.reserve(extruders.size()); + nozzle_temperature_range_highs.reserve(extruders.size()); + for (const auto& extruder_idx : extruders) { filament_types.push_back(print_config.filament_type.get_at(extruder_idx)); + nozzle_temperatures.push_back(print_config.nozzle_temperature.get_at(extruder_idx)); + nozzle_temperature_range_lows.push_back(print_config.nozzle_temperature_range_low.get_at(extruder_idx)); + nozzle_temperature_range_highs.push_back(print_config.nozzle_temperature_range_high.get_at(extruder_idx)); + } - auto compatibility = check_multi_filaments_compatibility(filament_types); + auto compatibility = check_multi_filaments_compatibility( + filament_types, + nozzle_temperatures, + nozzle_temperature_range_lows, + nozzle_temperature_range_highs); bool enable_mix_printing = !print.need_check_multi_filaments_compatibility(); StringObjectException ret; - if(compatibility == FilamentCompatibilityType::HighLowMixed){ + if (compatibility == FilamentCompatibilityType::InvalidTemperatureRange) { + ret.string = invalid_temp_range_msg; + return ret; + } + + if(compatibility != FilamentCompatibilityType::Compatible){ if(enable_mix_printing){ - ret.string =L("Printing high-temp and low-temp filaments together may cause nozzle clogging or printer damage."); + ret.string = incompatible_temp_msg; ret.is_warning = true; } else{ - ret.string =L("Printing high-temp and low-temp filaments together may cause nozzle clogging or printer damage. If you still want to print, you can enable the option in Preferences."); + ret.string = incompatible_temp_msg + " " + incompatible_temp_msg_preferences_enable; } } - else if (compatibility == FilamentCompatibilityType::HighMidMixed) { - ret.is_warning = true; - ret.string =L("Printing high-temp and mid-temp filaments together may cause nozzle clogging or printer damage."); - - } - else if (compatibility == FilamentCompatibilityType::LowMidMixed) { - ret.is_warning = true; - ret.string = L("Printing mid-temp and low-temp filaments together may cause nozzle clogging or printer damage."); - } return ret; } @@ -2798,43 +2859,7 @@ Vec2d Print::translate_to_print_space(const Point &point) const { FilamentTempType Print::get_filament_temp_type(const std::string& filament_type) { - const static std::string HighTempFilamentStr = "high_temp_filament"; - const static std::string LowTempFilamentStr = "low_temp_filament"; - const static std::string HighLowCompatibleFilamentStr = "high_low_compatible_filament"; - static std::unordered_map>filament_temp_type_map; - - if (filament_temp_type_map.empty()) { - fs::path file_path = fs::path(resources_dir()) / "info" / "filament_info.json"; - std::ifstream in(file_path.string()); - json j; - try{ - j = json::parse(in); - in.close(); - auto&&high_temp_filament_arr =j[HighTempFilamentStr].get < std::vector>(); - filament_temp_type_map[HighTempFilamentStr] = std::unordered_set(high_temp_filament_arr.begin(), high_temp_filament_arr.end()); - auto&& low_temp_filament_arr = j[LowTempFilamentStr].get < std::vector>(); - filament_temp_type_map[LowTempFilamentStr] = std::unordered_set(low_temp_filament_arr.begin(), low_temp_filament_arr.end()); - auto&& high_low_compatible_filament_arr = j[HighLowCompatibleFilamentStr].get < std::vector>(); - filament_temp_type_map[HighLowCompatibleFilamentStr] = std::unordered_set(high_low_compatible_filament_arr.begin(), high_low_compatible_filament_arr.end()); - } - 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(); - filament_temp_type_map[HighTempFilamentStr] = {"ABS","ASA","PC","PA","PA-CF","PA-GF","PA6-CF","PET-CF", "PETG-GF","PPS","PPS-CF","PPA-GF","PPA-CF","ABS-Aero","ABS-GF"}; - filament_temp_type_map[LowTempFilamentStr] = {"PLA","TPU","PLA-CF","PLA-AERO","PVA","BVOH","SBS"}; - filament_temp_type_map[HighLowCompatibleFilamentStr] = { "HIPS","PETG","PCTG","PE","PP","EVA","PE-CF","PP-CF","PP-GF","PHA"}; - } - } - - if (filament_temp_type_map[HighLowCompatibleFilamentStr].find(filament_type) != filament_temp_type_map[HighLowCompatibleFilamentStr].end()) - return HighLowCompatible; - if (filament_temp_type_map[HighTempFilamentStr].find(filament_type) != filament_temp_type_map[HighTempFilamentStr].end()) - return HighTemp; - if (filament_temp_type_map[LowTempFilamentStr].find(filament_type) != filament_temp_type_map[LowTempFilamentStr].end()) - return LowTemp; - - // Orca: prefer explicit definition from JSON, if the filament type is not defined in json, fallback to temperature-based logic to determine the filament temp type. - // FilamentTempType Temperature-based logic + // Range-based classification only: do not use filament_info.json. int min_temp, max_temp; if (MaterialType::get_temperature_range(filament_type, min_temp, max_temp)) { if (max_temp <= 250) diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 144698faa0..9206f2a390 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -877,8 +877,9 @@ enum FilamentTempType { enum FilamentCompatibilityType { Compatible, HighLowMixed, - HighMidMixed, - LowMidMixed + //HighLowMixed, + //HighMidMixed, + InvalidTemperatureRange }; // The complete print tray with possibly multiple objects. @@ -1087,7 +1088,11 @@ public: static FilamentTempType get_filament_temp_type(const std::string& filament_type); static int get_hrc_by_nozzle_type(const NozzleType& type); static std::vector get_incompatible_filaments_by_nozzle(const float nozzle_diameter, const std::optional nozzle_volume_type = std::nullopt); - static FilamentCompatibilityType check_multi_filaments_compatibility(const std::vector& filament_types); + static FilamentCompatibilityType check_multi_filaments_compatibility( + const std::vector& filament_types, + const std::vector& nozzle_temperatures, + const std::vector& nozzle_temperature_range_lows, + const std::vector& nozzle_temperature_range_highs); // 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& types); // get the compatible filament type of a multi-material object diff --git a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp index 66fe521105..cc6db72ff5 100644 --- a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp @@ -1505,6 +1505,9 @@ bool CalibrationPresetPage::is_filaments_compatiable(const std::map filament_types; + std::vector nozzle_temperatures; + std::vector nozzle_temperature_range_lows; + std::vector nozzle_temperature_range_highs; for (auto &item : prests) { const auto& item_preset = item.second; if (!item_preset) @@ -1533,13 +1536,38 @@ bool CalibrationPresetPage::is_filaments_compatiable(const std::mapconfig.get_filament_type(display_filament_type, 0)); + int nozzle_temperature = 0; + int nozzle_temperature_range_low = 0; + int nozzle_temperature_range_high = 0; + if (const auto* opt_nozzle_temp = item_preset->config.option("nozzle_temperature")) + nozzle_temperature = opt_nozzle_temp->get_at(0); + if (const auto* opt_nozzle_temp_low = item_preset->config.option("nozzle_temperature_range_low")) + nozzle_temperature_range_low = opt_nozzle_temp_low->get_at(0); + if (const auto* opt_nozzle_temp_high = item_preset->config.option("nozzle_temperature_range_high")) + nozzle_temperature_range_high = opt_nozzle_temp_high->get_at(0); + + nozzle_temperatures.push_back(nozzle_temperature); + nozzle_temperature_range_lows.push_back(nozzle_temperature_range_low); + nozzle_temperature_range_highs.push_back(nozzle_temperature_range_high); + // check is it in the filament blacklist if (!is_filament_in_blacklist(item.first, item_preset, error_tips)) return false; } - if (Print::check_multi_filaments_compatibility(filament_types) == FilamentCompatibilityType::HighLowMixed) { - error_tips = _u8L("Cannot print multiple filaments which have large difference of temperature together. Otherwise, the extruder and nozzle may be blocked or damaged during printing"); + auto compatibility = Print::check_multi_filaments_compatibility( + filament_types, + nozzle_temperatures, + nozzle_temperature_range_lows, + nozzle_temperature_range_highs); + + if (compatibility == FilamentCompatibilityType::InvalidTemperatureRange) { + error_tips = _u8L("Invalid recommended nozzle temperature range. The lower bound must be lower than the upper bound."); + return false; + } + + if (compatibility == FilamentCompatibilityType::HighLowMixed) { + error_tips = _u8L("Selected nozzle temperatures are incompatible. For multi-material printing, each filament's nozzle temperature must be within the recommended nozzle temperature range of the other filaments. Otherwise, nozzle clogging or printer damage may occur."); return false; } From 89c9c02ff6d976408eb9a32aa737ce7cacb8fa21 Mon Sep 17 00:00:00 2001 From: yw4z Date: Sat, 9 May 2026 09:31:37 +0300 Subject: [PATCH 43/44] Release Notes dialog Fixes / Improvements (#12265) * Update ReleaseNote.cpp * Update ReleaseNote.cpp * fix large sized images overflows * improve styling --- src/slic3r/GUI/ReleaseNote.cpp | 79 +++++++++++++++++----------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/src/slic3r/GUI/ReleaseNote.cpp b/src/slic3r/GUI/ReleaseNote.cpp index f341cff154..3dd87e8626 100644 --- a/src/slic3r/GUI/ReleaseNote.cpp +++ b/src/slic3r/GUI/ReleaseNote.cpp @@ -243,24 +243,23 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent) auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1)); m_line_top->SetBackgroundColour(wxColour(166, 169, 170)); + wxBoxSizer *m_sizer_top = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer *m_sizer_desc = new wxBoxSizer(wxVERTICAL); - wxBoxSizer *m_sizer_body = new wxBoxSizer(wxHORIZONTAL); - - - - auto sm = create_scaled_bitmap("OrcaSlicer", nullptr, 70); - m_brand = new wxStaticBitmap(this, wxID_ANY, sm, wxDefaultPosition, wxSize(FromDIP(70), FromDIP(70))); - - - - wxBoxSizer *m_sizer_right = new wxBoxSizer(wxVERTICAL); + auto sm = create_scaled_bitmap("OrcaSlicer", nullptr, 64); + m_brand = new wxStaticBitmap(this, wxID_ANY, sm, wxDefaultPosition, FromDIP(wxSize(64, 64))); m_text_up_info = new Label(this, Label::Head_14, wxEmptyString, LB_AUTO_WRAP); m_text_up_info->SetForegroundColour(wxColour(0x26, 0x2E, 0x30)); - m_simplebook_release_note = new wxSimplebook(this); - m_simplebook_release_note->SetSize(wxSize(FromDIP(560), FromDIP(430))); - m_simplebook_release_note->SetMinSize(wxSize(FromDIP(560), FromDIP(430))); + auto github_link = new HyperLink(this, _L("Check on Github"), "", LB_AUTO_WRAP); + github_link->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { + EndModal(wxID_YES); + }); + + m_simplebook_release_note = new wxSimplebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER); + //m_simplebook_release_note->SetSize(wxSize(FromDIP(560), FromDIP(430))); + m_simplebook_release_note->SetMinSize(FromDIP(wxSize(640,420))); m_simplebook_release_note->SetBackgroundColour(wxColour(0xF8, 0xF8, 0xF8)); m_scrollwindows_release_note = new wxScrolledWindow(m_simplebook_release_note, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(560), FromDIP(430)), wxVSCROLL); @@ -269,8 +268,9 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent) //webview m_vebview_release_note = CreateTipView(m_simplebook_release_note); - m_vebview_release_note->SetSize(wxSize(FromDIP(560), FromDIP(430))); - m_vebview_release_note->SetMinSize(wxSize(FromDIP(560), FromDIP(430))); + m_vebview_release_note->SetBackgroundColour(wxColour(0xF8, 0xF8, 0xF8)); + //m_vebview_release_note->SetSize(wxSize(FromDIP(560), FromDIP(430))); + //m_vebview_release_note->SetMinSize(wxSize(FromDIP(560), FromDIP(430))); //m_vebview_release_note->SetMaxSize(wxSize(FromDIP(560), FromDIP(430))); if (wxGetApp().app_config->get_bool("developer_mode")) m_vebview_release_note->EnableAccessToDevTools(); @@ -300,8 +300,6 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent) m_simplebook_release_note->AddPage(m_scrollwindows_release_note, wxEmptyString, false); m_simplebook_release_note->AddPage(m_vebview_release_note, wxEmptyString, false); - - auto sizer_button = new wxBoxSizer(wxHORIZONTAL); m_button_download = new Button(this, _L("Download")); @@ -327,8 +325,6 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent) }); auto stable_only_label = new Label(this, _L("Check for stable updates only")); - stable_only_label->SetFont(Label::Body_13); - stable_only_label->SetForegroundColour(wxColour(38, 46, 48)); stable_only_label->SetFont(Label::Body_12); m_button_cancel = new Button(this, _L("Cancel")); @@ -338,25 +334,27 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent) EndModal(wxID_NO); }); - m_sizer_main->Add(m_line_top, 0, wxEXPAND | wxBOTTOM, 0); - //sizer_button->Add(m_remind_choice, 0, wxALL | wxEXPAND, FromDIP(5)); + + sizer_button->Add(m_cb_stable_only , 0, wxALIGN_CENTER); + sizer_button->Add(stable_only_label , 0, wxALIGN_CENTER | wxLEFT, FromDIP(5)); sizer_button->AddStretchSpacer(); - sizer_button->Add(stable_only_label, 0, wxALIGN_CENTER | wxLEFT, FromDIP(7)); - sizer_button->Add(m_cb_stable_only, 0, wxALIGN_CENTER | wxLEFT, FromDIP(5)); - sizer_button->Add(m_button_download, 0, wxALL, FromDIP(5)); - sizer_button->Add(m_button_skip_version, 0, wxALL, FromDIP(5)); - sizer_button->Add(m_button_cancel, 0, wxALL, FromDIP(5)); + sizer_button->Add(m_button_download , 0, wxLEFT, FromDIP(10)); + sizer_button->Add(m_button_skip_version, 0, wxLEFT, FromDIP(10)); + sizer_button->Add(m_button_cancel , 0, wxLEFT, FromDIP(10)); - m_sizer_right->Add(m_text_up_info, 0, wxEXPAND | wxBOTTOM | wxTOP, FromDIP(15)); - m_sizer_right->Add(m_simplebook_release_note, 1, wxEXPAND | wxRIGHT, 0); - m_sizer_right->Add(sizer_button, 0, wxEXPAND | wxRIGHT, FromDIP(20)); + m_sizer_desc->AddStretchSpacer(); + m_sizer_desc->Add(m_text_up_info, 0, wxEXPAND | wxBOTTOM, FromDIP(5)); + m_sizer_desc->Add(github_link); + m_sizer_desc->AddStretchSpacer(); - m_sizer_body->Add(m_brand, 0, wxTOP|wxRIGHT|wxLEFT, FromDIP(15)); - m_sizer_body->Add(0, 0, 0, wxRIGHT, 0); - m_sizer_body->Add(m_sizer_right, 1, wxBOTTOM | wxEXPAND, FromDIP(8)); - m_sizer_main->Add(m_sizer_body, 1, wxEXPAND, 0); - m_sizer_main->Add(0, 0, 0, wxBOTTOM, 10); + m_sizer_top->Add(m_brand , 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(15)); + m_sizer_top->Add(m_sizer_desc, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL); + + m_sizer_main->Add(m_line_top , 0, wxEXPAND); + m_sizer_main->Add(m_sizer_top , 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(15)); + m_sizer_main->Add(m_simplebook_release_note, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(15)); + m_sizer_main->Add(sizer_button , 0, wxEXPAND | wxALL , FromDIP(15)); SetSizer(m_sizer_main); Layout(); @@ -479,14 +477,17 @@ void UpdateVersionDialog::update_version_info(wxString release_note, wxString ve // m_vebview_release_note->LoadURL(from_u8(url_line)); // } // else { - m_simplebook_release_note->SetMaxSize(wxSize(FromDIP(560), FromDIP(430))); + //m_simplebook_release_note->SetMaxSize(wxSize(FromDIP(560), FromDIP(430))); m_simplebook_release_note->SetSelection(1); m_text_up_info->SetLabel(wxString::Format(_L("Click to download new version in default browser: %s"), version)); auto data_buf_in = release_note.utf8_str(); - auto bg_color = StateColor::darkModeColorFor(*wxWHITE).GetAsString(); - auto fg_color = StateColor::darkModeColorFor(*wxBLACK).GetAsString(); - html_source = (boost::format("") - % fg_color % bg_color).str(); + auto bg_color = StateColor::darkModeColorFor(wxColour("#FFFFFF")).GetAsString(); + auto fg_color = StateColor::darkModeColorFor(wxColour("#262E30")).GetAsString(); + auto style = "body {color:" + fg_color + "; background-color:" + bg_color + "; font-family:sans-serif}" + + "a {color: #009688}" // matches hyperlink colors + + "img {max-width:100%; height:auto}" // fixes overflowing images + + "ul {padding-inline-start: 20px}"; // reduce left padding on list items + html_source = (boost::format("") % style).str(); md_html(data_buf_in.data(), data_buf_in.length(), [](const MD_CHAR* text, MD_SIZE size, void* userdata) { std::string* out_buf = (std::string*)userdata; out_buf->append(text, size); From 7bef75b2cdf7d32476274b951b5ea59736c109d3 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sat, 9 May 2026 18:32:46 +0800 Subject: [PATCH 44/44] attempt to reduce freezing issues caused by model dialog on Linux --- src/slic3r/GUI/DeviceErrorDialog.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/slic3r/GUI/DeviceErrorDialog.cpp b/src/slic3r/GUI/DeviceErrorDialog.cpp index ff9fe63dbf..008c99474d 100644 --- a/src/slic3r/GUI/DeviceErrorDialog.cpp +++ b/src/slic3r/GUI/DeviceErrorDialog.cpp @@ -240,7 +240,14 @@ wxString DeviceErrorDialog::show_error_code(int error_code) Show(); Raise(); +#ifndef __linux__ + // On Linux (especially Wayland) RequestUserAttention(wxUSER_ATTENTION_ERROR) maps to + // gtk_window_set_urgency_hint(TRUE) which can leave the window in an urgent-but-unfocused + // state — clicks no longer reach any widget in the app and the user has to kill the + // process to recover. Same root cause as #9874, where SecondaryCheckDialog had its + // RequestUserAttention call removed for the identical reason. this->RequestUserAttention(wxUSER_ATTENTION_ERROR); +#endif return error_msg; }