From 81b06d68f1d3985538ed226548461d51c4f0d6ab Mon Sep 17 00:00:00 2001 From: Ian Chua Date: Tue, 28 Jul 2026 17:11:54 +0800 Subject: [PATCH 01/51] feat: initial plugin auditing workflow --- src/slic3r/plugin/PluginAuditManager.cpp | 318 ++++++++++++------ src/slic3r/plugin/PluginAuditManager.hpp | 48 ++- src/slic3r/plugin/PluginFsUtils.cpp | 40 ++- src/slic3r/plugin/PluginFsUtils.hpp | 10 + src/slic3r/plugin/PluginLoader.cpp | 2 +- src/slic3r/plugin/PluginManager.cpp | 42 +++ src/slic3r/plugin/PluginManager.hpp | 3 + src/slic3r/plugin/PyPluginTrampoline.hpp | 27 +- src/slic3r/plugin/PythonPluginBridge.cpp | 91 ++++- src/slic3r/plugin/PythonPluginBridge.hpp | 2 +- ...PrinterAgentPluginCapabilityTrampoline.hpp | 64 ++-- .../ScriptPluginCapabilityTrampoline.hpp | 1 - ...cingPipelinePluginCapabilityTrampoline.hpp | 1 - 13 files changed, 458 insertions(+), 191 deletions(-) diff --git a/src/slic3r/plugin/PluginAuditManager.cpp b/src/slic3r/plugin/PluginAuditManager.cpp index 29aa59b253..f027dd072d 100644 --- a/src/slic3r/plugin/PluginAuditManager.cpp +++ b/src/slic3r/plugin/PluginAuditManager.cpp @@ -7,8 +7,16 @@ #include #include +#include #include +#include +#include +#include +#include +#include #include +#include +#include namespace Slic3r { @@ -78,24 +86,21 @@ bool is_inside_allowed_root(const boost::filesystem::path& candidate, const boos // ScopedPluginAuditContext // --------------------------------------------------------------------------- -thread_local std::string PluginAuditManager::m_current_plugin_key = ""; -thread_local std::string PluginAuditManager::m_current_capability_name = ""; -thread_local PluginAuditManager::AuditMode PluginAuditManager::m_audit_mode = PluginAuditManager::AuditMode::Loading; +thread_local std::string PluginAuditManager::m_current_plugin_key = ""; +thread_local std::string PluginAuditManager::m_current_capability_name = ""; thread_local std::vector PluginAuditManager::m_scoped_allowed_roots; +thread_local bool PluginAuditManager::m_audit_denial_pending = false; thread_local bool PluginAuditManager::m_has_last_violation = false; thread_local AuditViolation PluginAuditManager::m_last_violation; ScopedPluginAuditContext::ScopedPluginAuditContext(const std::string& plugin_key, - const std::string& capability_name, - PluginAuditManager::AuditMode mode) + const std::string& capability_name) : m_previous_id(PluginAuditManager::instance().current_plugin()) , m_previous_capability(PluginAuditManager::instance().current_capability()) - , m_previous_mode(PluginAuditManager::instance().audit_mode()) , m_previous_scoped_roots(PluginAuditManager::m_scoped_allowed_roots) { PluginAuditManager::instance().set_current_plugin(plugin_key); PluginAuditManager::instance().set_current_capability(capability_name); - PluginAuditManager::instance().set_audit_mode(mode); PluginAuditManager::m_scoped_allowed_roots.clear(); } @@ -103,7 +108,6 @@ ScopedPluginAuditContext::~ScopedPluginAuditContext() { PluginAuditManager::instance().set_current_plugin(m_previous_id); PluginAuditManager::instance().set_current_capability(m_previous_capability); - PluginAuditManager::instance().set_audit_mode(m_previous_mode); PluginAuditManager::m_scoped_allowed_roots = std::move(m_previous_scoped_roots); } @@ -198,14 +202,6 @@ bool PluginAuditManager::is_denied_filename(const boost::filesystem::path& candi return false; } -// --------------------------------------------------------------------------- -// Audit mode -// --------------------------------------------------------------------------- - -void PluginAuditManager::set_audit_mode(AuditMode mode) { m_audit_mode = mode; } - -PluginAuditManager::AuditMode PluginAuditManager::audit_mode() const { return m_audit_mode; } - // --------------------------------------------------------------------------- // Policy checks // --------------------------------------------------------------------------- @@ -219,21 +215,15 @@ AuditDecision PluginAuditManager::check_path_access(const boost::filesystem::pat if (plugin_key.empty()) return {true, ""}; // not running inside a plugin context - // Denied filenames are checked first, above both the Loading exemption below and the - // allowed roots. The app config and the cloud refresh token live directly inside - // data_dir(), which is a global allowed root, and no scope ever sets Enforcing — so a - // deny placed any lower would be unreachable for reads. + // Denied filenames are checked before the allowed roots. The app config and the cloud + // refresh token live directly inside data_dir(), which is a global allowed root, so a deny + // placed any lower would be unreachable. if (is_denied_filename(path)) { BOOST_LOG_TRIVIAL(warning) << "[AUDIT] block path=" << path.string() << " is_write=" << is_write << " plugin=" << plugin_key << " reason=denied filename"; return {false, "denied filename"}; } - // During import/loading, only block writes. Python must be able to read - // stdlib modules and the plugin file itself during import. - if (m_audit_mode == AuditMode::Loading && !is_write) - return {true, ""}; - namespace fs = boost::filesystem; fs::path candidate = path; @@ -261,7 +251,6 @@ AuditDecision PluginAuditManager::check_path_access(const boost::filesystem::pat } BOOST_LOG_TRIVIAL(warning) << "[AUDIT] block path=" << candidate.string() << " is_write=" << is_write - << " audit_mode=" << (m_audit_mode == AuditMode::Loading ? "Loading" : "Enforcing") << " plugin=" << plugin_key; return {false, "outside allowed root"}; } @@ -269,19 +258,99 @@ AuditDecision PluginAuditManager::check_path_access(const boost::filesystem::pat AuditDecision PluginAuditManager::check_open(const std::string& path_str, const std::string& mode) { const bool is_write = mode.find('w') != std::string::npos || mode.find('a') != std::string::npos || - mode.find('+') != std::string::npos; + mode.find('+') != std::string::npos || mode.find('x') != std::string::npos; return check_path_access(boost::filesystem::path(path_str), is_write); } +bool PluginAuditManager::request_filesystem_read_permissions(const std::string& plugin_key, + const std::vector& paths) +{ + if (plugin_key.empty() || paths.empty()) + return true; + + PluginDescriptor descriptor; + if (!PluginManager::instance().try_get_plugin_descriptor(plugin_key, descriptor) || descriptor.plugin_root.empty()) + return false; + + PluginInstallState state; + read_install_state(boost::filesystem::path(descriptor.plugin_root), state); + + std::vector missing; + for (const std::string& path : paths) { + if (std::find(state.permissions.fs_read.begin(), state.permissions.fs_read.end(), path) == state.permissions.fs_read.end()) + missing.push_back(path); + } + if (missing.empty()) + return true; + + if (wxTheApp == nullptr || GUI::wxGetApp().is_closing()) + return false; + + auto show_dialog = [&descriptor, &missing]() { + wxString requested_paths; + for (const std::string& path : missing) + requested_paths += wxString::FromUTF8(path.c_str()) + "\n"; + + wxMessageDialog dialog( + nullptr, + wxString::Format("Plugin \"%s\" requests filesystem read access to:\n%s", + wxString::FromUTF8(descriptor.name.c_str()), requested_paths), + "Plugin permissions", + wxYES_NO | wxICON_WARNING); + return dialog.ShowModal() == wxID_YES; + }; + + bool granted = false; + if (wxIsMainThread()) { + granted = show_dialog(); + } else { + auto result = std::make_shared>(); + auto future = result->get_future(); + GUI::wxGetApp().CallAfter([result, descriptor_name = descriptor.name, missing]() { + wxString requested_paths; + for (const std::string& path : missing) + requested_paths += wxString::FromUTF8(path.c_str()) + "\n"; + + wxMessageDialog dialog( + nullptr, + wxString::Format("Plugin \"%s\" requests filesystem read access to:\n%s", + wxString::FromUTF8(descriptor_name.c_str()), requested_paths), + "Plugin permissions", + wxYES_NO | wxICON_WARNING); + result->set_value(dialog.ShowModal() == wxID_YES); + }); + granted = future.get(); + } + + if (!granted) + return false; + + if (state.plugin_name.empty()) { + state.installed_from = descriptor.is_cloud_plugin() ? "cloud" : "local"; + state.installed_version = !descriptor.installed_version.empty() ? descriptor.installed_version : descriptor.version; + state.plugin_name = descriptor.name; + state.cloud_uuid = descriptor.cloud_uuid(); + state.enabled = true; + } + + state.permissions.fs_read.insert(state.permissions.fs_read.end(), missing.begin(), missing.end()); + return write_install_state(boost::filesystem::path(descriptor.plugin_root), state); +} + void PluginAuditManager::report_violation(const AuditViolation& violation) { m_last_violation = violation; m_has_last_violation = true; + m_audit_denial_pending = true; BOOST_LOG_TRIVIAL(warning) << "[AUDIT BLOCKED] plugin=" << violation.plugin_key << " event=" << violation.event_name << " path=" << violation.path.string() << " reason=" << violation.reason; } +bool PluginAuditManager::audit_denial_pending() const { return m_audit_denial_pending; } + +void PluginAuditManager::clear_audit_denial() { m_audit_denial_pending = false; } + void PluginAuditManager::clear_last_violation() { m_has_last_violation = false; @@ -301,27 +370,106 @@ bool PluginAuditManager::last_violation(AuditViolation& violation) const // The C-level audit hook // --------------------------------------------------------------------------- -namespace { +namespace PluginAuditDetail { -// Records a blocked event and raises PermissionError in the calling interpreter. Returns -1 -// so an event branch can `return report_denied(...)` directly. +PyObject* tuple_item(PyObject* args, Py_ssize_t index) +{ + if (!args || !PyTuple_Check(args) || index < 0 || index >= PyTuple_GET_SIZE(args)) + return nullptr; + return PyTuple_GET_ITEM(args, index); +} + +std::string python_path(PyObject* object) +{ + if (!object) + return {}; + + PyObject* path_object = PyOS_FSPath(object); + if (!path_object) { + PyErr_Clear(); + return {}; + } + + const char* path = PyUnicode_Check(path_object) ? PyUnicode_AsUTF8(path_object) : PyBytes_AsString(path_object); + std::string result = path ? path : ""; + Py_DECREF(path_object); + if (!path) + PyErr_Clear(); + return result; +} + +void add_filesystem_path(std::vector& paths, PyObject* object) +{ + const std::string path = python_path(object); + if (!path.empty()) + paths.emplace_back(path); +} + +std::vector filesystem_paths(const std::string& event_name, PyObject* args) +{ + std::vector paths; + + if (event_name == "open") { + add_filesystem_path(paths, tuple_item(args, 0)); + } else if (event_name == "os.rename") { + add_filesystem_path(paths, tuple_item(args, 0)); + add_filesystem_path(paths, tuple_item(args, 1)); + } else if (event_name == "os.remove") { + add_filesystem_path(paths, tuple_item(args, 0)); + } + + return paths; +} + +bool has_filesystem_permission(const PluginInstallState& state, const boost::filesystem::path& path) +{ + return std::find(state.permissions.fs_read.begin(), state.permissions.fs_read.end(), path.string()) != + state.permissions.fs_read.end(); +} + +bool persist_filesystem_permission(const std::string& plugin_key, + PluginInstallState& state, + const boost::filesystem::path& path) +{ + PluginDescriptor descriptor; + if (!PluginManager::instance().try_get_plugin_descriptor(plugin_key, descriptor) || descriptor.plugin_root.empty()) + return false; + + // A sandbox plugin may not have a sidecar yet. Seed the small amount of install metadata + // needed by the writer so clicking Yes still creates the JSON file. + if (state.plugin_name.empty()) { + state.installed_from = descriptor.is_cloud_plugin() ? "cloud" : "local"; + state.installed_version = !descriptor.installed_version.empty() ? descriptor.installed_version : descriptor.version; + state.plugin_name = descriptor.name; + state.cloud_uuid = descriptor.cloud_uuid(); + state.enabled = true; + } + + const std::string path_string = path.string(); + if (std::find(state.permissions.fs_read.begin(), state.permissions.fs_read.end(), path_string) == + state.permissions.fs_read.end()) + state.permissions.fs_read.push_back(path_string); + return write_install_state(boost::filesystem::path(descriptor.plugin_root), state); +} + +// Records a blocked event and raises PermissionError in the calling interpreter. int report_denied(PluginAuditManager& mgr, const std::string& event_name, - const boost::filesystem::path& path, + const boost::filesystem::path& target, const AuditDecision& decision) { AuditViolation violation; violation.plugin_key = mgr.current_plugin(); violation.event_name = event_name; - violation.path = path; + violation.path = target; violation.reason = decision.reason; mgr.report_violation(violation); - PyErr_SetString(PyExc_PermissionError, "Plugin attempted to access a blocked file path"); + PyErr_SetString(PyExc_PermissionError, "Plugin attempted an audited operation without permission"); return -1; } -} // namespace +} // namespace PluginAuditDetail int PluginAuditManager::audit_hook(const char* event, PyObject* args, void* user_data) { @@ -336,73 +484,53 @@ int PluginAuditManager::audit_hook(const char* event, PyObject* args, void* user BOOST_LOG_TRIVIAL(debug) << "[AUDIT EVENT] " << event_name; } - // extensive list of audit events can be found at https://docs.python.org/3/library/audit_events.html - - // --- open event --- - if (event_name == "open") { - const char* path_cstr = nullptr; - const char* mode_cstr = nullptr; - int flags = 0; - - // open(path, mode, flags) — path may be str, bytes, or int fd - if (!PyArg_ParseTuple(args, "s|si", &path_cstr, &mode_cstr, &flags)) { - PyErr_Clear(); // couldn't parse; allow - return 0; - } - - std::string path_str(path_cstr ? path_cstr : ""); - std::string mode_str(mode_cstr ? mode_cstr : "r"); - - AuditDecision decision = mgr->check_open(path_str, mode_str); - if (!decision.allowed) - return report_denied(*mgr, event_name, path_str, decision); + if (mgr->current_plugin().empty()) return 0; + + PluginInstallState state; + const bool have_install_state = PluginManager::instance().get_install_state(mgr->current_plugin(), state); + if (!have_install_state) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Failed to get install state for " << mgr->current_plugin(); } - // --- os.rename event (raised by os.rename and os.replace) --- - if (event_name == "os.rename") { - const char* src_cstr = nullptr; - const char* dst_cstr = nullptr; - PyObject* src_dir_fd = nullptr; - PyObject* dst_dir_fd = nullptr; + const std::string plugin_name = state.plugin_name.empty() ? mgr->current_plugin() : state.plugin_name; + const std::vector paths = PluginAuditDetail::filesystem_paths(event_name, args); + for (const auto& path : paths) { + if (PluginAuditDetail::has_filesystem_permission(state, path)) + continue; - // os.rename(src, dst, src_dir_fd, dst_dir_fd) — paths may be str, bytes, or int fd. - // The dir_fd arguments are unused, but must be accepted for the tuple to parse. - if (!PyArg_ParseTuple(args, "ss|OO", &src_cstr, &dst_cstr, &src_dir_fd, &dst_dir_fd)) { - PyErr_Clear(); // couldn't parse; allow - return 0; - } + wxMessageDialog dialog( + nullptr, + wxString::Format(_L("Plugin \"%s\" is requesting filesystem access to:\n%s"), + wxString::FromUTF8(plugin_name.c_str()), + wxString::FromUTF8(path.string().c_str())), + _L("Plugin permission request"), + wxYES_NO | wxICON_WARNING); + if (dialog.ShowModal() == wxID_YES && + PluginAuditDetail::persist_filesystem_permission(mgr->current_plugin(), state, path)) + continue; - // A rename writes at both ends, so either end being denied blocks the call. - for (const char* path_cstr : {src_cstr, dst_cstr}) { - std::string path_str(path_cstr ? path_cstr : ""); - AuditDecision decision = mgr->check_path_access(path_str, /* is_write */ true); - if (!decision.allowed) - return report_denied(*mgr, event_name, path_str, decision); - } - return 0; + return PluginAuditDetail::report_denied( + *mgr, event_name, path, {false, "filesystem permission required"}); } - // --- os.remove event (raised by os.remove and os.unlink) --- - if (event_name == "os.remove") { - const char* path_cstr = nullptr; - PyObject* dir_fd = nullptr; - - // os.remove(path, dir_fd) — path may be str, bytes, or int fd - if (!PyArg_ParseTuple(args, "s|O", &path_cstr, &dir_fd)) { - PyErr_Clear(); // couldn't parse; allow - return 0; - } - - std::string path_str(path_cstr ? path_cstr : ""); - AuditDecision decision = mgr->check_path_access(path_str, /* is_write */ true); - if (!decision.allowed) - return report_denied(*mgr, event_name, path_str, decision); + if (!paths.empty()) return 0; - } - // Unknown event — allow by default - return 0; + wxMessageDialog dialog( + nullptr, + wxString::Format( + _L("Plugin \"%s\" is requesting permission for the Python audit event \"%s\".\n\n" + "This operation does not expose a filesystem path to the audit hook."), + wxString::FromUTF8(plugin_name.c_str()), + wxString::FromUTF8(event_name.c_str())), + _L("Plugin permission request"), + wxYES_NO | wxICON_WARNING); + if (dialog.ShowModal() == wxID_YES) + return 0; + + return PluginAuditDetail::report_denied( + *mgr, event_name, boost::filesystem::path(), {false, "audit permission required"}); } void PluginAuditManager::install_hook() @@ -413,10 +541,10 @@ void PluginAuditManager::install_hook() } BOOST_LOG_TRIVIAL(info) << "[AUDIT] CPython audit hook installed successfully"; - // data_dir() is the only globally-allowed root during enforced plugin execution. + // data_dir() is the only globally-allowed root during plugin execution. // The executable directory and resources directory are intentionally NOT allowed - // here: plugins must not write outside data_dir() (G-code plugins additionally get - // the temp G-code folder via a scoped root). Reads remain permissive in Loading mode. + // here: plugins must not access outside data_dir() (G-code plugins additionally get + // the temp G-code folder via a scoped root). add_global_allowed_root(data_dir()); // The user's app config and cloud credentials live directly inside data_dir(), so the diff --git a/src/slic3r/plugin/PluginAuditManager.hpp b/src/slic3r/plugin/PluginAuditManager.hpp index 1b24357e47..f3fb43d20a 100644 --- a/src/slic3r/plugin/PluginAuditManager.hpp +++ b/src/slic3r/plugin/PluginAuditManager.hpp @@ -2,6 +2,7 @@ #define slic3r_PluginAuditManager_hpp_ #include +#include #include #include #include @@ -53,8 +54,8 @@ public: void add_scoped_allowed_root(const boost::filesystem::path& root); // --- denied-filenames registry --- - // Filenames a plugin may never touch, in any directory, regardless of audit mode or - // enclosing allowed root. A candidate is denied when its filename starts with a + // Filenames a plugin may never touch, in any directory, regardless of the enclosing allowed + // root. A candidate is denied when its filename starts with a // registered name, so .bak/.tmp companions are covered by the same entry. // // The comparison is case-insensitive on every platform, unlike the _WIN32-only iequals @@ -73,30 +74,23 @@ public: // 8.3 short name is out of scope (see the design doc). This blocks direct access only. bool is_denied_filename(const boost::filesystem::path& candidate) const; - // --- enforcement mode --- - enum class AuditMode { - // Import/loading phase: allow reads anywhere, only block writes - // outside allowed roots. Python needs to read stdlib modules - // during import and those are not inside plugin directories. - Loading, - - // Execution phase: block both reads and writes outside allowed - // roots, plus subprocess/socket/ctypes. - Enforcing, - }; - - void set_audit_mode(AuditMode mode); - AuditMode audit_mode() const; - // --- policy checks --- // Shared core for every audited filesystem event. The deny list is consulted above the - // Loading-mode read exemption and above the allowed roots, so a denied filename is - // blocked even though every scope currently runs in Loading and the files in question - // sit inside data_dir(), which is itself a global allowed root. + // allowed roots, so a denied filename is blocked even when the file sits inside data_dir(), + // which is itself a global allowed root. AuditDecision check_path_access(const boost::filesystem::path& candidate, bool is_write); AuditDecision check_open(const std::string& path, const std::string& mode); + // Ask the user to grant the requested filesystem-read paths. The request may originate on a + // plugin load worker, so the implementation marshals the modal dialog to the wx main thread. + // Returns true only when every missing path was granted and persisted; denial aborts the plugin + // load without adding a permission. + bool request_filesystem_read_permissions(const std::string& plugin_key, + const std::vector& paths); + void report_violation(const AuditViolation& violation); + bool audit_denial_pending() const; + void clear_audit_denial(); void clear_last_violation(); bool last_violation(AuditViolation& violation) const; @@ -109,12 +103,12 @@ private: static int audit_hook(const char* event, PyObject* args, void* user_data); - static thread_local std::string m_current_plugin_key; - static thread_local std::string m_current_capability_name; - static thread_local AuditMode m_audit_mode; + static thread_local std::string m_current_plugin_key; + static thread_local std::string m_current_capability_name; static thread_local std::vector m_scoped_allowed_roots; - static thread_local bool m_has_last_violation; - static thread_local AuditViolation m_last_violation; + static thread_local bool m_audit_denial_pending; + static thread_local bool m_has_last_violation; + static thread_local AuditViolation m_last_violation; // mutable: is_denied_filename() is a const query that must lock. mutable std::mutex m_mutex; @@ -130,8 +124,7 @@ class ScopedPluginAuditContext public: explicit ScopedPluginAuditContext( const std::string& plugin_key, - const std::string& capability_name = {}, - PluginAuditManager::AuditMode mode = PluginAuditManager::AuditMode::Loading); + const std::string& capability_name = {}); ~ScopedPluginAuditContext(); @@ -141,7 +134,6 @@ public: private: std::string m_previous_id; std::string m_previous_capability; - PluginAuditManager::AuditMode m_previous_mode; std::vector m_previous_scoped_roots; }; diff --git a/src/slic3r/plugin/PluginFsUtils.cpp b/src/slic3r/plugin/PluginFsUtils.cpp index b0867ef28f..dc7cd1ee7c 100644 --- a/src/slic3r/plugin/PluginFsUtils.cpp +++ b/src/slic3r/plugin/PluginFsUtils.cpp @@ -784,6 +784,23 @@ bool read_install_state(const boost::filesystem::path& plugin_dir, PluginInstall parsed.plugin_name = state["plugin_name"].get(); if (state.contains("cloud_uuid") && state["cloud_uuid"].is_string()) parsed.cloud_uuid = state["cloud_uuid"].get(); + + if (state.contains("permissions") && state["permissions"].is_object()) { + const auto& permissions = state["permissions"]; + if (permissions.contains("networking") && permissions["networking"].is_array()) + for (const auto& host : permissions["networking"]) + if (host.is_string()) + parsed.permissions.networking.push_back(host.get()); + if (permissions.contains("fs_read") && permissions["fs_read"].is_array()) + for (const auto& path : permissions["fs_read"]) + if (path.is_string()) + parsed.permissions.fs_read.push_back(path.get()); + if (permissions.contains("fs_write") && permissions["fs_write"].is_array()) + for (const auto& path : permissions["fs_write"]) + if (path.is_string()) + parsed.permissions.fs_write.push_back(path.get()); + } + if (state.contains("enabled") && state["enabled"].is_boolean()) parsed.enabled = state["enabled"].get(); @@ -819,6 +836,12 @@ bool write_install_state(const boost::filesystem::path& plugin_dir, const Plugin if (!state.cloud_uuid.empty()) json["cloud_uuid"] = state.cloud_uuid; + json["permissions"] = { + {"networking", state.permissions.networking}, + {"fs_read", state.permissions.fs_read}, + {"fs_write", state.permissions.fs_write}, + }; + nlohmann::json capabilities = nlohmann::json::array(); for (const auto& [name, enabled] : state.capabilities) capabilities.push_back(nlohmann::json{{name, enabled}}); @@ -836,6 +859,9 @@ bool write_install_state(const boost::filesystem::path& plugin_dir, const Plugin const std::vector>& capabilities) { PluginInstallState state; + // Loading a plugin updates its lifecycle/capability state, but must retain permissions granted + // during register_capabilities() or by a previous runtime audit prompt. + read_install_state(plugin_dir, state); state.installed_from = entry.is_cloud_plugin() ? "cloud" : "local"; // Prefer the descriptor's recorded installed_version (the version fetched from the cloud // at install time, preserved across sidecar re-writes) so a stale manifest/PEP723 header @@ -852,10 +878,16 @@ bool write_install_state(const boost::filesystem::path& plugin_dir, const Plugin bool write_install_state(const boost::filesystem::path& plugin_dir, const PluginDescriptor& entry) { // Install-time writer: the package is not loaded, so its capabilities are not known yet and the - // sidecar is (re)initialized to "auto-load, nothing disabled". PluginManager writes the real - // per-capability flags once the package is loaded, via the (dir, entry, enabled, capabilities) - // overload. - return write_install_state(plugin_dir, entry, true, {}); + // sidecar is (re)initialized to "auto-load, nothing disabled". This intentionally resets + // permissions on a fresh install/reinstall. PluginManager writes the real per-capability flags + // while preserving permissions once the package is loaded, via the overload above. + PluginInstallState state; + state.installed_from = entry.is_cloud_plugin() ? "cloud" : "local"; + state.installed_version = !entry.installed_version.empty() ? entry.installed_version : entry.version; + state.plugin_name = entry.name; + state.cloud_uuid = entry.cloud_uuid(); + state.enabled = true; + return write_install_state(plugin_dir, state); } bool read_python_plugin_metadata(const boost::filesystem::path& py_path, PluginDescriptor& descriptor, std::string& error) diff --git a/src/slic3r/plugin/PluginFsUtils.hpp b/src/slic3r/plugin/PluginFsUtils.hpp index f65a5e0e69..d361d9d9ac 100644 --- a/src/slic3r/plugin/PluginFsUtils.hpp +++ b/src/slic3r/plugin/PluginFsUtils.hpp @@ -81,11 +81,21 @@ inline nlohmann::json py_to_json(const pybind11::handle& o) return py::str(o).cast(); // fallback: str() } +struct PluginPermissions +{ + std::vector networking; + std::vector fs_read; + std::vector fs_write; +}; + struct PluginInstallState { std::string installed_from; // "local" | "cloud" std::string installed_version; std::string plugin_name; std::string cloud_uuid; // empty for local + + PluginPermissions permissions; + bool enabled = true; std::vector> capabilities; // name -> enabled, ordered }; diff --git a/src/slic3r/plugin/PluginLoader.cpp b/src/slic3r/plugin/PluginLoader.cpp index 92fe92068f..0c45564f1b 100644 --- a/src/slic3r/plugin/PluginLoader.cpp +++ b/src/slic3r/plugin/PluginLoader.cpp @@ -280,7 +280,7 @@ bool load(const PluginDescriptor& descriptor, // (while the active plugin key is set), then instantiates each registered capability and caches // its get_name(). Returns one entry per capability. std::string bridge_error; - auto capabilities_found = bridge.finalize_plugin_capture(descriptor.entry_path, bridge_error); + auto capabilities_found = bridge.finalize_plugin_capture(descriptor.entry_path, descriptor.plugin_key, bridge_error); if (!bridge_error.empty()) { capabilities_found.clear(); error = "Plugin registration failed: " + bridge_error; diff --git a/src/slic3r/plugin/PluginManager.cpp b/src/slic3r/plugin/PluginManager.cpp index c586aafe99..5e97305ae7 100644 --- a/src/slic3r/plugin/PluginManager.cpp +++ b/src/slic3r/plugin/PluginManager.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -552,6 +553,20 @@ std::shared_ptr PluginManager::get_plugin_capability( return nullptr; } +bool PluginManager::get_install_state(const std::string& plugin_key, PluginInstallState& install_state) +{ + PluginDescriptor descriptor; + if (!try_get_plugin_descriptor(plugin_key, descriptor)) { + return false; + } + + if (!read_install_state(boost::filesystem::path(descriptor.plugin_root), install_state)) { + return false; + } + + return true; +} + // ── Lifecycle ─────────────────────────────────────────────────────────────────────────────── bool PluginManager::is_plugin_loaded(const std::string& plugin_key) const @@ -840,6 +855,8 @@ void PluginManager::load_plugin_impl(const std::string& plugin_key, bool skip_de if (!plugin_loader::load(descriptor, skip_deps, capabilities_to_enable, registry_precheck, plugin, error)) { if (error == LOAD_CANCELLED) return; // cancelled: nothing materialized survives, and no error is recorded + if (error.rfind("Plugin registration failed:", 0) == 0) + mark_plugin_install_state_disabled(plugin_key); fail(std::move(error)); return; } @@ -1065,6 +1082,31 @@ void PluginManager::write_loaded_plugin_install_state(const std::string& plugin_ write_install_state(boost::filesystem::path(descriptor.plugin_root), descriptor, /*enabled=*/true, capabilities); } +void PluginManager::mark_plugin_install_state_disabled(const std::string& plugin_key) +{ + std::lock_guard state_lock(m_install_state_mutex); + + PluginDescriptor descriptor; + if (!try_get_plugin_descriptor(plugin_key, descriptor) || descriptor.plugin_root.empty()) + return; + + const boost::filesystem::path root(descriptor.plugin_root); + PluginInstallState state; + if (!read_install_state(root, state)) { + state.installed_from = descriptor.is_cloud_plugin() ? "cloud" : "local"; + state.installed_version = !descriptor.installed_version.empty() ? descriptor.installed_version : descriptor.version; + state.plugin_name = descriptor.name; + state.cloud_uuid = descriptor.cloud_uuid(); + } + state.enabled = false; + if (!write_install_state(root, state)) + return; + + std::lock_guard lock(m_mutex); + if (Plugin* plugin = find_plugin_locked(plugin_key)) + plugin->descriptor.enabled = false; +} + // ── Callbacks ─────────────────────────────────────────────────────────────────────────────── void PluginManager::subscribe_on_load_callback(PluginLifecycleCompleteFn fn) diff --git a/src/slic3r/plugin/PluginManager.hpp b/src/slic3r/plugin/PluginManager.hpp index 59a2791355..d6fab5fa7f 100644 --- a/src/slic3r/plugin/PluginManager.hpp +++ b/src/slic3r/plugin/PluginManager.hpp @@ -150,6 +150,8 @@ public: PluginCapabilityType type = PluginCapabilityType::Unknown, bool only_enabled = true) const; + bool get_install_state(const std::string& plugin_key, PluginInstallState& install_state); + void load_plugin(const std::string& plugin_key, bool skip_deps = false, std::vector capabilities_to_enable = {}); bool unload_plugin(const std::string& plugin_key); void unload_all_plugins(); @@ -248,6 +250,7 @@ private: // Writes the sidecar for a loaded plugin (enabled=true plus the current per-capability flags). void write_loaded_plugin_install_state(const std::string& plugin_key); + void mark_plugin_install_state_disabled(const std::string& plugin_key); bool finalize_cloud_plugin_removal(const PluginDescriptor& plugin, bool keep_local, std::string& error); bool delete_installed_plugin_package(const PluginDescriptor& plugin, std::string& error); diff --git a/src/slic3r/plugin/PyPluginTrampoline.hpp b/src/slic3r/plugin/PyPluginTrampoline.hpp index e36c0b375c..ad7fe25f10 100644 --- a/src/slic3r/plugin/PyPluginTrampoline.hpp +++ b/src/slic3r/plugin/PyPluginTrampoline.hpp @@ -26,25 +26,30 @@ try { \ override_call; \ } catch (pybind11::error_already_set & err) { \ + const bool _orca_audit_denial = ::Slic3r::PluginAuditManager::instance().audit_denial_pending(); \ + if (_orca_audit_denial) \ + ::Slic3r::PluginAuditManager::instance().clear_current_plugin(); \ ::Slic3r::log_python_exception_keep(err); \ + if (_orca_audit_denial) \ + ::Slic3r::PluginAuditManager::instance().clear_audit_denial(); \ throw; \ } // Opens the plugin's filesystem audit scope for the duration of a C++ -> Python call, and publishes // the calling capability's cached name so host APIs invoked from Python can tell which capability // they are serving. No-op without an audit plugin key. Declares a local `_orca_audit_scope`. -#define ORCA_PY_AUDIT_SCOPE(mode) \ +#define ORCA_PY_AUDIT_SCOPE() \ std::optional<::Slic3r::ScopedPluginAuditContext> _orca_audit_scope; \ if (const std::string& _orca_audit_key = this->audit_plugin_key(); !_orca_audit_key.empty()) \ - _orca_audit_scope.emplace(_orca_audit_key, this->name(), mode) + _orca_audit_scope.emplace(_orca_audit_key, this->name()) -#define ORCA_PY_OVERRIDE_AUDITED(mode, audit_setup, override_macro, ret, base, name, ...) \ +#define ORCA_PY_OVERRIDE_AUDITED(audit_setup, override_macro, ret, base, name, ...) \ do { \ ::Slic3r::PluginCapabilityInterface::RefCounter _orca_ref_counter(*this); \ ::Slic3r::PythonGILState _orca_python_gil; \ if (!_orca_python_gil) \ throw std::runtime_error("Python interpreter is shutting down"); \ - ORCA_PY_AUDIT_SCOPE(mode); \ + ORCA_PY_AUDIT_SCOPE(); \ if (_orca_audit_scope) \ audit_setup(); \ ORCA_PY_LOGGED_OVERRIDE_BODY(override_macro(ret, base, name, ##__VA_ARGS__)); \ @@ -58,7 +63,7 @@ public: std::string get_name() const override { - ORCA_PY_OVERRIDE_AUDITED(::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, std::string, Base, get_name); + ORCA_PY_OVERRIDE_AUDITED([] {}, PYBIND11_OVERRIDE_PURE, std::string, Base, get_name); } // Config UI hooks. Available on every capability type, so they live here rather than in @@ -66,7 +71,6 @@ public: bool has_config_ui() const override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE, bool, @@ -77,7 +81,6 @@ public: std::string get_config_ui() const override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE, std::string, @@ -94,7 +97,7 @@ public: // mistake), both fall back to the base's empty object rather than writing `"cap_config": null`. nlohmann::json get_default_config() const override { - ORCA_PY_AUDIT_SCOPE(::Slic3r::PluginAuditManager::AuditMode::Loading); + ORCA_PY_AUDIT_SCOPE(); try { pybind11::gil_scoped_acquire gil; pybind11::function override = pybind11::get_override(static_cast(this), "get_default_config"); @@ -117,17 +120,17 @@ public: void on_load() override { - ORCA_PY_OVERRIDE_AUDITED(::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE, void, Base, on_load); + ORCA_PY_OVERRIDE_AUDITED([] {}, PYBIND11_OVERRIDE, void, Base, on_load); } void on_unload() override { - ORCA_PY_OVERRIDE_AUDITED(::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE, void, Base, on_unload); + ORCA_PY_OVERRIDE_AUDITED([] {}, PYBIND11_OVERRIDE, void, Base, on_unload); } void on_cancelled() override { - ORCA_PY_OVERRIDE_AUDITED(::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE, void, Base, on_cancelled); + ORCA_PY_OVERRIDE_AUDITED([] {}, PYBIND11_OVERRIDE, void, Base, on_cancelled); } }; @@ -139,7 +142,7 @@ public: PluginCapabilityType get_type() const override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE, PluginCapabilityType, PluginCapabilityInterface, + [] {}, PYBIND11_OVERRIDE, PluginCapabilityType, PluginCapabilityInterface, get_type); } }; diff --git a/src/slic3r/plugin/PythonPluginBridge.cpp b/src/slic3r/plugin/PythonPluginBridge.cpp index 328ebbace1..6c3c4fc8d2 100644 --- a/src/slic3r/plugin/PythonPluginBridge.cpp +++ b/src/slic3r/plugin/PythonPluginBridge.cpp @@ -1,5 +1,6 @@ #include "PythonPluginBridge.hpp" +#include #include #include #include @@ -39,6 +40,7 @@ thread_local std::string g_active_plugin_key; std::mutex g_registry_mutex; std::unordered_map> g_pending_capabilities; std::unordered_map g_pending_package; +std::unordered_map> g_pending_fs_read_permissions; struct PluginInstanceHandle { // The C++ plugin interface points into a Python object. Keep both alive through one @@ -76,6 +78,8 @@ void discard_pending_capture_without_python(const std::string& plugin_key) (void) package->second.release(); g_pending_package.erase(package); } + + g_pending_fs_read_permissions.erase(plugin_key); } } // namespace @@ -100,34 +104,38 @@ void PythonPluginBridge::begin_plugin_capture(const std::string& plugin_key) // for this same entry path. g_pending_capabilities.erase(plugin_key); g_pending_package.erase(plugin_key); + g_pending_fs_read_permissions.erase(plugin_key); } // From now until finalize/cancel, @orca.plugin and register_capability() calls made by // Python code on this thread are attributed to this plugin. g_active_plugin_key = plugin_key; } -std::vector PythonPluginBridge::finalize_plugin_capture(const std::string& plugin_key, std::string& error) +std::vector PythonPluginBridge::finalize_plugin_capture(const std::string& capture_key, + const std::string& plugin_key, + std::string& error) { PythonGILState gil; if (!gil) { error = "Python interpreter is shutting down"; return {}; } - BOOST_LOG_TRIVIAL(info) << "Finalizing Python plugin capture for key " << plugin_key; + BOOST_LOG_TRIVIAL(info) << "Finalizing Python plugin capture for key " << capture_key; // Phase 1: run the package class's register_capabilities() while the active key is // still set. That method is expected to call orca.register_capability() once per // capability class, and register_capability() needs g_active_plugin_key to know which // pending bucket to append to. { - auto clear_active_key = [&plugin_key]() { - if (g_active_plugin_key == plugin_key) + auto clear_active_key = [&capture_key]() { + if (g_active_plugin_key == capture_key) g_active_plugin_key.clear(); }; - auto discard_pending_for_key = [&plugin_key]() { + auto discard_pending_for_key = [&capture_key]() { std::lock_guard lock(g_registry_mutex); - g_pending_capabilities.erase(plugin_key); - g_pending_package.erase(plugin_key); + g_pending_capabilities.erase(capture_key); + g_pending_package.erase(capture_key); + g_pending_fs_read_permissions.erase(capture_key); }; try { @@ -137,7 +145,7 @@ std::vector PythonPluginBridge::finalize_plugin_capture(cons py::object package_cls; { std::lock_guard lock(g_registry_mutex); - auto it = g_pending_package.find(plugin_key); + auto it = g_pending_package.find(capture_key); if (it != g_pending_package.end()) { package_cls = it->second; g_pending_package.erase(it); @@ -156,6 +164,33 @@ std::vector PythonPluginBridge::finalize_plugin_capture(cons // are kept. py::object package = package_cls(); package.attr("register_capabilities")(); + + // Permission declarations are collected while register_capabilities() runs so the + // plugin can describe its needs without touching wx from the Python load worker. Ask + // only after registration returns, before capability instances are materialized. + std::vector fs_read_permissions; + { + std::lock_guard lock(g_registry_mutex); + auto it = g_pending_fs_read_permissions.find(capture_key); + if (it != g_pending_fs_read_permissions.end()) { + fs_read_permissions = std::move(it->second); + g_pending_fs_read_permissions.erase(it); + } + } + if (!fs_read_permissions.empty()) { + bool granted = false; + { + py::gil_scoped_release release; + granted = PluginAuditManager::instance().request_filesystem_read_permissions(plugin_key, fs_read_permissions); + } + if (!granted) { + error = "Plugin filesystem read permission request denied"; + BOOST_LOG_TRIVIAL(warning) << error << " for key " << plugin_key; + discard_pending_for_key(); + clear_active_key(); + return {}; + } + } } catch (py::error_already_set& err) { log_python_exception_keep(err); error = err.what(); @@ -179,7 +214,7 @@ std::vector PythonPluginBridge::finalize_plugin_capture(cons std::vector classes; { std::lock_guard lock(g_registry_mutex); - auto it = g_pending_capabilities.find(plugin_key); + auto it = g_pending_capabilities.find(capture_key); if (it != g_pending_capabilities.end()) { classes = std::move(it->second); g_pending_capabilities.erase(it); @@ -188,10 +223,10 @@ std::vector PythonPluginBridge::finalize_plugin_capture(cons // Registration is complete. Later register_capability() calls should fail instead of // accidentally attaching themselves to this plugin. - if (g_active_plugin_key == plugin_key) + if (g_active_plugin_key == capture_key) g_active_plugin_key.clear(); - BOOST_LOG_TRIVIAL(info) << "Collected " << classes.size() << " registered capability class(es) for key " << plugin_key; + BOOST_LOG_TRIVIAL(info) << "Collected " << classes.size() << " registered capability class(es) for key " << capture_key; std::vector capabilities; capabilities.reserve(classes.size()); @@ -203,7 +238,7 @@ std::vector PythonPluginBridge::finalize_plugin_capture(cons py::object instance = cls(); if (!py::isinstance(instance)) { error = "Registered capability must inherit from a PluginCapability base"; - BOOST_LOG_TRIVIAL(error) << "Python plugin capture failed type check for key " << plugin_key + BOOST_LOG_TRIVIAL(error) << "Python plugin capture failed type check for key " << capture_key << " error=" << error; return {}; } @@ -211,7 +246,7 @@ std::vector PythonPluginBridge::finalize_plugin_capture(cons auto capability_iface = instance.cast>(); if (!capability_iface) { error = "Failed to cast Python capability to PluginCapabilityInterface"; - BOOST_LOG_TRIVIAL(error) << "Python plugin capture failed cast for key " << plugin_key + BOOST_LOG_TRIVIAL(error) << "Python plugin capture failed cast for key " << capture_key << " error=" << error; return {}; } @@ -225,7 +260,7 @@ std::vector PythonPluginBridge::finalize_plugin_capture(cons // here is a hard error that rejects the whole plugin capture. if (name.find(';') != std::string::npos) { error = "Capability name must not contain ';': " + name; - BOOST_LOG_TRIVIAL(error) << "Python plugin capture rejected capability for key " << plugin_key + BOOST_LOG_TRIVIAL(error) << "Python plugin capture rejected capability for key " << capture_key << " error=" << error; return {}; } @@ -245,12 +280,12 @@ std::vector PythonPluginBridge::finalize_plugin_capture(cons // log the traceback here. GIL is held for the duration of finalize_plugin_capture. log_python_exception_keep(err); error = err.what(); - BOOST_LOG_TRIVIAL(error) << "Python plugin capture raised Python exception for key " << plugin_key + BOOST_LOG_TRIVIAL(error) << "Python plugin capture raised Python exception for key " << capture_key << " error=" << error; return {}; } catch (const std::exception& ex) { error = ex.what(); - BOOST_LOG_TRIVIAL(error) << "Python plugin capture raised exception for key " << plugin_key + BOOST_LOG_TRIVIAL(error) << "Python plugin capture raised exception for key " << capture_key << " error=" << error; return {}; } @@ -278,6 +313,7 @@ void PythonPluginBridge::cancel_plugin_capture(const std::string& plugin_key) // may already have registered under this key. g_pending_capabilities.erase(plugin_key); g_pending_package.erase(plugin_key); + g_pending_fs_read_permissions.erase(plugin_key); } if (g_active_plugin_key == plugin_key) @@ -304,6 +340,7 @@ void PythonPluginBridge::clear_pending_captures() (void) pkg.release(); } g_pending_package.clear(); + g_pending_fs_read_permissions.clear(); g_active_plugin_key.clear(); return; } @@ -312,6 +349,7 @@ void PythonPluginBridge::clear_pending_captures() BOOST_LOG_TRIVIAL(info) << "Clearing " << g_pending_capabilities.size() << " pending Python plugin capture(s)"; g_pending_capabilities.clear(); g_pending_package.clear(); + g_pending_fs_read_permissions.clear(); g_active_plugin_key.clear(); } @@ -448,6 +486,27 @@ void bind_python_api(pybind11::module_& m) }, R"pbdoc(Register a PluginCapability subclass while OrcaSlicer loads your module.)pbdoc"); + m.def( + "request_permissions", + [](const std::vector& fs_read) { + if (g_active_plugin_key.empty()) + throw py::value_error("request_permissions() called outside plugin discovery context"); + + std::lock_guard lock(g_registry_mutex); + auto& requested = g_pending_fs_read_permissions[g_active_plugin_key]; + for (const std::string& path : fs_read) { + if (path.empty()) + throw py::value_error("request_permissions(fs_read=...) does not accept empty paths"); + if (std::find(requested.begin(), requested.end(), path) == requested.end()) + requested.push_back(path); + } + }, + py::arg("fs_read") = std::vector{}, + R"pbdoc(Request filesystem read permissions while OrcaSlicer loads your module. + +The host presents the request to the user after register_capabilities() returns. Denying the +request aborts the plugin load.)pbdoc"); + m.def("plugin", [](py::object cls) { if (g_active_plugin_key.empty()) throw py::value_error("@orca.plugin used outside plugin discovery context"); diff --git a/src/slic3r/plugin/PythonPluginBridge.hpp b/src/slic3r/plugin/PythonPluginBridge.hpp index 6ccadabd00..036c8f1941 100644 --- a/src/slic3r/plugin/PythonPluginBridge.hpp +++ b/src/slic3r/plugin/PythonPluginBridge.hpp @@ -31,7 +31,7 @@ public: // Returns one CapturedCapability per capability, or an empty vector on failure // (error message populated). std::vector finalize_plugin_capture( - const std::string& plugin_key, std::string& error); + const std::string& capture_key, const std::string& plugin_key, std::string& error); // Clear any pending registrations for the key. Safe to call when import fails. void cancel_plugin_capture(const std::string& plugin_key); diff --git a/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapabilityTrampoline.hpp b/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapabilityTrampoline.hpp index 226ea04650..5491e1cef6 100644 --- a/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapabilityTrampoline.hpp +++ b/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapabilityTrampoline.hpp @@ -16,206 +16,206 @@ public: AgentInfo get_agent_info() override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, AgentInfo, PrinterAgentPluginCapability, + [] {}, PYBIND11_OVERRIDE_PURE, AgentInfo, PrinterAgentPluginCapability, get_agent_info); } int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, connect_printer, dev_id, + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, connect_printer, dev_id, dev_ip, username, password, use_ssl); } int disconnect_printer() override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, disconnect_printer); + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, disconnect_printer); } int send_message(std::string dev_id, std::string json_str, int qos, int flag) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, send_message, dev_id, + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, send_message, dev_id, json_str, qos, flag); } int send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, send_message_to_printer, + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, send_message_to_printer, dev_id, json_str, qos, flag); } bool start_discovery(bool start, bool sending) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, bool, PrinterAgentPluginCapability, start_discovery, start, + [] {}, PYBIND11_OVERRIDE_PURE, bool, PrinterAgentPluginCapability, start_discovery, start, sending); } int bind_detect(std::string dev_ip, std::string sec_link, detectResult& detect) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, bind_detect, dev_ip, + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, bind_detect, dev_ip, sec_link, detect); } std::string get_user_selected_machine() override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, std::string, PrinterAgentPluginCapability, + [] {}, PYBIND11_OVERRIDE_PURE, std::string, PrinterAgentPluginCapability, get_user_selected_machine); } int set_user_selected_machine(std::string dev_id) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_user_selected_machine, dev_id); } int start_send_gcode_to_sdcard(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, start_send_gcode_to_sdcard, params, update_fn, cancel_fn, wait_fn); } int start_local_print(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, start_local_print, + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, start_local_print, params, update_fn, cancel_fn); } FilamentSyncMode get_filament_sync_mode() const override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, FilamentSyncMode, PrinterAgentPluginCapability, + [] {}, PYBIND11_OVERRIDE_PURE, FilamentSyncMode, PrinterAgentPluginCapability, get_filament_sync_mode); } bool fetch_filament_info(std::string dev_id) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, bool, PrinterAgentPluginCapability, fetch_filament_info, dev_id); + [] {}, PYBIND11_OVERRIDE_PURE, bool, PrinterAgentPluginCapability, fetch_filament_info, dev_id); } int check_cert() override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, check_cert); + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, check_cert); } void install_device_cert(std::string dev_id, bool lan_only) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, void, PrinterAgentPluginCapability, install_device_cert, dev_id, + [] {}, PYBIND11_OVERRIDE_PURE, void, PrinterAgentPluginCapability, install_device_cert, dev_id, lan_only); } int ping_bind(std::string ping_code) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, ping_bind, ping_code); + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, ping_bind, ping_code); } int bind(std::string dev_ip, std::string dev_id, std::string dev_model, std::string sec_link, std::string timezone, bool improved, OnUpdateStatusFn update_fn) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, bind, dev_ip, dev_id, + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, bind, dev_ip, dev_id, dev_model, sec_link, timezone, improved, update_fn); } int unbind(std::string dev_id) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, unbind, dev_id); + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, unbind, dev_id); } int start_print(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, start_print, params, + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, start_print, params, update_fn, cancel_fn, wait_fn); } int start_local_print_with_record(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, start_local_print_with_record, params, update_fn, cancel_fn, wait_fn); } int start_sdcard_print(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, start_sdcard_print, params, + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, start_sdcard_print, params, update_fn, cancel_fn); } int get_hms_snapshot(std::string dev_id, std::string file_name, std::function callback) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, get_hms_snapshot, dev_id, + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, get_hms_snapshot, dev_id, file_name, callback); } int set_server_callback(OnServerErrFn fn) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_server_callback, fn); + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_server_callback, fn); } int set_on_ssdp_msg_fn(OnMsgArrivedFn fn) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_on_ssdp_msg_fn, fn); + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_on_ssdp_msg_fn, fn); } int set_on_printer_connected_fn(OnPrinterConnectedFn fn) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_on_printer_connected_fn, + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_on_printer_connected_fn, fn); } int set_on_subscribe_failure_fn(GetSubscribeFailureFn fn) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_on_subscribe_failure_fn, + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_on_subscribe_failure_fn, fn); } int set_on_message_fn(OnMessageFn fn) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_on_message_fn, fn); + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_on_message_fn, fn); } int set_on_user_message_fn(OnMessageFn fn) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_on_user_message_fn, fn); + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_on_user_message_fn, fn); } int set_on_local_connect_fn(OnLocalConnectedFn fn) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_on_local_connect_fn, fn); + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_on_local_connect_fn, fn); } int set_on_local_message_fn(OnMessageFn fn) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_on_local_message_fn, fn); + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_on_local_message_fn, fn); } int set_queue_on_main_fn(QueueOnMainFn fn) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_queue_on_main_fn, fn); + [] {}, PYBIND11_OVERRIDE_PURE, int, PrinterAgentPluginCapability, set_queue_on_main_fn, fn); } // request_bind_ticket returns its ticket through a std::string* out-param, which pybind11 @@ -223,7 +223,7 @@ public: // returns a (result, ticket) tuple, which we unpack into the int result and the out-param. int request_bind_ticket(std::string* ticket) override { - ORCA_PY_AUDIT_SCOPE(::Slic3r::PluginAuditManager::AuditMode::Loading); + ORCA_PY_AUDIT_SCOPE(); ::Slic3r::PluginCapabilityInterface::RefCounter _orca_ref_counter(*this); ::Slic3r::PythonGILState gil; if (!gil) diff --git a/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapabilityTrampoline.hpp b/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapabilityTrampoline.hpp index f77d7ce597..62958a89d9 100644 --- a/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapabilityTrampoline.hpp +++ b/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapabilityTrampoline.hpp @@ -13,7 +13,6 @@ public: ExecutionResult execute() override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, ExecutionResult, diff --git a/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapabilityTrampoline.hpp b/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapabilityTrampoline.hpp index 8605532c12..5c9d527e42 100644 --- a/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapabilityTrampoline.hpp +++ b/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapabilityTrampoline.hpp @@ -10,7 +10,6 @@ public: using PyPluginCommonTrampoline::PyPluginCommonTrampoline; ExecutionResult execute(SlicingPipelineContext& ctx) override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [&]{ // At Step.psGCodePostProcess the plugin edits the exported G-code file, which lives // outside data_dir() (a temp/output folder), so writing to it would otherwise be From 2169b72c94842db859bf802d7807cca2ab0c9dae Mon Sep 17 00:00:00 2001 From: Ian Chua Date: Tue, 28 Jul 2026 19:28:58 +0800 Subject: [PATCH 02/51] fix: update tests --- tests/slic3rutils/test_plugin_audit.cpp | 21 +++++++++++++-------- tests/slic3rutils/test_plugin_install.cpp | 14 +++++++++++++- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/tests/slic3rutils/test_plugin_audit.cpp b/tests/slic3rutils/test_plugin_audit.cpp index 49eedbd1fb..20fc2b86e7 100644 --- a/tests/slic3rutils/test_plugin_audit.cpp +++ b/tests/slic3rutils/test_plugin_audit.cpp @@ -81,7 +81,7 @@ TEST_CASE("Plugin audit denies app config and token filenames anywhere", "[audit } } -TEST_CASE("Plugin audit deny beats allowed roots and the Loading read exemption", "[audit]") +TEST_CASE("Plugin audit deny beats allowed roots", "[audit]") { ScopedDataDir data_dir_guard("plugin-audit-deny"); seed_denied_names(); @@ -91,8 +91,8 @@ TEST_CASE("Plugin audit deny beats allowed roots and the Loading read exemption" // config and the token would otherwise be reachable simply by living inside it. mgr.add_global_allowed_root(data_dir()); - // Enter a plugin context. The deny must hold in Loading mode, which every scope runs in. - ScopedPluginAuditContext ctx("test_plugin", "", PluginAuditManager::AuditMode::Loading); + // Enter a plugin context. The deny must hold even inside a globally allowed root. + ScopedPluginAuditContext ctx("test_plugin", ""); const fs::path conf = fs::path(data_dir()) / (SLIC3R_APP_KEY ".conf"); const fs::path token = fs::path(data_dir()) / secret_constants::USER_SECRET_FILENAME; @@ -103,6 +103,13 @@ TEST_CASE("Plugin audit deny beats allowed roots and the Loading read exemption" CHECK(decision.allowed); } + SECTION("a file outside the allowed root is blocked for reads as well as writes") + { + AuditDecision decision = mgr.check_open((fs::path(data_dir()).parent_path() / "outside.txt").string(), "r"); + CHECK_FALSE(decision.allowed); + CHECK(decision.reason == "outside allowed root"); + } + SECTION("writing the app config is blocked despite data_dir() being allowed") { AuditDecision decision = mgr.check_open(conf.string(), "w"); @@ -110,16 +117,14 @@ TEST_CASE("Plugin audit deny beats allowed roots and the Loading read exemption" CHECK(decision.reason == "denied filename"); } - SECTION("reading the app config is blocked even though Loading exempts reads") + SECTION("reading the app config is blocked despite the allowed root") { - // Without the deny, a read in Loading mode short-circuits to allow. The deny sits above - // that exemption, so this must still be blocked. AuditDecision decision = mgr.check_open(conf.string(), "r"); CHECK_FALSE(decision.allowed); CHECK(decision.reason == "denied filename"); } - SECTION("reading the cloud refresh token is blocked in Loading mode") + SECTION("reading the cloud refresh token is blocked") { AuditDecision decision = mgr.check_open(token.string(), "r"); CHECK_FALSE(decision.allowed); @@ -150,7 +155,7 @@ TEST_CASE("Plugin audit deny beats a plugin's own scoped root", "[audit]") const fs::path plugin_dir = fs::path(data_dir()) / "plugins" / "test_plugin"; fs::create_directories(plugin_dir); - ScopedPluginAuditContext ctx("test_plugin", "", PluginAuditManager::AuditMode::Loading); + ScopedPluginAuditContext ctx("test_plugin", ""); mgr.add_scoped_allowed_root(plugin_dir); SECTION("the plugin's own non-denied file opens for read and write") diff --git a/tests/slic3rutils/test_plugin_install.cpp b/tests/slic3rutils/test_plugin_install.cpp index fceeaf1f83..c6ad670ff7 100644 --- a/tests/slic3rutils/test_plugin_install.cpp +++ b/tests/slic3rutils/test_plugin_install.cpp @@ -112,6 +112,18 @@ TEST_CASE("install-state sidecar is the source of truth for a cloud plugin's ins REQUIRE(read_install_state(plugin_dir, state)); CHECK(state.installed_version == "1.2.0"); + state.permissions.networking = {"api.example.com", "192.168.45.6"}; + state.permissions.fs_read = {"/path/to/read"}; + state.permissions.fs_write = {"/path/to/write"}; + REQUIRE(write_install_state(plugin_dir, state)); + + // Permission data is persisted in the same sidecar as the installation metadata. + PluginInstallState persisted; + REQUIRE(read_install_state(plugin_dir, persisted)); + CHECK(persisted.permissions.networking == state.permissions.networking); + CHECK(persisted.permissions.fs_read == state.permissions.fs_read); + CHECK(persisted.permissions.fs_write == state.permissions.fs_write); + // Reading the sidecar back onto a freshly-scanned descriptor (whose header version is still // 1.0.0) must surface the cloud-installed 1.2.0. This is what lets update_cloud_metadata compare // the cloud's latest version against the installed version instead of the stale header, so an @@ -120,4 +132,4 @@ TEST_CASE("install-state sidecar is the source of truth for a cloud plugin's ins scanned.version = "1.0.0"; // as parsed from the unchanged PEP723 header read_install_state(plugin_dir, scanned); CHECK(scanned.installed_version == "1.2.0"); -} \ No newline at end of file +} From 35970f61dcd3c4b8e03092df7b2fe88f77cecf49 Mon Sep 17 00:00:00 2001 From: Ian Chua Date: Wed, 29 Jul 2026 16:52:16 +0800 Subject: [PATCH 03/51] fix: lift audit while reporting errors to log files --- src/slic3r/plugin/PythonInterpreter.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/slic3r/plugin/PythonInterpreter.cpp b/src/slic3r/plugin/PythonInterpreter.cpp index e46ee58f80..299a2dd7ba 100644 --- a/src/slic3r/plugin/PythonInterpreter.cpp +++ b/src/slic3r/plugin/PythonInterpreter.cpp @@ -87,6 +87,12 @@ void log_python_exception_keep(pybind11::error_already_set& err) if (!gil) return; + // Traceback output is host-owned work. In particular, the stderr tee opens the Python log + // file on every write. Keep that open outside the plugin audit context, otherwise an ordinary + // exception raised by a plugin can recursively trigger the filesystem permission dialog while + // its original exception is being reported. + ScopedPluginAuditContext audit_suppression(""); + // Non-destructive: print the traceback to sys.stderr (tee'd to the session log) // WITHOUT consuming err, so the caller can rethrow it intact. For example, downstream C++ // catchers can still read err.what() for the user-facing dialog. We must NOT use From ddd62e25df4ffb908037040faeadf562b29cae68 Mon Sep 17 00:00:00 2001 From: Ian Chua Date: Thu, 13 Aug 2026 19:16:18 +0800 Subject: [PATCH 04/51] add audit hook for fs, network and processes --- src/slic3r/plugin/PluginAuditManager.cpp | 437 ++++++++++++++++++---- src/slic3r/plugin/PluginAuditManager.hpp | 30 +- src/slic3r/plugin/PluginFsUtils.cpp | 30 +- src/slic3r/plugin/PluginFsUtils.hpp | 6 +- src/slic3r/plugin/PythonInterpreter.cpp | 4 - tests/slic3rutils/test_plugin_install.cpp | 14 +- 6 files changed, 424 insertions(+), 97 deletions(-) diff --git a/src/slic3r/plugin/PluginAuditManager.cpp b/src/slic3r/plugin/PluginAuditManager.cpp index f027dd072d..023e55bd22 100644 --- a/src/slic3r/plugin/PluginAuditManager.cpp +++ b/src/slic3r/plugin/PluginAuditManager.cpp @@ -14,12 +14,103 @@ #include #include #include +#include +#include #include +#include #include #include namespace Slic3r { +// extensive list of audit events can be found at https://docs.python.org/3/library/audit_events.html +static const std::unordered_map audit_event_categories{ + // fsread + {"glob.glob", AuditEventCategory::FsRead}, + {"glob.glob/2", AuditEventCategory::FsRead}, + {"os.fwalk", AuditEventCategory::FsRead}, + {"os.getxattr", AuditEventCategory::FsRead}, + {"os.listdir", AuditEventCategory::FsRead}, + {"os.listdrives", AuditEventCategory::FsRead}, + {"os.listmounts", AuditEventCategory::FsRead}, + {"os.listvolumes", AuditEventCategory::FsRead}, + {"os.listxattr", AuditEventCategory::FsRead}, + {"os.scandir", AuditEventCategory::FsRead}, + {"os.walk", AuditEventCategory::FsRead}, + {"pathlib.Path.glob", AuditEventCategory::FsRead}, + {"pathlib.Path.rglob", AuditEventCategory::FsRead}, + + // fsreadwrite + {"os.chflags", AuditEventCategory::FsReadWrite}, + {"os.chmod", AuditEventCategory::FsReadWrite}, + {"os.chown", AuditEventCategory::FsReadWrite}, + {"os.removexattr", AuditEventCategory::FsReadWrite}, + {"os.rename", AuditEventCategory::FsReadWrite}, + {"os.setxattr", AuditEventCategory::FsReadWrite}, + {"os.truncate", AuditEventCategory::FsReadWrite}, + {"os.utime", AuditEventCategory::FsReadWrite}, + {"shutil.chown", AuditEventCategory::FsReadWrite}, + {"shutil.copymode", AuditEventCategory::FsReadWrite}, + {"shutil.copystat", AuditEventCategory::FsReadWrite}, + {"shutil.copyfile", AuditEventCategory::FsReadWrite}, + {"shutil.copytree", AuditEventCategory::FsReadWrite}, + {"shutil.make_archive", AuditEventCategory::FsReadWrite}, + {"shutil.move", AuditEventCategory::FsReadWrite}, + {"shutil.unpack_archive", AuditEventCategory::FsReadWrite}, + + // fscreate + {"os.link", AuditEventCategory::FsCreate}, + {"os.mkdir", AuditEventCategory::FsCreate}, + {"os.symlink", AuditEventCategory::FsCreate}, + {"tempfile.mkdtemp", AuditEventCategory::FsCreate}, + {"tempfile.mkstemp", AuditEventCategory::FsCreate}, + {"_winapi.CreateJunction", AuditEventCategory::FsCreate}, + + // fsdelete + {"os.remove", AuditEventCategory::FsDelete}, + {"os.rmdir", AuditEventCategory::FsDelete}, + {"shutil.rmtree", AuditEventCategory::FsDelete}, + + // http + {"http.client.connect", AuditEventCategory::Http}, + {"http.client.send", AuditEventCategory::Http}, + {"urllib.Request", AuditEventCategory::Http}, + + // socket + {"socket.__new__", AuditEventCategory::Socket}, + {"socket.bind", AuditEventCategory::Socket}, + {"socket.connect", AuditEventCategory::Socket}, + {"socket.getaddrinfo", AuditEventCategory::Socket}, + {"socket.gethostbyaddr", AuditEventCategory::Socket}, + {"socket.gethostbyname", AuditEventCategory::Socket}, + {"socket.gethostname", AuditEventCategory::Socket}, + {"socket.getnameinfo", AuditEventCategory::Socket}, + {"socket.getservbyname", AuditEventCategory::Socket}, + {"socket.getservbyport", AuditEventCategory::Socket}, + {"socket.sendmsg", AuditEventCategory::Socket}, + {"socket.sendto", AuditEventCategory::Socket}, + + // processcreate + {"os.fork", AuditEventCategory::ProcessCreate}, + {"os.forkpty", AuditEventCategory::ProcessCreate}, + {"os.posix_spawn", AuditEventCategory::ProcessCreate}, + {"os.spawn", AuditEventCategory::ProcessCreate}, + {"os.system", AuditEventCategory::ProcessCreate}, + {"os.startfile", AuditEventCategory::ProcessCreate}, + {"os.startfile/2", AuditEventCategory::ProcessCreate}, + {"pty.spawn", AuditEventCategory::ProcessCreate}, + {"subprocess.Popen", AuditEventCategory::ProcessCreate}, + {"_winapi.CreateProcess", AuditEventCategory::ProcessCreate}, + {"_posixsubprocess.fork_exec", AuditEventCategory::ProcessCreate}, +}; + +// Returns the category event_name belongs to, or AuditEventCategory::None when it isn't audited. +static AuditEventCategory event_category(const std::string& event_name) +{ + const auto it = audit_event_categories.find(event_name); + return it == audit_event_categories.end() ? AuditEventCategory::None : it->second; +} + // --------------------------------------------------------------------------- // Path safety // --------------------------------------------------------------------------- @@ -344,7 +435,7 @@ void PluginAuditManager::report_violation(const AuditViolation& violation) m_audit_denial_pending = true; BOOST_LOG_TRIVIAL(warning) << "[AUDIT BLOCKED] plugin=" << violation.plugin_key << " event=" << violation.event_name - << " path=" << violation.path.string() << " reason=" << violation.reason; + << " reason=" << violation.reason; } bool PluginAuditManager::audit_denial_pending() const { return m_audit_denial_pending; } @@ -366,6 +457,34 @@ bool PluginAuditManager::last_violation(AuditViolation& violation) const return true; } +bool PluginAuditManager::has_approved_ancestor(const std::string& plugin_key, + const std::vector& call_site_ids) const +{ + if (plugin_key.empty() || call_site_ids.empty()) + return false; + + std::lock_guard lock(m_mutex); + auto it = m_approved_call_sites.find(plugin_key); + if (it == m_approved_call_sites.end()) + return false; + + for (const auto& id : call_site_ids) + if (it->second.count(id)) + return true; + return false; +} + +void PluginAuditManager::record_approved_call_sites(const std::string& plugin_key, + const std::vector& call_site_ids) +{ + if (plugin_key.empty() || call_site_ids.empty()) + return; + + std::lock_guard lock(m_mutex); + auto& approved = m_approved_call_sites[plugin_key]; + approved.insert(call_site_ids.begin(), call_site_ids.end()); +} + // --------------------------------------------------------------------------- // The C-level audit hook // --------------------------------------------------------------------------- @@ -398,38 +517,163 @@ std::string python_path(PyObject* object) return result; } -void add_filesystem_path(std::vector& paths, PyObject* object) +std::string python_unicode(PyObject* object) { - const std::string path = python_path(object); - if (!path.empty()) - paths.emplace_back(path); + if (!object || !PyUnicode_Check(object)) + return {}; + const char* text = PyUnicode_AsUTF8(object); + if (!text) { + PyErr_Clear(); + return {}; + } + return text; } -std::vector filesystem_paths(const std::string& event_name, PyObject* args) +std::string python_str(PyObject* object) { - std::vector paths; + if (!object) + return {}; - if (event_name == "open") { - add_filesystem_path(paths, tuple_item(args, 0)); - } else if (event_name == "os.rename") { - add_filesystem_path(paths, tuple_item(args, 0)); - add_filesystem_path(paths, tuple_item(args, 1)); - } else if (event_name == "os.remove") { - add_filesystem_path(paths, tuple_item(args, 0)); + PyObject* str_object = PyObject_Str(object); + if (!str_object) { + PyErr_Clear(); + return {}; } - return paths; + const std::string result = python_unicode(str_object); + Py_DECREF(str_object); + return result; } -bool has_filesystem_permission(const PluginInstallState& state, const boost::filesystem::path& path) +std::vector call_site_identities(const std::string& plugin_root) { - return std::find(state.permissions.fs_read.begin(), state.permissions.fs_read.end(), path.string()) != - state.permissions.fs_read.end(); + std::vector ids; + if (plugin_root.empty()) + return ids; + + PyFrameObject* frame = PyEval_GetFrame(); // borrowed reference + Py_XINCREF(frame); // normalize to an owned reference for the loop below + + while (frame) { + PyCodeObject* code = PyFrame_GetCode(frame); // new reference + const std::string filename = python_unicode(reinterpret_cast(code->co_filename)); + const bool is_plugin_frame = !filename.empty() && boost::algorithm::starts_with(filename, plugin_root); + + std::string id; + if (!is_plugin_frame && !filename.empty()) { + const std::string funcname = python_unicode(reinterpret_cast(code->co_name)); + id = filename + ":" + funcname + ":" + std::to_string(code->co_firstlineno); + } + Py_DECREF(code); + + PyFrameObject* back = PyFrame_GetBack(frame); // new reference, or nullptr at the top of the stack + Py_DECREF(frame); + frame = back; + + if (is_plugin_frame) + break; + if (!id.empty()) + ids.push_back(std::move(id)); + } + + Py_XDECREF(frame); // only holds a reference here if the loop exited via break + + return ids; } -bool persist_filesystem_permission(const std::string& plugin_key, - PluginInstallState& state, - const boost::filesystem::path& path) +static const std::unordered_set two_path_fs_events{ + "os.rename", "os.link", "os.symlink", "shutil.copyfile", + "shutil.copytree", "shutil.copymode", "shutil.copystat", "shutil.move", + "shutil.unpack_archive", "_winapi.CreateJunction", +}; + +static const std::unordered_map> audit_target_arg_indices{ + {"http.client.connect", {1}}, + {"urllib.Request", {0}}, + + {"socket.connect", {1}}, + {"socket.bind", {1}}, + {"socket.getaddrinfo", {0}}, + {"socket.gethostbyname", {0}}, + {"socket.gethostbyaddr", {0}}, + {"socket.getnameinfo", {0}}, + {"socket.getservbyname", {0}}, + {"socket.getservbyport", {0}}, + + {"os.system", {0}}, + {"subprocess.Popen", {1, 0}}, + {"os.posix_spawn", {1, 0}}, + {"os.spawn", {2, 1}}, + {"os.startfile", {0}}, + {"pty.spawn", {0}}, + {"_winapi.CreateProcess", {1, 0}}, + {"_posixsubprocess.fork_exec", {0}}, +}; + +AuditEventCategory open_category(PyObject* args) +{ + const std::string mode = python_unicode(tuple_item(args, 1)); + if (!mode.empty() && mode.find_first_of("wax+") == std::string::npos) + return AuditEventCategory::FsRead; + return AuditEventCategory::FsReadWrite; +} + +std::vector audit_targets(const std::string& event_name, AuditEventCategory category, PyObject* args) +{ + std::vector targets; + + switch (category) { + case AuditEventCategory::FsRead: + case AuditEventCategory::FsReadWrite: + case AuditEventCategory::FsCreate: + case AuditEventCategory::FsDelete: { + const Py_ssize_t path_count = two_path_fs_events.count(event_name) ? 2 : 1; + for (Py_ssize_t index = 0; index < path_count; ++index) { + const std::string path = python_path(tuple_item(args, index)); + if (!path.empty()) + targets.push_back(path); + } + return targets; + } + default: + break; + } + + const auto it = audit_target_arg_indices.find(event_name); + if (it != audit_target_arg_indices.end()) { + for (const Py_ssize_t index : it->second) { + std::string value = python_str(tuple_item(args, index)); + if (!value.empty()) { + targets.push_back(std::move(value)); + break; + } + } + } + + return targets; +} + +std::vector* permission_list_for(AuditEventCategory category, PluginPermissions& permissions) +{ + switch (category) { + case AuditEventCategory::FsRead: return &permissions.fs_read; + case AuditEventCategory::FsReadWrite: return &permissions.fs_readwrite; + case AuditEventCategory::Http: return &permissions.network_http; + case AuditEventCategory::Socket: return &permissions.network_socket; + case AuditEventCategory::ProcessCreate: return &permissions.process; + default: return nullptr; + } +} + +bool has_permission(const std::vector& granted, const std::string& target) +{ + return std::find(granted.begin(), granted.end(), target) != granted.end(); +} + +bool persist_permission(const std::string& plugin_key, + PluginInstallState& state, + std::vector& permission_list, + const std::string& target) { PluginDescriptor descriptor; if (!PluginManager::instance().try_get_plugin_descriptor(plugin_key, descriptor) || descriptor.plugin_root.empty()) @@ -445,23 +689,18 @@ bool persist_filesystem_permission(const std::string& plugin_key, state.enabled = true; } - const std::string path_string = path.string(); - if (std::find(state.permissions.fs_read.begin(), state.permissions.fs_read.end(), path_string) == - state.permissions.fs_read.end()) - state.permissions.fs_read.push_back(path_string); + if (!has_permission(permission_list, target)) + permission_list.push_back(target); return write_install_state(boost::filesystem::path(descriptor.plugin_root), state); } -// Records a blocked event and raises PermissionError in the calling interpreter. int report_denied(PluginAuditManager& mgr, const std::string& event_name, - const boost::filesystem::path& target, const AuditDecision& decision) { AuditViolation violation; violation.plugin_key = mgr.current_plugin(); violation.event_name = event_name; - violation.path = target; violation.reason = decision.reason; mgr.report_violation(violation); @@ -469,6 +708,74 @@ int report_denied(PluginAuditManager& mgr, return -1; } +wxString audit_message(AuditEventCategory category, const wxString& plugin_name, const wxString& event_name, + const wxString& target_list) +{ + if (target_list.IsEmpty()) + return wxString::Format( + _L("Plugin \"%s\" is requesting permission for the Python audit event \"%s\".\n\n" + "This operation does not expose a target the audit hook can display."), + plugin_name, event_name); + + switch (category) { + case AuditEventCategory::FsRead: + return wxString::Format(_L("Plugin \"%s\" is requesting to read the following file(s):\n%s"), plugin_name, target_list); + case AuditEventCategory::FsReadWrite: + return wxString::Format(_L("Plugin \"%s\" is requesting to read/write the following file(s):\n%s"), plugin_name, target_list); + case AuditEventCategory::FsCreate: + return wxString::Format(_L("Plugin \"%s\" is requesting to create the following file(s):\n%s"), plugin_name, target_list); + case AuditEventCategory::FsDelete: + return wxString::Format(_L("Plugin \"%s\" is requesting to delete the following file(s):\n%s"), plugin_name, target_list); + case AuditEventCategory::Http: + return wxString::Format(_L("Plugin \"%s\" is requesting to make an HTTP request to:\n%s"), plugin_name, target_list); + case AuditEventCategory::Socket: + return wxString::Format(_L("Plugin \"%s\" is requesting to open a network connection to:\n%s"), plugin_name, target_list); + case AuditEventCategory::ProcessCreate: + return wxString::Format(_L("Plugin \"%s\" is requesting to run the following command(s):\n%s"), plugin_name, target_list); + default: + return wxString::Format(_L("Plugin \"%s\" is requesting permission for the Python audit event \"%s\"."), plugin_name, event_name); + } +} + +int decide_audited_event(PluginAuditManager& mgr, + PluginInstallState& state, + const std::string& plugin_key, + const std::string& plugin_name, + const std::string& event_name, + AuditEventCategory category, + const std::vector& targets, + std::vector* permission_list, + const std::vector& call_site_ids) +{ + std::vector unresolved = targets; + if (permission_list) { + unresolved.clear(); + for (const auto& target : targets) + if (!has_permission(*permission_list, target)) + unresolved.push_back(target); + if (!targets.empty() && unresolved.empty()) + return 0; + } + + wxString target_list; + for (const auto& target : unresolved) + target_list += wxString::FromUTF8(target.c_str()) + "\n"; + + wxMessageDialog dialog(nullptr, + audit_message(category, wxString::FromUTF8(plugin_name.c_str()), + wxString::FromUTF8(event_name.c_str()), target_list), + _L("Plugin permission request"), wxYES_NO | wxICON_WARNING); + if (dialog.ShowModal() != wxID_YES) + return report_denied(mgr, event_name, {false, "audit permission required"}); + + if (permission_list) + for (const auto& target : unresolved) + persist_permission(plugin_key, state, *permission_list, target); + + mgr.record_approved_call_sites(plugin_key, call_site_ids); + return 0; +} + } // namespace PluginAuditDetail int PluginAuditManager::audit_hook(const char* event, PyObject* args, void* user_data) @@ -479,12 +786,33 @@ int PluginAuditManager::audit_hook(const char* event, PyObject* args, void* user std::string event_name(event ? event : ""); + if (event_name.empty()) + return 0; + // Verbose logging of every audit event (can be noisy) if (mgr->verbose_events) { BOOST_LOG_TRIVIAL(debug) << "[AUDIT EVENT] " << event_name; } - if (mgr->current_plugin().empty()) + if (mgr->current_plugin().empty()) { + BOOST_LOG_TRIVIAL(trace) << "[AUDIT] event=" << event_name << " bypassed (no plugin context)"; + return 0; + } + + PluginDescriptor plugin_descriptor; + PluginManager::instance().try_get_plugin_descriptor(mgr->current_plugin(), plugin_descriptor); + + // Some plugins call other audited events, e.g. urlib.request will call socket.connect. So this is so that if urlib.request + // was already approved, socket.connect won't trigger another permission dialog. + const std::vector call_site_ids = + PluginAuditDetail::call_site_identities(plugin_descriptor.plugin_root); + if (mgr->has_approved_ancestor(mgr->current_plugin(), call_site_ids)) + return 0; + + // the open function can take in different flags that determine if it is a read or readwrite. + const AuditEventCategory event_type = + event_name == "open" ? PluginAuditDetail::open_category(args) : event_category(event_name); + if (event_type == AuditEventCategory::None) return 0; PluginInstallState state; @@ -494,53 +822,16 @@ int PluginAuditManager::audit_hook(const char* event, PyObject* args, void* user } const std::string plugin_name = state.plugin_name.empty() ? mgr->current_plugin() : state.plugin_name; - const std::vector paths = PluginAuditDetail::filesystem_paths(event_name, args); - for (const auto& path : paths) { - if (PluginAuditDetail::has_filesystem_permission(state, path)) - continue; - wxMessageDialog dialog( - nullptr, - wxString::Format(_L("Plugin \"%s\" is requesting filesystem access to:\n%s"), - wxString::FromUTF8(plugin_name.c_str()), - wxString::FromUTF8(path.string().c_str())), - _L("Plugin permission request"), - wxYES_NO | wxICON_WARNING); - if (dialog.ShowModal() == wxID_YES && - PluginAuditDetail::persist_filesystem_permission(mgr->current_plugin(), state, path)) - continue; + const std::vector targets = PluginAuditDetail::audit_targets(event_name, event_type, args); + std::vector* permission_list = PluginAuditDetail::permission_list_for(event_type, state.permissions); - return PluginAuditDetail::report_denied( - *mgr, event_name, path, {false, "filesystem permission required"}); - } - - if (!paths.empty()) - return 0; - - wxMessageDialog dialog( - nullptr, - wxString::Format( - _L("Plugin \"%s\" is requesting permission for the Python audit event \"%s\".\n\n" - "This operation does not expose a filesystem path to the audit hook."), - wxString::FromUTF8(plugin_name.c_str()), - wxString::FromUTF8(event_name.c_str())), - _L("Plugin permission request"), - wxYES_NO | wxICON_WARNING); - if (dialog.ShowModal() == wxID_YES) - return 0; - - return PluginAuditDetail::report_denied( - *mgr, event_name, boost::filesystem::path(), {false, "audit permission required"}); + return PluginAuditDetail::decide_audited_event(*mgr, state, mgr->current_plugin(), plugin_name, event_name, + event_type, targets, permission_list, call_site_ids); } void PluginAuditManager::install_hook() { - if (PySys_AddAuditHook(audit_hook, this) < 0) { - BOOST_LOG_TRIVIAL(error) << "[AUDIT] Failed to install CPython audit hook"; - return; - } - BOOST_LOG_TRIVIAL(info) << "[AUDIT] CPython audit hook installed successfully"; - // data_dir() is the only globally-allowed root during plugin execution. // The executable directory and resources directory are intentionally NOT allowed // here: plugins must not access outside data_dir() (G-code plugins additionally get @@ -558,6 +849,12 @@ void PluginAuditManager::install_hook() // (see its comment for why all four config names are denied); the tests seed from it too. for (const auto& name : default_denied_filenames()) add_denied_filename(name); + + if (PySys_AddAuditHook(audit_hook, this) < 0) { + BOOST_LOG_TRIVIAL(error) << "[AUDIT] Failed to install CPython audit hook"; + return; + } + BOOST_LOG_TRIVIAL(info) << "[AUDIT] CPython audit hook installed successfully"; } } // namespace Slic3r diff --git a/src/slic3r/plugin/PluginAuditManager.hpp b/src/slic3r/plugin/PluginAuditManager.hpp index f3fb43d20a..3b86014d42 100644 --- a/src/slic3r/plugin/PluginAuditManager.hpp +++ b/src/slic3r/plugin/PluginAuditManager.hpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include @@ -19,10 +21,23 @@ struct AuditDecision { struct AuditViolation { std::string plugin_key; std::string event_name; - boost::filesystem::path path; std::string reason; }; +// The set of CPython audit events PluginAuditManager recognizes, grouped by the kind of +// operation they represent. None means the event isn't one audit_hook() acts on at all. +enum class AuditEventCategory { + None, + FsRead, + FsReadWrite, + FsCreate, + FsDelete, + Http, + Socket, + ProcessCreate, + Threading, +}; + // Returns true if candidate resolves to a path inside allowed_root. // Uses weakly_canonical and component-wise comparison to reject traversal attacks. bool is_inside_allowed_root(const boost::filesystem::path& candidate, @@ -94,6 +109,16 @@ public: void clear_last_violation(); bool last_violation(AuditViolation& violation) const; + // --- call-site cascade cache --- + // A single plugin action often fires several nested CPython audit events as it passes + // through stdlib layers (urllib.request calling http.client calling socket, for example). + // Once the user approves one event, every stdlib frame still on the stack for that call + // is recorded here by (filename, function, first line) identity. A later event whose own + // ancestor chain still contains one of those frames is the same logical action seen from + // a deeper layer, so it is auto-approved instead of prompting again. + bool has_approved_ancestor(const std::string& plugin_key, const std::vector& call_site_ids) const; + void record_approved_call_sites(const std::string& plugin_key, const std::vector& call_site_ids); + bool verbose_events = true; private: @@ -110,10 +135,11 @@ private: static thread_local bool m_has_last_violation; static thread_local AuditViolation m_last_violation; - // mutable: is_denied_filename() is a const query that must lock. + // mutable: is_denied_filename() and has_approved_ancestor() are const queries that must lock. mutable std::mutex m_mutex; std::vector m_global_allowed_roots; std::vector m_denied_filenames; + std::unordered_map> m_approved_call_sites; // plugin_key -> call-site ids }; // RAII guard that sets the current plugin key and capability name, restoring the previous diff --git a/src/slic3r/plugin/PluginFsUtils.cpp b/src/slic3r/plugin/PluginFsUtils.cpp index c152ae165e..3e014eaec7 100644 --- a/src/slic3r/plugin/PluginFsUtils.cpp +++ b/src/slic3r/plugin/PluginFsUtils.cpp @@ -788,18 +788,18 @@ bool read_install_state(const boost::filesystem::path& plugin_dir, PluginInstall if (state.contains("permissions") && state["permissions"].is_object()) { const auto& permissions = state["permissions"]; - if (permissions.contains("networking") && permissions["networking"].is_array()) - for (const auto& host : permissions["networking"]) - if (host.is_string()) - parsed.permissions.networking.push_back(host.get()); - if (permissions.contains("fs_read") && permissions["fs_read"].is_array()) - for (const auto& path : permissions["fs_read"]) - if (path.is_string()) - parsed.permissions.fs_read.push_back(path.get()); - if (permissions.contains("fs_write") && permissions["fs_write"].is_array()) - for (const auto& path : permissions["fs_write"]) - if (path.is_string()) - parsed.permissions.fs_write.push_back(path.get()); + auto read_string_list = [&permissions](const char* key, std::vector& out) { + if (!permissions.contains(key) || !permissions[key].is_array()) + return; + for (const auto& entry : permissions[key]) + if (entry.is_string()) + out.push_back(entry.get()); + }; + read_string_list("fs_read", parsed.permissions.fs_read); + read_string_list("fs_readwrite", parsed.permissions.fs_readwrite); + read_string_list("network_http", parsed.permissions.network_http); + read_string_list("network_socket", parsed.permissions.network_socket); + read_string_list("process", parsed.permissions.process); } if (state.contains("enabled") && state["enabled"].is_boolean()) @@ -838,9 +838,11 @@ bool write_install_state(const boost::filesystem::path& plugin_dir, const Plugin json["cloud_uuid"] = state.cloud_uuid; json["permissions"] = { - {"networking", state.permissions.networking}, {"fs_read", state.permissions.fs_read}, - {"fs_write", state.permissions.fs_write}, + {"fs_readwrite", state.permissions.fs_readwrite}, + {"network_http", state.permissions.network_http}, + {"network_socket", state.permissions.network_socket}, + {"process", state.permissions.process}, }; nlohmann::json capabilities = nlohmann::json::array(); diff --git a/src/slic3r/plugin/PluginFsUtils.hpp b/src/slic3r/plugin/PluginFsUtils.hpp index be7f5bb551..980d05144e 100644 --- a/src/slic3r/plugin/PluginFsUtils.hpp +++ b/src/slic3r/plugin/PluginFsUtils.hpp @@ -83,9 +83,11 @@ inline nlohmann::json py_to_json(const pybind11::handle& o) struct PluginPermissions { - std::vector networking; std::vector fs_read; - std::vector fs_write; + std::vector fs_readwrite; + std::vector network_http; + std::vector network_socket; + std::vector process; }; struct PluginInstallState { diff --git a/src/slic3r/plugin/PythonInterpreter.cpp b/src/slic3r/plugin/PythonInterpreter.cpp index 299a2dd7ba..3d180c2f2a 100644 --- a/src/slic3r/plugin/PythonInterpreter.cpp +++ b/src/slic3r/plugin/PythonInterpreter.cpp @@ -628,10 +628,6 @@ bool PythonInterpreter::initialize() else BOOST_LOG_TRIVIAL(info) << "Bundled uv executable not found"; - // Install the CPython audit hook for plugin policy enforcement. - // This is defense-in-depth: today it only inspects the `open` audit event - // and blocks writes outside the allowed roots; subprocess/socket/ctypes and - // other events are not yet handled. It is NOT a full security sandbox. PluginAuditManager::instance().install_hook(); // Persist Python stderr (plugin tracebacks, including uncaught diff --git a/tests/slic3rutils/test_plugin_install.cpp b/tests/slic3rutils/test_plugin_install.cpp index c6ad670ff7..ae16703fa6 100644 --- a/tests/slic3rutils/test_plugin_install.cpp +++ b/tests/slic3rutils/test_plugin_install.cpp @@ -112,17 +112,21 @@ TEST_CASE("install-state sidecar is the source of truth for a cloud plugin's ins REQUIRE(read_install_state(plugin_dir, state)); CHECK(state.installed_version == "1.2.0"); - state.permissions.networking = {"api.example.com", "192.168.45.6"}; - state.permissions.fs_read = {"/path/to/read"}; - state.permissions.fs_write = {"/path/to/write"}; + state.permissions.fs_read = {"/path/to/read"}; + state.permissions.fs_readwrite = {"/path/to/readwrite"}; + state.permissions.network_http = {"https://api.example.com"}; + state.permissions.network_socket = {"192.168.45.6:443"}; + state.permissions.process = {"/usr/bin/curl"}; REQUIRE(write_install_state(plugin_dir, state)); // Permission data is persisted in the same sidecar as the installation metadata. PluginInstallState persisted; REQUIRE(read_install_state(plugin_dir, persisted)); - CHECK(persisted.permissions.networking == state.permissions.networking); CHECK(persisted.permissions.fs_read == state.permissions.fs_read); - CHECK(persisted.permissions.fs_write == state.permissions.fs_write); + CHECK(persisted.permissions.fs_readwrite == state.permissions.fs_readwrite); + CHECK(persisted.permissions.network_http == state.permissions.network_http); + CHECK(persisted.permissions.network_socket == state.permissions.network_socket); + CHECK(persisted.permissions.process == state.permissions.process); // Reading the sidecar back onto a freshly-scanned descriptor (whose header version is still // 1.0.0) must surface the cloud-installed 1.2.0. This is what lets update_cloud_metadata compare From d99f4c8164053f5e80390b9604b6e8790f7f8d88 Mon Sep 17 00:00:00 2001 From: Ian Chua Date: Fri, 14 Aug 2026 12:33:08 +0800 Subject: [PATCH 05/51] Merge branch 'main' into feat/plugin-auditing --- .github/ISSUE_TEMPLATE/bug_report.yml | 10 +- CMakeLists.txt | 4 + README.md | 4 + deps/OpenSSL/OpenSSL.cmake | 8 + deps_src/imgui/imgui_draw.cpp | 1 + deps_src/imgui/imstb_textedit.h | 95 + localization/i18n/OrcaSlicer.pot | 88 +- localization/i18n/ca/OrcaSlicer_ca.po | 153 +- localization/i18n/cs/OrcaSlicer_cs.po | 153 +- localization/i18n/de/OrcaSlicer_de.po | 153 +- localization/i18n/en/OrcaSlicer_en.po | 96 +- localization/i18n/es/OrcaSlicer_es.po | 153 +- localization/i18n/eu/OrcaSlicer_eu.po | 181 +- localization/i18n/fr/OrcaSlicer_fr.po | 163 +- localization/i18n/hu/OrcaSlicer_hu.po | 1208 +++++---- localization/i18n/it/OrcaSlicer_it.po | 153 +- localization/i18n/ja/OrcaSlicer_ja.po | 153 +- localization/i18n/ko/OrcaSlicer_ko.po | 159 +- localization/i18n/lt/OrcaSlicer_lt.po | 153 +- localization/i18n/nl/OrcaSlicer_nl.po | 153 +- localization/i18n/pl/OrcaSlicer_pl.po | 153 +- localization/i18n/pt_BR/OrcaSlicer_pt_BR.po | 225 +- localization/i18n/ru/OrcaSlicer_ru.po | 1403 +++++------ localization/i18n/sv/OrcaSlicer_sv.po | 153 +- localization/i18n/th/OrcaSlicer_th.po | 521 ++-- localization/i18n/tr/OrcaSlicer_tr.po | 777 +++--- localization/i18n/uk/OrcaSlicer_uk.po | 153 +- localization/i18n/vi/OrcaSlicer_vi.po | 153 +- localization/i18n/zh_CN/OrcaSlicer_zh_CN.po | 153 +- localization/i18n/zh_TW/OrcaSlicer_zh_TW.po | 155 +- resources/profiles/Creality.json | 2 +- ...SuperDetail @Creality K1 (0.4 nozzle).json | 2 +- ...ail @Creality K1 Max_CFS-C 0.4 nozzle.json | 2 +- ... SuperDetail @Creality K1C 0.4 nozzle.json | 2 +- ...Detail @Creality K1C_CFS-C 0.4 nozzle.json | 2 +- ...erDetail @Creality K1Max (0.4 nozzle).json | 2 +- ...rDetail @Creality K1_CFS-C 0.4 nozzle.json | 2 +- ...6mm Optimal @Creality K1 (0.4 nozzle).json | 2 +- ...mal @Creality K1 Max_CFS-C 0.4 nozzle.json | 2 +- ...mm Optimal @Creality K1 SE 0.4 nozzle.json | 2 +- ...imal @Creality K1 SE_CFS-C 0.4 nozzle.json | 2 +- ...16mm Optimal @Creality K1C 0.4 nozzle.json | 2 +- ...ptimal @Creality K1C_CFS-C 0.4 nozzle.json | 2 +- ... Optimal @Creality K1Max (0.4 nozzle).json | 2 +- ...Optimal @Creality K1_CFS-C 0.4 nozzle.json | 2 +- ...mm Standard @Creality K1 (0.4 nozzle).json | 2 +- ...ard @Creality K1 Max_CFS-C 0.4 nozzle.json | 2 +- .../0.20mm Standard @Creality K1 SE 0.4.json | 2 +- ...dard @Creality K1 SE_CFS-C 0.4 nozzle.json | 2 +- ...0mm Standard @Creality K1C 0.4 nozzle.json | 2 +- ...andard @Creality K1C_CFS-C 0.4 nozzle.json | 2 +- ...Standard @Creality K1Max (0.4 nozzle).json | 2 +- ...tandard @Creality K1_CFS-C 0.4 nozzle.json | 2 +- ....24mm Draft @Creality K1 (0.4 nozzle).json | 2 +- ...aft @Creality K1 Max_CFS-C 0.4 nozzle.json | 2 +- ...24mm Draft @Creality K1 SE 0.4 nozzle.json | 2 +- ...raft @Creality K1 SE_CFS-C 0.4 nozzle.json | 2 +- ...0.24mm Draft @Creality K1C 0.4 nozzle.json | 2 +- ... Draft @Creality K1C_CFS-C 0.4 nozzle.json | 2 +- ...mm Draft @Creality K1Max (0.4 nozzle).json | 2 +- ...m Draft @Creality K1_CFS-C 0.4 nozzle.json | 2 +- ...mm Standard @Creality K1 (0.6 nozzle).json | 2 +- ...m Standard @Creality K1 SE 0.6 nozzle.json | 2 +- ...0mm Standard @Creality K1C 0.6 nozzle.json | 2 +- ...Standard @Creality K1Max (0.6 nozzle).json | 2 +- ...mm Standard @Creality K1 (0.8 nozzle).json | 2 +- ...0mm Standard @Creality K1C 0.8 nozzle.json | 2 +- ...Standard @Creality K1Max (0.8 nozzle).json | 2 +- resources/profiles/Custom.json | 2 +- .../filament/Generic ABS @MyToolChanger.json | 6 - .../filament/Generic ASA @MyToolChanger.json | 6 - .../filament/Generic PA @MyToolChanger.json | 6 - .../Generic PA-CF @MyToolChanger.json | 6 - .../filament/Generic PC @MyToolChanger.json | 6 - .../filament/Generic PETG @MyToolChanger.json | 6 - .../filament/Generic PLA @MyToolChanger.json | 6 - .../Generic PLA-CF @MyToolChanger.json | 6 - .../filament/Generic PVA @MyToolChanger.json | 6 - .../Custom/machine/fdm_klipper_common.json | 2 +- .../Custom/machine/fdm_repetier_common.json | 2 +- .../Custom/machine/fdm_rrf_common.json | 2 +- .../machine/fdm_toolchanger_common.json | 11 +- resources/profiles/OrcaFilamentLibrary.json | 2 +- .../filament/Bambu/Bambu PET-CF @base.json | 3 + .../Bambu/Bambu PETG Basic @base.json | 3 + .../Bambu/Bambu PETG Translucent @base.json | 3 + .../filament/Bambu/Bambu PLA Aero @base.json | 3 + .../Bambu Support For PLA-PETG @base.json | 3 + .../Bambu/Bambu Support for ABS @base.json | 3 + .../filament/COEX/COEX TPU 60A @base.json | 3 + .../filament/Elas/Elas ASA @base.json | 42 - .../filament/Elas/Elas PETG Basic @base.json | 42 - .../filament/Elas/Elas PLA Basic @base.json | 42 - .../filament/Elas/Elas PLA Pro @base.json | 42 - .../Elegoo/Elegoo PAHT-CF @System.json | 3 + .../filament/Elegoo/Elegoo PETG @base.json | 3 + .../Elegoo/Elegoo PLA Wood @System.json | 3 + .../Eolas Prints PLA Neon @System.json | 3 + .../Eolas Prints PLA Silk @System.json | 3 + .../filament/Generic PA-CF @System.json | 3 + .../filament/Generic PETG HF @System.json | 3 + .../filament/Generic PETG-CF @System.json | 3 + .../Generic PLA High Speed @System.json | 3 + .../filament/Generic PLA Matte @System.json | 3 + .../filament/Generic PP-CF @System.json | 3 + .../filament/Generic PP-GF @System.json | 3 + .../Overture/Overture Air PLA @base.json | 3 + .../Valment/Valment PLA Silk @base.json | 3 + .../filament/base/fdm_filament_abs.json | 6 + .../filament/base/fdm_filament_asa.json | 6 + .../filament/base/fdm_filament_bvoh.json | 9 + .../filament/base/fdm_filament_common.json | 6 + .../filament/base/fdm_filament_cope.json | 3 + .../filament/base/fdm_filament_eva.json | 3 + .../filament/base/fdm_filament_hips.json | 3 + .../filament/base/fdm_filament_pa.json | 3 + .../filament/base/fdm_filament_paht.json | 3 + .../filament/base/fdm_filament_pc.json | 3 + .../filament/base/fdm_filament_pctg.json | 3 + .../filament/base/fdm_filament_pe.json | 3 + .../filament/base/fdm_filament_pet.json | 3 + .../filament/base/fdm_filament_pha.json | 3 + .../filament/base/fdm_filament_pla.json | 3 + .../filament/base/fdm_filament_pla_silk.json | 3 + .../filament/base/fdm_filament_pp.json | 3 + .../filament/base/fdm_filament_ppa.json | 3 + .../filament/base/fdm_filament_pps.json | 3 + .../filament/base/fdm_filament_pva.json | 9 + .../filament/base/fdm_filament_sbs.json | 3 + .../filament/base/fdm_filament_tpu.json | 9 + .../filament/eSUN/eSUN PLA-Marble @base.json | 3 + .../filament/eSUN/eSUN PLA-Matte @base.json | 3 + .../filament/eSUN/eSUN ePLA-LW @System.json | 3 + resources/profiles/Qidi.json | 1078 +++++++- .../profiles/Qidi/Qidi X-Plus 5_cover.png | Bin 0 -> 33441 bytes .../Bambu ABS @Qidi X-Plus 5 0.2 nozzle.json | 20 + .../Bambu ABS @Qidi X-Plus 5 0.4 nozzle.json | 14 + .../Bambu ABS @Qidi X-Plus 5 0.6 nozzle.json | 17 + .../Bambu ABS @Qidi X-Plus 5 0.8 nozzle.json | 20 + .../Qidi/filament/X5/Bambu ABS @X-Plus 5.json | 105 + .../Bambu PETG @Qidi X-Plus 5 0.2 nozzle.json | 17 + .../Bambu PETG @Qidi X-Plus 5 0.4 nozzle.json | 14 + .../Bambu PETG @Qidi X-Plus 5 0.6 nozzle.json | 14 + .../Bambu PETG @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/Bambu PETG @X-Plus 5.json | 102 + .../Bambu PLA @Qidi X-Plus 5 0.2 nozzle.json | 17 + .../Bambu PLA @Qidi X-Plus 5 0.4 nozzle.json | 14 + .../Bambu PLA @Qidi X-Plus 5 0.6 nozzle.json | 14 + .../Bambu PLA @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../Qidi/filament/X5/Bambu PLA @X-Plus 5.json | 54 + ...Generic ABS @Qidi X-Plus 5 0.2 nozzle.json | 17 + ...Generic ABS @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...Generic ABS @Qidi X-Plus 5 0.6 nozzle.json | 17 + ...Generic ABS @Qidi X-Plus 5 0.8 nozzle.json | 17 + .../filament/X5/Generic ABS @X-Plus 5.json | 108 + .../Generic PC @Qidi X-Plus 5 0.2 nozzle.json | 23 + .../Generic PC @Qidi X-Plus 5 0.4 nozzle.json | 20 + .../Generic PC @Qidi X-Plus 5 0.6 nozzle.json | 20 + .../Generic PC @Qidi X-Plus 5 0.8 nozzle.json | 20 + .../filament/X5/Generic PC @X-Plus 5.json | 108 + ...eneric PETG @Qidi X-Plus 5 0.2 nozzle.json | 17 + ...eneric PETG @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...eneric PETG @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...eneric PETG @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/Generic PETG @X-Plus 5.json | 105 + ...Generic PLA @Qidi X-Plus 5 0.2 nozzle.json | 17 + ...Generic PLA @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...Generic PLA @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...Generic PLA @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/Generic PLA @X-Plus 5.json | 66 + ...ic PLA Silk @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...ic PLA Silk @Qidi X-Plus 5 0.6 nozzle.json | 14 + .../X5/Generic PLA Silk @X-Plus 5.json | 90 + ...eneric PLA+ @Qidi X-Plus 5 0.2 nozzle.json | 17 + ...eneric PLA+ @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...eneric PLA+ @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...eneric PLA+ @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/Generic PLA+ @X-Plus 5.json | 60 + ...ric TPU 95A @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...ric TPU 95A @Qidi X-Plus 5 0.6 nozzle.json | 11 + ...ric TPU 95A @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../X5/Generic TPU 95A @X-Plus 5.json | 81 + ...ATCHBOX ABS @Qidi X-Plus 5 0.2 nozzle.json | 20 + ...ATCHBOX ABS @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...ATCHBOX ABS @Qidi X-Plus 5 0.6 nozzle.json | 17 + ...ATCHBOX ABS @Qidi X-Plus 5 0.8 nozzle.json | 20 + .../filament/X5/HATCHBOX ABS @X-Plus 5.json | 105 + ...TCHBOX PETG @Qidi X-Plus 5 0.2 nozzle.json | 17 + ...TCHBOX PETG @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...TCHBOX PETG @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...TCHBOX PETG @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/HATCHBOX PETG @X-Plus 5.json | 102 + ...ATCHBOX PLA @Qidi X-Plus 5 0.2 nozzle.json | 17 + ...ATCHBOX PLA @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...ATCHBOX PLA @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...ATCHBOX PLA @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/HATCHBOX PLA @X-Plus 5.json | 54 + ...verture ABS @Qidi X-Plus 5 0.2 nozzle.json | 20 + ...verture ABS @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...verture ABS @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...verture ABS @Qidi X-Plus 5 0.8 nozzle.json | 17 + .../filament/X5/Overture ABS @X-Plus 5.json | 108 + ...verture PLA @Qidi X-Plus 5 0.2 nozzle.json | 17 + ...verture PLA @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...verture PLA @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...verture PLA @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/Overture PLA @X-Plus 5.json | 66 + ...olyLite ABS @Qidi X-Plus 5 0.2 nozzle.json | 20 + ...olyLite ABS @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...olyLite ABS @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...olyLite ABS @Qidi X-Plus 5 0.8 nozzle.json | 17 + .../filament/X5/PolyLite ABS @X-Plus 5.json | 108 + ...olyLite PLA @Qidi X-Plus 5 0.2 nozzle.json | 17 + ...olyLite PLA @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...olyLite PLA @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...olyLite PLA @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/PolyLite PLA @X-Plus 5.json | 66 + ...aker PLA-HT @Qidi X-Plus 5 0.2 nozzle.json | 17 + ...aker PLA-HT @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...aker PLA-HT @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...aker PLA-HT @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../X5/Polymaker PLA-HT @X-Plus 5.json | 66 + ...BS Odorless @Qidi X-Plus 5 0.2 nozzle.json | 20 + ...BS Odorless @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...BS Odorless @Qidi X-Plus 5 0.6 nozzle.json | 20 + ...BS Odorless @Qidi X-Plus 5 0.8 nozzle.json | 23 + .../X5/QIDI ABS Odorless @X-Plus 5.json | 108 + ... ABS Rapido @Qidi X-Plus 5 0.2 nozzle.json | 20 + ... ABS Rapido @Qidi X-Plus 5 0.4 nozzle.json | 14 + ... ABS Rapido @Qidi X-Plus 5 0.6 nozzle.json | 17 + ... ABS Rapido @Qidi X-Plus 5 0.8 nozzle.json | 20 + .../X5/QIDI ABS Rapido @X-Plus 5.json | 105 + ...apido Metal @Qidi X-Plus 5 0.2 nozzle.json | 20 + ...apido Metal @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...apido Metal @Qidi X-Plus 5 0.6 nozzle.json | 17 + ...apido Metal @Qidi X-Plus 5 0.8 nozzle.json | 20 + .../X5/QIDI ABS Rapido Metal @X-Plus 5.json | 105 + ...QIDI ABS-GF @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...QIDI ABS-GF @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...QIDI ABS-GF @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/QIDI ABS-GF @X-Plus 5.json | 114 + .../QIDI ASA @Qidi X-Plus 5 0.2 nozzle.json | 20 + .../QIDI ASA @Qidi X-Plus 5 0.4 nozzle.json | 14 + .../QIDI ASA @Qidi X-Plus 5 0.6 nozzle.json | 17 + .../QIDI ASA @Qidi X-Plus 5 0.8 nozzle.json | 20 + .../Qidi/filament/X5/QIDI ASA @X-Plus 5.json | 111 + ...DI ASA-Aero @Qidi X-Plus 5 0.4 nozzle.json | 11 + .../filament/X5/QIDI ASA-Aero @X-Plus 5.json | 126 + ...QIDI ASA-CF @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...QIDI ASA-CF @Qidi X-Plus 5 0.6 nozzle.json | 17 + ...QIDI ASA-CF @Qidi X-Plus 5 0.8 nozzle.json | 20 + .../filament/X5/QIDI ASA-CF @X-Plus 5.json | 111 + ...IDI PA12-CF @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...IDI PA12-CF @Qidi X-Plus 5 0.6 nozzle.json | 11 + ...IDI PA12-CF @Qidi X-Plus 5 0.8 nozzle.json | 11 + .../filament/X5/QIDI PA12-CF @X-Plus 5.json | 111 + ...QIDI PA6-CF @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...QIDI PA6-CF @Qidi X-Plus 5 0.6 nozzle.json | 11 + ...QIDI PA6-CF @Qidi X-Plus 5 0.8 nozzle.json | 11 + .../filament/X5/QIDI PA6-CF @X-Plus 5.json | 111 + ...IDI PAHT-CF @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...IDI PAHT-CF @Qidi X-Plus 5 0.6 nozzle.json | 11 + ...IDI PAHT-CF @Qidi X-Plus 5 0.8 nozzle.json | 11 + .../filament/X5/QIDI PAHT-CF @X-Plus 5.json | 111 + ...IDI PAHT-GF @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...IDI PAHT-GF @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...IDI PAHT-GF @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/QIDI PAHT-GF @X-Plus 5.json | 111 + ...I PC-ABS-FR @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...I PC-ABS-FR @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...I PC-ABS-FR @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/QIDI PC-ABS-FR @X-Plus 5.json | 111 + ...DI PEBA 95A @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...DI PEBA 95A @Qidi X-Plus 5 0.6 nozzle.json | 11 + .../filament/X5/QIDI PEBA 95A @X-Plus 5.json | 96 + ...QIDI PET-CF @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...QIDI PET-CF @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...QIDI PET-CF @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/QIDI PET-CF @X-Plus 5.json | 111 + ...QIDI PET-GF @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...QIDI PET-GF @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...QIDI PET-GF @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/QIDI PET-GF @X-Plus 5.json | 111 + ... PETG Basic @Qidi X-Plus 5 0.2 nozzle.json | 17 + ... PETG Basic @Qidi X-Plus 5 0.4 nozzle.json | 11 + ... PETG Basic @Qidi X-Plus 5 0.6 nozzle.json | 14 + ... PETG Basic @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../X5/QIDI PETG Basic @X-Plus 5.json | 102 + ...PETG Rapido @Qidi X-Plus 5 0.2 nozzle.json | 17 + ...PETG Rapido @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...PETG Rapido @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...PETG Rapido @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../X5/QIDI PETG Rapido @X-Plus 5.json | 102 + ... PETG Tough @Qidi X-Plus 5 0.2 nozzle.json | 17 + ... PETG Tough @Qidi X-Plus 5 0.4 nozzle.json | 11 + ... PETG Tough @Qidi X-Plus 5 0.6 nozzle.json | 14 + ... PETG Tough @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../X5/QIDI PETG Tough @X-Plus 5.json | 102 + ...Translucent @Qidi X-Plus 5 0.2 nozzle.json | 17 + ...Translucent @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...Translucent @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...Translucent @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../X5/QIDI PETG Translucent @X-Plus 5.json | 102 + ...IDI PETG-CF @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...IDI PETG-CF @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...IDI PETG-CF @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/QIDI PETG-CF @X-Plus 5.json | 102 + ...IDI PETG-GF @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...IDI PETG-GF @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...IDI PETG-GF @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/QIDI PETG-GF @X-Plus 5.json | 102 + ...I PLA Basic @Qidi X-Plus 5 0.2 nozzle.json | 17 + ...I PLA Basic @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...I PLA Basic @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...I PLA Basic @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/QIDI PLA Basic @X-Plus 5.json | 63 + ...Matte Basic @Qidi X-Plus 5 0.2 nozzle.json | 17 + ...Matte Basic @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...Matte Basic @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...Matte Basic @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../X5/QIDI PLA Matte Basic @X-Plus 5.json | 63 + ... PLA Rapido @Qidi X-Plus 5 0.2 nozzle.json | 17 + ... PLA Rapido @Qidi X-Plus 5 0.4 nozzle.json | 14 + ... PLA Rapido @Qidi X-Plus 5 0.6 nozzle.json | 14 + ... PLA Rapido @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../X5/QIDI PLA Rapido @X-Plus 5.json | 60 + ...apido Matte @Qidi X-Plus 5 0.2 nozzle.json | 17 + ...apido Matte @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...apido Matte @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...apido Matte @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../X5/QIDI PLA Rapido Matte @X-Plus 5.json | 57 + ...apido Metal @Qidi X-Plus 5 0.2 nozzle.json | 17 + ...apido Metal @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...apido Metal @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...apido Metal @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../X5/QIDI PLA Rapido Metal @X-Plus 5.json | 57 + ...DI PLA Silk @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...DI PLA Silk @Qidi X-Plus 5 0.6 nozzle.json | 14 + .../filament/X5/QIDI PLA Silk @X-Plus 5.json | 84 + ...QIDI PLA-CF @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...QIDI PLA-CF @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...QIDI PLA-CF @Qidi X-Plus 5 0.8 nozzle.json | 17 + .../filament/X5/QIDI PLA-CF @X-Plus 5.json | 75 + ...QIDI PPS-CF @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...QIDI PPS-CF @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...QIDI PPS-CF @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/QIDI PPS-CF @X-Plus 5.json | 117 + ...QIDI PPS-GF @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...QIDI PPS-GF @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...QIDI PPS-GF @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../filament/X5/QIDI PPS-GF @X-Plus 5.json | 117 + ...rt For PAHT @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...rt For PAHT @Qidi X-Plus 5 0.6 nozzle.json | 11 + ...rt For PAHT @Qidi X-Plus 5 0.8 nozzle.json | 11 + .../X5/QIDI Support For PAHT @X-Plus 5.json | 114 + ... For PET-PA @Qidi X-Plus 5 0.4 nozzle.json | 11 + ... For PET-PA @Qidi X-Plus 5 0.6 nozzle.json | 11 + ... For PET-PA @Qidi X-Plus 5 0.8 nozzle.json | 11 + .../X5/QIDI Support For PET-PA @X-Plus 5.json | 114 + ... TPU 95A-HF @Qidi X-Plus 5 0.4 nozzle.json | 11 + ... TPU 95A-HF @Qidi X-Plus 5 0.6 nozzle.json | 11 + ... TPU 95A-HF @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../X5/QIDI TPU 95A-HF @X-Plus 5.json | 84 + ...DI TPU-Aero @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...DI TPU-Aero @Qidi X-Plus 5 0.6 nozzle.json | 11 + .../filament/X5/QIDI TPU-Aero @X-Plus 5.json | 93 + ...QIDI TPU-GF @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...QIDI TPU-GF @Qidi X-Plus 5 0.6 nozzle.json | 11 + ...QIDI TPU-GF @Qidi X-Plus 5 0.8 nozzle.json | 11 + .../filament/X5/QIDI TPU-GF @X-Plus 5.json | 84 + ...IDI UltraPA @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...IDI UltraPA @Qidi X-Plus 5 0.6 nozzle.json | 11 + ...IDI UltraPA @Qidi X-Plus 5 0.8 nozzle.json | 11 + .../filament/X5/QIDI UltraPA @X-Plus 5.json | 99 + ...ltraPA-CF25 @Qidi X-Plus 5 0.4 nozzle.json | 11 + ...ltraPA-CF25 @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...ltraPA-CF25 @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../X5/QIDI UltraPA-CF25 @X-Plus 5.json | 114 + ...WOOD Rapido @Qidi X-Plus 5 0.4 nozzle.json | 14 + ...WOOD Rapido @Qidi X-Plus 5 0.6 nozzle.json | 14 + ...WOOD Rapido @Qidi X-Plus 5 0.8 nozzle.json | 14 + .../X5/QIDI WOOD Rapido @X-Plus 5.json | 66 + .../filament/X5/fdm_filament_x5_common.json | 255 ++ .../Qidi/machine/Qidi Q2 0.4 nozzle.json | 2 +- .../Qidi/machine/Qidi Q2C 0.4 nozzle.json | 2 +- .../Qidi/machine/Qidi X-Max 4 0.4 nozzle.json | 2 +- .../machine/Qidi X-Plus 4 0.4 nozzle.json | 2 +- .../machine/Qidi X-Plus 5 0.2 nozzle.json | 28 + .../machine/Qidi X-Plus 5 0.4 nozzle.json | 88 + .../machine/Qidi X-Plus 5 0.6 nozzle.json | 31 + .../machine/Qidi X-Plus 5 0.8 nozzle.json | 31 + .../profiles/Qidi/machine/Qidi X-Plus 5.json | 12 + ...8mm High Quality @X-Plus 5 0.2 nozzle.json | 70 + .../0.08mm High Quality @X-Plus 5.json | 73 + .../0.10mm Standard @X-Plus 5 0.2 nozzle.json | 63 + ...Balanced Quality @X-Plus 5 0.2 nozzle.json | 66 + .../0.12mm High Quality @X-Plus 5.json | 73 + .../0.16mm High Quality @X-Plus 5.json | 65 + .../process/0.16mm Standard @X-Plus 5.json | 62 + ...Balanced Quality @X-Plus 5 0.6 nozzle.json | 73 + .../0.20mm High Quality @X-Plus 5.json | 63 + .../process/0.20mm Standard @X-Plus 5.json | 47 + ...Balanced Quality @X-Plus 5 0.6 nozzle.json | 71 + ...Balanced Quality @X-Plus 5 0.8 nozzle.json | 63 + .../process/0.24mm Standard @X-Plus 5.json | 50 + .../0.30mm Standard @X-Plus 5 0.6 nozzle.json | 65 + ...Balanced Quality @X-Plus 5 0.8 nozzle.json | 72 + .../0.40mm Standard @X-Plus 5 0.8 nozzle.json | 60 + .../Qidi/qidi_xplus5_buildplate_model.stl | Bin 0 -> 28284 bytes .../Qidi/qidi_xplus5_buildplate_texture.svg | 1 + resources/profiles/Snapmaker.json | 278 ++- .../Polymaker General PLA Family @U1.json | 32 + .../filament/Polymaker PLA @U1 base.json | 107 + .../Polymaker Silk PLA Family @U1.json | 32 + .../Polymaker Tough PLA Family @U1.json | 32 + .../Fiberon ASA-CF08 @Snapmaker U1.json | 1 - .../Fiberon PA12-CF10 @Snapmaker U1.json | 1 - .../Fiberon PA6-CF20 @Snapmaker U1.json | 1 - .../Fiberon PETG-ESD @Snapmaker U1.json | 1 - .../PolyLite Dual PLA @0.2 nozzle.json | 6 +- .../PolyLite J1 PLA @0.2 nozzle.json | 6 +- .../filament/Polymaker/PolyLite J1 PLA.json | 6 +- .../Polymaker/PolyLite PETG @Base.json | 10 +- .../PolyLite PETG @Snapmaker U1.json | 1 - ...lyLite PETG Translucent @Snapmaker U1.json | 1 - .../Polymaker/PolyLite PLA @0.2 nozzle.json | 6 +- .../Polymaker/PolyLite PLA @base.json | 6 +- .../PolyTerra Dual PLA @0.2 nozzle.json | 6 +- .../PolyTerra J1 PLA @0.2 nozzle.json | 6 +- .../filament/Polymaker/PolyTerra J1 PLA.json | 6 +- .../Polymaker/PolyTerra PLA @0.2 nozzle.json | 6 +- .../Polymaker/Polymaker HT-PLA @Base.json | 10 +- .../Polymaker/Polymaker HT-PLA-GF @Base.json | 10 +- .../Polymaker/Polymaker PETG @Base.json | 10 +- .../Polymaker/Polymaker PLA Pro @Base.json | 10 +- .../Snapmaker/filament/Snapmaker ABS @U1.json | 3 + .../Snapmaker/filament/Snapmaker ASA @U1.json | 3 + ...akaway Support For PLA @U1 0.2 nozzle.json | 104 + ...akaway Support For PLA @U1 0.6 nozzle.json | 104 + ...akaway Support For PLA @U1 0.8 nozzle.json | 98 + ...apmaker Breakaway Support For PLA @U1.json | 78 + .../Snapmaker PETG HF @U1 0.2 nozzle.json | 108 + .../Snapmaker PETG HF @U1 0.6 nozzle.json | 113 + .../Snapmaker PETG HF @U1 0.8 nozzle.json | 110 + .../filament/Snapmaker PETG HF @U1 base2.json | 279 +++ ...maker PETG Translucent @U1 0.2 nozzle.json | 110 + ...maker PETG Translucent @U1 0.4 nozzle.json | 98 + ...maker PETG Translucent @U1 0.6 nozzle.json | 107 + ...maker PETG Translucent @U1 0.8 nozzle.json | 104 + .../Snapmaker PETG Translucent @U1 base.json | 8 + .../Snapmaker PLA Basic @U1 base.json | 127 + .../filament/Snapmaker PLA Basic @U1.json | 284 +++ ...aker PLA Full Spectrum @U1 0.4 nozzle.json | 284 +++ .../Snapmaker PLA Glow @U1 0.4 nozzle.json | 95 + .../filament/Snapmaker PLA Glow @U1 base.json | 44 + .../Snapmaker PLA Matte @U1 0.2 nozzle.json | 287 +++ .../Snapmaker PLA Matte @U1 0.6 nozzle.json | 287 +++ .../Snapmaker PLA Matte @U1 0.8 nozzle.json | 287 +++ .../Snapmaker PLA Matte @U1 base2.json | 127 + .../filament/Snapmaker PLA Matte @U1.json | 26 +- .../Snapmaker PLA Metal @U1 base.json | 3 - .../Snapmaker PLA Silk @U1 0.2 nozzle.json | 285 +++ .../Snapmaker PLA Silk @U1 0.6 nozzle.json | 285 +++ .../Snapmaker PLA Silk @U1 0.8 nozzle.json | 285 +++ .../filament/Snapmaker PLA Silk @U1 base.json | 3 - .../filament/Snapmaker PLA Silk @U1.json | 276 ++- ...napmaker PLA SnapSpeed @U1 0.2 nozzle.json | 50 + ...napmaker PLA SnapSpeed @U1 0.6 nozzle.json | 41 + ...napmaker PLA SnapSpeed @U1 0.8 nozzle.json | 41 + .../Snapmaker PLA SnapSpeed @U1 base2.json | 281 +++ .../filament/Snapmaker PLA SnapSpeed @U1.json | 42 +- ...pmaker PLA Translucent @U1 0.2 nozzle.json | 284 +++ ...pmaker PLA Translucent @U1 0.4 nozzle.json | 284 +++ ...pmaker PLA Translucent @U1 0.6 nozzle.json | 284 +++ ...pmaker PLA Translucent @U1 0.8 nozzle.json | 284 +++ .../Snapmaker PLA Translucent @U1 base.json | 44 + .../Snapmaker PLA Wood @U1 0.4 nozzle.json | 108 + .../Snapmaker PLA Wood @U1 0.6 nozzle.json | 114 + .../Snapmaker PLA Wood @U1 0.8 nozzle.json | 114 + .../Snapmaker PLA-CF @U1 0.4 nozzle.json | 132 + .../Snapmaker PLA-CF @U1 0.6 nozzle.json | 138 ++ .../Snapmaker PLA-CF @U1 0.8 nozzle.json | 135 + .../filament/Snapmaker PLA-CF @U1 base.json | 3 - .../filament/Snapmaker PLA-CF @U1.json | 3 + .../Snapmaker PVA @U1 0.6 nozzle.json | 113 + .../Snapmaker PVA @U1 0.8 nozzle.json | 107 + .../Snapmaker/filament/Snapmaker PVA @U1.json | 90 + .../Snapmaker TPU 90A @U1 0.6 nozzle.json | 150 ++ .../Snapmaker TPU 90A @U1 0.8 nozzle.json | 144 ++ .../filament/Snapmaker TPU 90A @U1.json | 141 ++ .../filament/Snapmaker TPU 95A @U1 base.json | 3 - .../Snapmaker TPU 95A HF @U1 0.6 nozzle.json | 147 ++ .../Snapmaker TPU 95A HF @U1 0.8 nozzle.json | 147 ++ .../filament/Snapmaker TPU 95A HF @U1.json | 144 ++ .../machine/Snapmaker U1 (0.2 nozzle).json | 171 +- .../machine/Snapmaker U1 (0.4 nozzle).json | 100 +- .../Snapmaker U1 (0.4+0.6 nozzle).json | 6 +- .../machine/Snapmaker U1 (0.6 nozzle).json | 179 +- .../machine/Snapmaker U1 (0.8 nozzle).json | 171 +- .../profiles/Snapmaker/machine/fdm_U1.json | 11 +- ...gh Quality @Snapmaker U1 (0.2 nozzle).json | 70 +- ...6 Standard @Snapmaker U1 (0.2 nozzle).json | 62 +- ...Extra Fine @Snapmaker U1 (0.4 nozzle).json | 15 +- ...gh Quality @Snapmaker U1 (0.2 nozzle).json | 70 +- ...gh Quality @Snapmaker U1 (0.4 nozzle).json | 14 +- ...8 Standard @Snapmaker U1 (0.2 nozzle).json | 62 +- ...gh Quality @Snapmaker U1 (0.2 nozzle).json | 70 +- ...0 Standard @Snapmaker U1 (0.2 nozzle).json | 66 +- .../0.12 Fine @Snapmaker U1 (0.4 nozzle).json | 15 +- ...gh Quality @Snapmaker U1 (0.4 nozzle).json | 17 +- ...2 Standard @Snapmaker U1 (0.2 nozzle).json | 62 +- ...4 Standard @Snapmaker U1 (0.2 nozzle).json | 62 +- ...gh Quality @Snapmaker U1 (0.4 nozzle).json | 15 +- ...16 Optimal @Snapmaker U1 (0.4 nozzle).json | 14 +- ...8 Standard @Snapmaker U1 (0.6 nozzle).json | 70 +- ... Support W @Snapmaker U1 (0.4 nozzle).json | 23 - ...20 Quality @Snapmaker U1 (0.4 nozzle).json | 1 + ...0 Standard @Snapmaker U1 (0.4 nozzle).json | 2 + ...andard @Snapmaker U1 (0.4+0.6 nozzle).json | 1 + ...0 Standard @Snapmaker U1 (0.6 nozzle).json | 1 + ...0 Strength @Snapmaker U1 (0.4 nozzle).json | 14 +- ...20 Support @Snapmaker U1 (0.4 nozzle).json | 2 + ... Support W @Snapmaker U1 (0.4 nozzle).json | 2 + ...0.24 Draft @Snapmaker U1 (0.4 nozzle).json | 14 +- ...4 Standard @Snapmaker U1 (0.6 nozzle).json | 69 +- ...4 Standard @Snapmaker U1 (0.8 nozzle).json | 71 +- ...xtra Draft @Snapmaker U1 (0.4 nozzle).json | 16 +- ...0.30 Draft @Snapmaker U1 (0.6 nozzle).json | 2 + ...0 Standard @Snapmaker U1 (0.6 nozzle).json | 67 +- ...0 Strength @Snapmaker U1 (0.6 nozzle).json | 71 +- ...2 Standard @Snapmaker U1 (0.8 nozzle).json | 74 +- ...6 Standard @Snapmaker U1 (0.6 nozzle).json | 69 +- ...xtra Draft @Snapmaker U1 (0.6 nozzle).json | 2 + ...0 Standard @Snapmaker U1 (0.8 nozzle).json | 76 +- ...2 Standard @Snapmaker U1 (0.6 nozzle).json | 69 +- ...8 Standard @Snapmaker U1 (0.8 nozzle).json | 71 +- ...6 Standard @Snapmaker U1 (0.8 nozzle).json | 68 +- .../Snapmaker/process/fdm_process_U1.json | 1 - .../fdm_process_U1_0.06_nozzle_0.2.json | 27 + .../fdm_process_U1_0.08_nozzle_0.2.json | 27 + .../fdm_process_U1_0.10_nozzle_0.2.json | 27 + .../fdm_process_U1_0.12_nozzle_0.2.json | 27 + .../fdm_process_U1_0.14_nozzle_0.2.json | 27 + .../fdm_process_U1_0.18_nozzle_0.6.json | 26 + .../fdm_process_U1_0.24_nozzle_0.6.json | 24 + .../fdm_process_U1_0.24_nozzle_0.8.json | 26 + .../fdm_process_U1_0.30_nozzle_0.6.json | 24 + .../fdm_process_U1_0.32_nozzle_0.8.json | 26 + .../fdm_process_U1_0.36_nozzle_0.6.json | 24 + .../fdm_process_U1_0.40_nozzle_0.8.json | 26 + .../fdm_process_U1_0.42_nozzle_0.6.json | 24 + .../fdm_process_U1_0.48_nozzle_0.8.json | 26 + .../fdm_process_U1_0.56_nozzle_0.8.json | 26 + .../process/fdm_process_U1_0.6_common.json | 2 +- .../process/fdm_process_U1_common.json | 13 +- .../Snapmaker/process/fdm_process_a400.json | 2 +- .../Snapmaker/process/fdm_process_common.json | 2 +- .../Snapmaker/process/fdm_process_idex.json | 2 +- .../Voron/machine/fdm_klipper_common.json | 2 +- resources/profiles/re3D.json | 431 ++-- .../re3D/filament/fdm_filament_pp.json | 10 + .../re3D/filament/re3D PC @0.4 nozzle.json | 3 + .../re3D/filament/re3D PC @0.8 nozzle.json | 3 + .../re3D/filament/re3D PETG @0.4 nozzle.json | 3 + .../re3D/filament/re3D PETG @0.8 nozzle.json | 3 + .../re3D/filament/re3D PLA @0.4 nozzle.json | 3 + .../re3D/filament/re3D PLA @0.8 nozzle.json | 3 + ...ozzle.json => re3D rPETG @0.8 nozzle.json} | 11 +- ...zzle.json => re3D rPETG @1.75 nozzle.json} | 11 +- ...D Greengate rPETG.json => re3D rPETG.json} | 7 +- .../re3D/filament/re3D rPP @0.8 nozzle.json | 2 +- .../re3D/filament/re3D rPP @1.75 nozzle.json | 2 +- .../profiles/re3D/filament/re3D rPP.json | 5 +- .../machine/re3D Gigabot 4 0.4 nozzle.json | 2 +- .../machine/re3D Gigabot 4 0.8 nozzle.json | 2 +- .../re3D Gigabot 4 XLT 0.4 nozzle.json | 2 +- .../re3D Gigabot 4 XLT 0.8 nozzle.json | 2 +- .../machine/re3D GigabotX 2 0.8 nozzle.json | 4 +- .../machine/re3D GigabotX 2 1.75 nozzle.json | 4 +- .../re3D GigabotX 2 XLT 0.8 nozzle.json | 4 +- .../re3D GigabotX 2 XLT 1.75 nozzle.json | 4 +- .../re3D/machine/re3D GigabotX 2 XLT.json | 2 +- .../re3D/machine/re3D GigabotX 2.json | 2 +- .../machine/re3D Terabot 4 0.4 nozzle.json | 2 +- .../machine/re3D Terabot 4 0.8 nozzle.json | 2 +- .../machine/re3D TerabotX 2 0.8 nozzle.json | 4 +- .../machine/re3D TerabotX 2 1.75 nozzle.json | 4 +- .../re3D/machine/re3D TerabotX 2.json | 2 +- .../0.26mm Standard @re3D fdm 0.4.json | 34 +- .../process/0.2mm Fine @re3D fdm 0.4.json | 31 +- .../process/0.32mm Draft @re3D fdm 0.4.json | 31 +- .../process/0.3mm Fine @re3D fdm 0.8.json | 31 +- .../process/0.4mm Draft @re3D fdm 0.8.json | 31 +- .../re3D/process/fdm_process_common.json | 12 - .../re3D/process/fdm_process_re3D_common.json | 202 +- resources/shaders/140/gouraud.fs | 97 +- resources/shaders/140/phong.fs | 79 +- resources/web/dialog/PluginsDialog/index.js | 19 +- resources/web/dialog/PluginsDialog/styles.css | 14 + scripts/msix/AppxManifest.xml | 18 +- scripts/orca_extra_profile_check.py | 10 +- src/OrcaSlicer.cpp | 2 +- src/libslic3r/AABBMesh.cpp | 15 +- src/libslic3r/AABBTreeLines.hpp | 3 +- src/libslic3r/AppConfig.cpp | 25 +- src/libslic3r/Arachne/WallToolPaths.hpp | 16 +- src/libslic3r/BoundingBox.hpp | 2 +- src/libslic3r/Brim.cpp | 38 +- src/libslic3r/Config.hpp | 25 +- src/libslic3r/Extruder.cpp | 4 +- src/libslic3r/Fill/Fill.cpp | 12 + src/libslic3r/Fill/FillBase.cpp | 10 +- src/libslic3r/Fill/FillBase.hpp | 3 + src/libslic3r/Fill/FillPlanePath.cpp | 163 +- src/libslic3r/Fill/FillPlanePath.hpp | 7 + src/libslic3r/Fill/FillRectilinear.cpp | 2 +- src/libslic3r/Format/STEP.cpp | 2 +- src/libslic3r/Format/STEP.hpp | 2 +- src/libslic3r/GCode.cpp | 297 ++- src/libslic3r/GCode.hpp | 9 +- src/libslic3r/GCode/GCodeProcessor.cpp | 10 +- src/libslic3r/GCode/PrintExtents.cpp | 3 +- src/libslic3r/GCode/WipeTower.cpp | 2200 ++++++++++------- src/libslic3r/GCode/WipeTower.hpp | 236 +- src/libslic3r/GCode/WipeTower2.cpp | 776 +++--- src/libslic3r/GCode/WipeTower2.hpp | 89 +- src/libslic3r/GCodeWriter.cpp | 52 +- src/libslic3r/Measure.hpp | 2 +- src/libslic3r/Model.cpp | 4 +- src/libslic3r/Orient.hpp | 120 +- src/libslic3r/PerimeterGenerator.cpp | 329 ++- src/libslic3r/PlaceholderParser.cpp | 2 + src/libslic3r/Polyline.hpp | 4 +- src/libslic3r/Preset.cpp | 15 +- src/libslic3r/PresetBundle.cpp | 2 +- src/libslic3r/Print.cpp | 156 +- src/libslic3r/PrintApply.cpp | 24 +- src/libslic3r/PrintConfig.cpp | 111 +- src/libslic3r/PrintConfig.hpp | 57 +- src/libslic3r/PrintObject.cpp | 87 +- src/libslic3r/SLA/IndexedMesh.cpp | 8 +- src/libslic3r/Technologies.hpp | 5 - src/libvgcode/include/Viewer.hpp | 9 +- src/libvgcode/src/Settings.hpp | 6 +- src/libvgcode/src/Viewer.cpp | 10 + src/libvgcode/src/ViewerImpl.cpp | 61 +- src/libvgcode/src/ViewerImpl.hpp | 7 +- src/slic3r/GUI/3DScene.cpp | 78 +- src/slic3r/GUI/AMSMaterialsSetting.cpp | 126 +- src/slic3r/GUI/ConfigManipulation.cpp | 106 +- src/slic3r/GUI/ConfigManipulation.hpp | 10 +- src/slic3r/GUI/ConnectPrinter.cpp | 4 +- src/slic3r/GUI/DeviceCore/DevManager.cpp | 64 +- src/slic3r/GUI/DeviceCore/DevManager.h | 7 +- src/slic3r/GUI/DeviceManager.cpp | 70 +- src/slic3r/GUI/DeviceManager.hpp | 8 +- .../GUI/DeviceTab/uiAmsHumidityPopup.cpp | 8 +- src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h | 10 +- .../GUI/DeviceTab/uiDeviceUpdateVersion.cpp | 8 +- .../GUI/DeviceTab/uiDeviceUpdateVersion.h | 8 +- src/slic3r/GUI/Field.cpp | 294 ++- src/slic3r/GUI/Field.hpp | 38 + src/slic3r/GUI/GCodeViewer.cpp | 3 +- src/slic3r/GUI/GCodeViewer.hpp | 5 +- src/slic3r/GUI/GLCanvas3D.cpp | 193 +- src/slic3r/GUI/GLCanvas3D.hpp | 6 + src/slic3r/GUI/GUI.cpp | 8 +- src/slic3r/GUI/GUI.hpp | 10 +- src/slic3r/GUI/GUI_App.cpp | 136 +- src/slic3r/GUI/GUI_App.hpp | 12 +- src/slic3r/GUI/GUI_Factories.cpp | 1 + src/slic3r/GUI/GUI_ObjectList.cpp | 2 +- src/slic3r/GUI/GUI_ObjectSettings.cpp | 8 +- src/slic3r/GUI/GUI_ObjectSettings.hpp | 2 +- src/slic3r/GUI/GUI_ObjectTableSettings.cpp | 7 +- src/slic3r/GUI/GUI_ObjectTableSettings.hpp | 2 +- src/slic3r/GUI/GUI_Utils.cpp | 54 +- src/slic3r/GUI/GUI_Utils.hpp | 30 +- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp | 70 +- src/slic3r/GUI/Gizmos/GLGizmoBrimEars.hpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 7 +- src/slic3r/GUI/IMSlider.cpp | 2 +- src/slic3r/GUI/ImGuiWrapper.cpp | 14 + src/slic3r/GUI/Jobs/ArrangeJob.cpp | 2 +- .../GUI/Jobs/CreateFontStyleImagesJob.cpp | 30 +- src/slic3r/GUI/Jobs/OrientJob.cpp | 43 +- src/slic3r/GUI/MainFrame.cpp | 106 +- src/slic3r/GUI/MainFrame.hpp | 4 +- src/slic3r/GUI/MsgDialog.cpp | 124 +- src/slic3r/GUI/MsgDialog.hpp | 6 +- src/slic3r/GUI/OptionsGroup.cpp | 28 + src/slic3r/GUI/OptionsGroup.hpp | 9 + src/slic3r/GUI/PartPlate.cpp | 37 +- src/slic3r/GUI/PartPlate.hpp | 3 + src/slic3r/GUI/PhysicalPrinterDialog.cpp | 90 +- src/slic3r/GUI/PhysicalPrinterDialog.hpp | 1 - src/slic3r/GUI/Plater.cpp | 78 +- src/slic3r/GUI/PluginSource.hpp | 2 + src/slic3r/GUI/PluginsDialog.cpp | 53 +- src/slic3r/GUI/PluginsDialog.hpp | 1 + src/slic3r/GUI/Preferences.cpp | 46 +- src/slic3r/GUI/Preferences.hpp | 2 + src/slic3r/GUI/PresetComboBoxes.cpp | 3 + src/slic3r/GUI/ReleaseNote.cpp | 9 +- src/slic3r/GUI/SavePresetDialog.cpp | 56 +- src/slic3r/GUI/SavePresetDialog.hpp | 1 - src/slic3r/GUI/SelectMachine.cpp | 13 +- src/slic3r/GUI/SelectMachinePop.cpp | 1 - src/slic3r/GUI/Selection.cpp | 17 +- src/slic3r/GUI/Tab.cpp | 152 +- src/slic3r/GUI/Tab.hpp | 2 + src/slic3r/GUI/Widgets/CheckBox.cpp | 4 +- src/slic3r/GUI/Widgets/RadioBox.cpp | 5 + src/slic3r/GUI/Widgets/SpinInput.cpp | 9 + src/slic3r/GUI/Widgets/SwitchButton.cpp | 4 +- src/slic3r/GUI/Widgets/TextInput.cpp | 9 + src/slic3r/GUI/wxExtensions.cpp | 4 + src/slic3r/Utils/IPrinterAgent.hpp | 7 + src/slic3r/Utils/MoonrakerPrinterAgent.cpp | 1 - src/slic3r/Utils/NetworkAgentFactory.cpp | 20 - src/slic3r/Utils/NetworkAgentFactory.hpp | 2 - src/slic3r/Utils/PresetUpdater.cpp | 96 +- src/slic3r/Utils/RaycastManager.cpp | 2 +- src/slic3r/plugin/PluginDescriptor.hpp | 3 + src/slic3r/plugin/PluginFsUtils.cpp | 3 +- src/slic3r/plugin/PluginManager.cpp | 83 +- src/slic3r/plugin/PluginManager.hpp | 6 + src/slic3r/plugin/host/PluginHostApp.cpp | 10 + .../wipe_tower_temperature_trace_main.txt | 172 ++ tests/fff_print/CMakeLists.txt | 2 + tests/fff_print/test_multifilament.cpp | 611 +++++ tests/fff_print/test_perimeters.cpp | 257 ++ tests/fff_print/test_print.cpp | 16 + tests/fff_print/test_skirt_brim.cpp | 168 ++ tests/fff_print/test_wipe_tower.cpp | 184 ++ tests/libslic3r/CMakeLists.txt | 2 + tests/libslic3r/test_3mf.cpp | 97 +- tests/libslic3r/test_config.cpp | 57 +- .../test_config_variant_expansion.cpp | 121 +- tests/libslic3r/test_fill_plane_path.cpp | 164 ++ tests/libslic3r/test_model.cpp | 40 + .../libslic3r/test_preset_bundle_loading.cpp | 116 +- .../test_toolordering_nozzle_group.cpp | 55 +- tests/slic3rutils/plugin_test_utils.hpp | 20 +- tests/slic3rutils/test_network_versions.cpp | 19 +- .../test_plugin_cloud_metadata.cpp | 40 + tests/slic3rutils/test_plugin_lifecycle.cpp | 28 +- .../test_slicing_pipeline_bindings.cpp | 8 +- tests/test_utils.hpp | 82 +- 750 files changed, 33478 insertions(+), 6833 deletions(-) create mode 100644 resources/profiles/Qidi/Qidi X-Plus 5_cover.png create mode 100644 resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Bambu ABS @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Bambu PETG @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Bambu PLA @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic ABS @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PC @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PETG @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PLA @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PLA Silk @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PLA Silk @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PLA Silk @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic PLA+ @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic TPU 95A @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic TPU 95A @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic TPU 95A @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Generic TPU 95A @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/HATCHBOX ABS @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/HATCHBOX PETG @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/HATCHBOX PLA @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Overture ABS @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Overture PLA @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/PolyLite ABS @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/PolyLite PLA @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS-GF @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS-GF @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS-GF @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ABS-GF @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ASA @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ASA-Aero @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ASA-Aero @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ASA-CF @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ASA-CF @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ASA-CF @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI ASA-CF @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PA12-CF @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PA12-CF @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PA12-CF @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PA12-CF @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PA6-CF @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PA6-CF @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PA6-CF @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PA6-CF @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PEBA 95A @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PEBA 95A @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PEBA 95A @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PET-CF @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PET-CF @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PET-CF @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PET-CF @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PET-GF @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PET-GF @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PET-GF @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PET-GF @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Basic @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Tough @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG-CF @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG-CF @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG-CF @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG-CF @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG-GF @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG-GF @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG-GF @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PETG-GF @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Basic @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Silk @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Silk @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA Silk @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA-CF @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA-CF @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA-CF @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PLA-CF @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PPS-CF @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PPS-CF @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PPS-CF @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PPS-CF @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PPS-GF @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PPS-GF @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PPS-GF @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI PPS-GF @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI TPU-Aero @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI TPU-Aero @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI TPU-Aero @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI TPU-GF @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI TPU-GF @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI TPU-GF @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI TPU-GF @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI UltraPA @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI UltraPA @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI UltraPA @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI UltraPA @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @X-Plus 5.json create mode 100644 resources/profiles/Qidi/filament/X5/fdm_filament_x5_common.json create mode 100644 resources/profiles/Qidi/machine/Qidi X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/machine/Qidi X-Plus 5 0.4 nozzle.json create mode 100644 resources/profiles/Qidi/machine/Qidi X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/machine/Qidi X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/machine/Qidi X-Plus 5.json create mode 100644 resources/profiles/Qidi/process/0.08mm High Quality @X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/process/0.08mm High Quality @X-Plus 5.json create mode 100644 resources/profiles/Qidi/process/0.10mm Standard @X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/process/0.12mm Balanced Quality @X-Plus 5 0.2 nozzle.json create mode 100644 resources/profiles/Qidi/process/0.12mm High Quality @X-Plus 5.json create mode 100644 resources/profiles/Qidi/process/0.16mm High Quality @X-Plus 5.json create mode 100644 resources/profiles/Qidi/process/0.16mm Standard @X-Plus 5.json create mode 100644 resources/profiles/Qidi/process/0.18mm Balanced Quality @X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/process/0.20mm High Quality @X-Plus 5.json create mode 100644 resources/profiles/Qidi/process/0.20mm Standard @X-Plus 5.json create mode 100644 resources/profiles/Qidi/process/0.24mm Balanced Quality @X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/process/0.24mm Balanced Quality @X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/process/0.24mm Standard @X-Plus 5.json create mode 100644 resources/profiles/Qidi/process/0.30mm Standard @X-Plus 5 0.6 nozzle.json create mode 100644 resources/profiles/Qidi/process/0.32mm Balanced Quality @X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/process/0.40mm Standard @X-Plus 5 0.8 nozzle.json create mode 100644 resources/profiles/Qidi/qidi_xplus5_buildplate_model.stl create mode 100644 resources/profiles/Qidi/qidi_xplus5_buildplate_texture.svg create mode 100644 resources/profiles/Snapmaker/filament/Polymaker General PLA Family @U1.json create mode 100644 resources/profiles/Snapmaker/filament/Polymaker PLA @U1 base.json create mode 100644 resources/profiles/Snapmaker/filament/Polymaker Silk PLA Family @U1.json create mode 100644 resources/profiles/Snapmaker/filament/Polymaker Tough PLA Family @U1.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1 0.2 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1 0.6 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1 0.8 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 0.2 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 0.6 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 0.8 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 base2.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.2 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.4 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.6 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.8 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 base.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Basic @U1 base.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Basic @U1.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Full Spectrum @U1 0.4 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Glow @U1 0.4 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Glow @U1 base.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 0.2 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 0.6 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 0.8 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 base2.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 0.2 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 0.6 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 0.8 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 0.2 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 0.6 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 0.8 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 base2.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.2 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.4 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.6 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.8 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 base.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Wood @U1 0.4 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Wood @U1 0.6 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA Wood @U1 0.8 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 0.4 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 0.6 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 0.8 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PVA @U1 0.6 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker PVA @U1 0.8 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker TPU 90A @U1 0.6 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker TPU 90A @U1 0.8 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker TPU 90A @U1.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker TPU 95A HF @U1 0.6 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker TPU 95A HF @U1 0.8 nozzle.json create mode 100644 resources/profiles/Snapmaker/filament/Snapmaker TPU 95A HF @U1.json delete mode 100644 resources/profiles/Snapmaker/process/0.20 Bambu Support W @Snapmaker U1 (0.4 nozzle).json create mode 100644 resources/profiles/Snapmaker/process/fdm_process_U1_0.06_nozzle_0.2.json create mode 100644 resources/profiles/Snapmaker/process/fdm_process_U1_0.08_nozzle_0.2.json create mode 100644 resources/profiles/Snapmaker/process/fdm_process_U1_0.10_nozzle_0.2.json create mode 100644 resources/profiles/Snapmaker/process/fdm_process_U1_0.12_nozzle_0.2.json create mode 100644 resources/profiles/Snapmaker/process/fdm_process_U1_0.14_nozzle_0.2.json create mode 100644 resources/profiles/Snapmaker/process/fdm_process_U1_0.18_nozzle_0.6.json create mode 100644 resources/profiles/Snapmaker/process/fdm_process_U1_0.24_nozzle_0.6.json create mode 100644 resources/profiles/Snapmaker/process/fdm_process_U1_0.24_nozzle_0.8.json create mode 100644 resources/profiles/Snapmaker/process/fdm_process_U1_0.30_nozzle_0.6.json create mode 100644 resources/profiles/Snapmaker/process/fdm_process_U1_0.32_nozzle_0.8.json create mode 100644 resources/profiles/Snapmaker/process/fdm_process_U1_0.36_nozzle_0.6.json create mode 100644 resources/profiles/Snapmaker/process/fdm_process_U1_0.40_nozzle_0.8.json create mode 100644 resources/profiles/Snapmaker/process/fdm_process_U1_0.42_nozzle_0.6.json create mode 100644 resources/profiles/Snapmaker/process/fdm_process_U1_0.48_nozzle_0.8.json create mode 100644 resources/profiles/Snapmaker/process/fdm_process_U1_0.56_nozzle_0.8.json create mode 100644 resources/profiles/re3D/filament/fdm_filament_pp.json rename resources/profiles/re3D/filament/{re3D Greengate rPETG @0.8 nozzle.json => re3D rPETG @0.8 nozzle.json} (89%) rename resources/profiles/re3D/filament/{re3D Greengate rPETG @1.75 nozzle.json => re3D rPETG @1.75 nozzle.json} (89%) rename resources/profiles/re3D/filament/{re3D Greengate rPETG.json => re3D rPETG.json} (78%) create mode 100644 tests/data/wipe_tower_temperature_trace_main.txt create mode 100644 tests/fff_print/test_perimeters.cpp create mode 100644 tests/fff_print/test_wipe_tower.cpp create mode 100644 tests/libslic3r/test_fill_plane_path.cpp create mode 100644 tests/libslic3r/test_model.cpp diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 1b3ba3f407..63f74a069e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -32,9 +32,17 @@ body: attributes: label: OrcaSlicer Version description: Which version of Orca Slicer are you running? You can see the full version in `Help` -> `About Orca Slicer`. - placeholder: e.g. 1.9.0 + placeholder: e.g. 2.5.0 validations: required: true + - type: input + id: working_version + attributes: + label: Regression compared to a previous version + description: Did it work in a previous version? + placeholder: e.g. 2.3.2 + validations: + required: false - type: dropdown id: os_type attributes: diff --git a/CMakeLists.txt b/CMakeLists.txt index c9417fc906..fc688b35df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,8 +80,12 @@ endif() if (DEFINED BBL_RELEASE_TO_PUBLIC) add_compile_definitions("BBL_RELEASE_TO_PUBLIC=${BBL_RELEASE_TO_PUBLIC}") + if (BBL_RELEASE_TO_PUBLIC) + add_compile_definitions(WXINSPECTOR_DISABLE) + endif () else () add_compile_definitions("BBL_RELEASE_TO_PUBLIC=$") + add_compile_definitions("$<$:WXINSPECTOR_DISABLE>") endif () find_package(Git) diff --git a/README.md b/README.md index 2242d6ae33..e9a28ba4f3 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,10 @@ Download the **Windows Installer exe** for your preferred version from the [rele - This file may already be available on your computer if you've installed visual studio. Check the following location: `%VCINSTALLDIR%Redist\MSVC\v142` +### Microsoft Store + +Install from the [Microsoft Store](https://apps.microsoft.com/detail/9mv6gl23xm59) when you prefer a Store-signed package (helps on Windows 11 Smart App Control). + ### Windows Package Manager ```shell diff --git a/deps/OpenSSL/OpenSSL.cmake b/deps/OpenSSL/OpenSSL.cmake index 21a49b91b8..e43997265b 100644 --- a/deps/OpenSSL/OpenSSL.cmake +++ b/deps/OpenSSL/OpenSSL.cmake @@ -52,6 +52,14 @@ ExternalProject_Add(dep_OpenSSL CONFIGURE_COMMAND ${_conf_cmd} ${_cross_arch} "--openssldir=${DESTDIR}" "--prefix=${DESTDIR}" + # OpenSSL's linux-x86_64 target sets multilib=64, so it installs to + # /lib64 while every other dep uses /lib. CPython's + # --with-openssl only ever emits -L/lib, so it misses the bundled + # static libs and silently links the system OpenSSL instead -- which, + # against 1.1.1w headers, leaves _ssl.so with an undefined + # SSL_get_peer_certificate (removed in OpenSSL 3.x). Pin libdir so the + # prefix stays single-layout. + "--libdir=lib" ${_cross_comp_prefix_line} no-shared no-asm diff --git a/deps_src/imgui/imgui_draw.cpp b/deps_src/imgui/imgui_draw.cpp index 913a551fa0..d88bc79904 100644 --- a/deps_src/imgui/imgui_draw.cpp +++ b/deps_src/imgui/imgui_draw.cpp @@ -2856,6 +2856,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesDefault() { 0x0020, 0x00FF, // Basic Latin + Latin Supplement 0x2000, 0x206F, // General Punctuation + 0x2103, 0x2103, // ℃ Celsius symbol 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana 0x31F0, 0x31FF, // Katakana Phonetic Extensions 0xFF00, 0xFFEF, // Half-width characters diff --git a/deps_src/imgui/imstb_textedit.h b/deps_src/imgui/imstb_textedit.h index 7644670975..3733bb2fa9 100644 --- a/deps_src/imgui/imstb_textedit.h +++ b/deps_src/imgui/imstb_textedit.h @@ -465,6 +465,57 @@ static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *stat STB_TEXTEDIT_LAYOUTROW(&r, str, 0); y = r.ymin; } + else + { + // In multi-line mode, clamp y to stay within the text vertical bounds. + // This lets the click still land at a valid location if the mouse is slightly + // above or below the text. + StbTexteditRow r; + int n = STB_TEXTEDIT_STRINGLEN(str); + int i = 0; + float base_y = 0, y_min, y_max; + + // Get the first row to establish y_min and start the iteration + STB_TEXTEDIT_LAYOUTROW(&r, str, 0); + if (r.num_chars <= 0) + { + state->cursor = 0; + state->select_start = state->cursor; + state->select_end = state->cursor; + state->has_preferred_x = 0; + return; + } + y_min = r.ymin; + y_max = base_y + r.ymax; + i = r.num_chars; + base_y += r.baseline_y_delta; + + // Walk the remaining rows to find the bottom of the last row + while (i < n) + { + STB_TEXTEDIT_LAYOUTROW(&r, str, i); + if (r.num_chars <= 0) + break; + y_max = base_y + r.ymax; + i += r.num_chars; + base_y += r.baseline_y_delta; + } + + // If the text ends with a newline, account for the empty trailing line + // so the cursor can be placed on it + if (n > 0 && STB_TEXTEDIT_GETCHAR(str, n - 1) == STB_TEXTEDIT_NEWLINE) + { + STB_TEXTEDIT_LAYOUTROW(&r, str, n); + y_max = base_y + r.ymax; + } + + // Subtract half the last line height to avoid rounding issues when the mouse + // is just barely below the last line (keep cursor on the last line, not after the text) + y_max -= (r.ymax - r.ymin) * 0.5f; + + if (y < y_min) y = y_min; + if (y > y_max) y = y_max; + } state->cursor = stb_text_locate_coord(str, x, y); state->select_start = state->cursor; @@ -485,6 +536,50 @@ static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state STB_TEXTEDIT_LAYOUTROW(&r, str, 0); y = r.ymin; } + else + { + // In multi-line mode, clamp y to stay within the text vertical bounds. + // This lets the drag keep working if the mouse goes off the top or bottom of the text. + StbTexteditRow r; + int n = STB_TEXTEDIT_STRINGLEN(str); + int i = 0; + float base_y = 0, y_min, y_max; + + // Get the first row to establish y_min and start the iteration + STB_TEXTEDIT_LAYOUTROW(&r, str, 0); + if (r.num_chars <= 0) + return; + y_min = r.ymin; + y_max = base_y + r.ymax; + i = r.num_chars; + base_y += r.baseline_y_delta; + + // Walk the remaining rows to find the bottom of the last row + while (i < n) + { + STB_TEXTEDIT_LAYOUTROW(&r, str, i); + if (r.num_chars <= 0) + break; + y_max = base_y + r.ymax; + i += r.num_chars; + base_y += r.baseline_y_delta; + } + + // If the text ends with a newline, account for the empty trailing line + // so the cursor can be placed on it + if (n > 0 && STB_TEXTEDIT_GETCHAR(str, n - 1) == STB_TEXTEDIT_NEWLINE) + { + STB_TEXTEDIT_LAYOUTROW(&r, str, n); + y_max = base_y + r.ymax; + } + + // Subtract half the last line height to avoid rounding issues when the mouse + // is just barely below the last line (keep cursor on the last line, not after the text) + y_max -= (r.ymax - r.ymin) * 0.5f; + + if (y < y_min) y = y_min; + if (y > y_max) y = y_max; + } if (state->select_start == state->select_end) state->select_start = state->cursor; diff --git a/localization/i18n/OrcaSlicer.pot b/localization/i18n/OrcaSlicer.pot index 208dd08218..88e49a85fc 100644 --- a/localization/i18n/OrcaSlicer.pot +++ b/localization/i18n/OrcaSlicer.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -3608,6 +3608,9 @@ msgstr "" msgid "Arranging" msgstr "" +msgid "Arranging " +msgstr "" + msgid "Arranging canceled." msgstr "" @@ -7778,19 +7781,19 @@ msgid "Replaced with 3D files from directory:\n" msgstr "" #, possible-boost-format -msgid "✖ Skipped %1%: same file.\n" +msgid "✖ Skipped %s: same file.\n" msgstr "" #, possible-boost-format -msgid "✖ Skipped %1%: file does not exist.\n" +msgid "✖ Skipped %s: file does not exist.\n" msgstr "" #, possible-boost-format -msgid "✖ Skipped %1%: failed to replace.\n" +msgid "✖ Skipped %s: failed to replace.\n" msgstr "" #, possible-boost-format -msgid "✔ Replaced %1%.\n" +msgid "✔ Replaced %s.\n" msgstr "" msgid "Replaced volumes" @@ -8661,6 +8664,17 @@ msgstr "" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "" +msgid "Dimmed layer brightness" +msgstr "" + +msgid "%" +msgstr "" + +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" + msgid "Login region" msgstr "" @@ -12357,12 +12371,26 @@ msgstr "" msgid "Intra-layer order" msgstr "" -msgid "Print order within a single layer." +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." msgstr "" msgid "As object list" msgstr "" +msgid "Best of all (shortest path)" +msgstr "" + +msgid "Snake" +msgstr "" + msgid "Slow printing down for better layer cooling" msgstr "" @@ -17218,6 +17246,15 @@ msgid "" "Please select one that should be used." msgstr "" +msgid "Auto-scale for nozzle" +msgstr "" + +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" + msgid "PA Calibration" msgstr "" @@ -17340,6 +17377,12 @@ msgstr "" msgid "End speed: " msgstr "" +msgid "Auto-adjust to max volumetric speed" +msgstr "" + +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "" + msgid "" "Please input valid values:\n" "start > 10\n" @@ -17347,6 +17390,39 @@ msgid "" "end > start + step" msgstr "" +#, possible-c-format, possible-boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" + +#, possible-c-format, possible-boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" + +#, possible-c-format, possible-boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" + +msgid "Continue anyway?" +msgstr "" + +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "" + +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "" + msgid "Start retraction length: " msgstr "" diff --git a/localization/i18n/ca/OrcaSlicer_ca.po b/localization/i18n/ca/OrcaSlicer_ca.po index 92e367eaf5..79a9d82df4 100644 --- a/localization/i18n/ca/OrcaSlicer_ca.po +++ b/localization/i18n/ca/OrcaSlicer_ca.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: 2025-03-15 10:55+0100\n" "Last-Translator: \n" "Language-Team: \n" @@ -3931,6 +3931,10 @@ msgstr "Organitzant..." msgid "Arranging" msgstr "Organitzant" +# AI Translated +msgid "Arranging " +msgstr "Organitzant " + msgid "Arranging canceled." msgstr "S'ha cancel·lat l'ordenació." @@ -8357,21 +8361,21 @@ msgstr "No s'ha seleccionat el directori per a la substitució" msgid "Replaced with 3D files from directory:\n" msgstr "Substituït amb fitxers 3D del directori:\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ Omès %1%: mateix fitxer.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ Omès %s: mateix fitxer.\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ Omès %1%: el fitxer no existeix.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ Omès %s: el fitxer no existeix.\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ Omès %1%: la substitució ha fallat.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ Omès %s: la substitució ha fallat.\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ Substituït %1%.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ Substituït %s.\n" msgid "Replaced volumes" msgstr "Volums substituïts" @@ -9350,6 +9354,21 @@ msgstr "Enfosquir les capes inferiors" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "En desplaçar el control lliscant de capes a la previsualització laminada, mostra enfosquides les capes per sota de l'actual, de manera que només la capa que s'està visualitzant es vegi amb la lluminositat completa." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Brillantor de les capes enfosquides" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"Amb quina brillantor es mostren les capes enfosquides quan \"Enfosquir les capes inferiors\" està activat.\n" +"99% amb prou feines s'enfosqueix, 0% les mostra negres. Limitat al 99% perquè el 100% seria el mateix que desactivar l'opció." + msgid "Login region" msgstr "Regió d'inici de sessió" @@ -13494,12 +13513,37 @@ msgstr "Objecte" msgid "Intra-layer order" msgstr "Ordre intracapa" -msgid "Print order within a single layer." -msgstr "Ordre d'impressió dins d'una sola capa" +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Ordre en què es visiten les instàncies dels objectes dins d'una mateixa capa, que determina quant recorregut es dedica a moure's entre elles.\n" +"\n" +"Per defecte: encadenament pel veí més proper, refinat amb 2-opt i eliminació de creuaments. Una bona opció general.\n" +"Com a llista d'objectes: les instàncies s'imprimeixen en el mateix ordre que la llista d'objectes, sense cap optimització del recorregut. Feu-lo servir quan necessiteu un ordre previsible i controlat manualment.\n" +"La millor de totes (camí més curt): s'avaluen totes les estratègies i s'utilitza la més curta. L'ordre de les instàncies dels objectes es decideix una sola vegada per a tota la impressió, mentre que l'ordre de les illes individuals es decideix per capa, de manera que capes diferents poden acabar utilitzant estratègies diferents. El laminat és una mica més lent.\n" +"Serpentí: recorregut en serpentina, fila per fila, refinat amb 2-opt. Adequat per a graelles regulars de moltes peces petites.\n" +"\n" +"Amb diversos filaments o eines a la mateixa capa, minimitzar els canvis d'eina té prioritat: els objectes s'agrupen primer per filament i aquest paràmetre només ordena les instàncies dins de cada grup de filament, de manera que la seqüència global pot no semblar el camí més curt per la safata." msgid "As object list" msgstr "Com a llista d'objectes" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "La millor de totes (camí més curt)" + +# AI Translated +msgid "Snake" +msgstr "Serpentí" + msgid "Slow printing down for better layer cooling" msgstr "Reduir la velocitat d'impressió per millorar la refrigeració de les capes" @@ -18927,6 +18971,20 @@ msgstr "" "Hi ha diverses adreces IP que responen al nom d'amfitrió( host ) %1%.\n" "Seleccioneu-ne la que s'hagi d'utilitzar." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "Escala automàtica segons el broquet" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Aquest model està dissenyat per a un broquet de 0,4 mm amb una alçada de capa de 0,2 mm. \n" +"Quan l'opció d'escalat està activada (recomanat), es redimensiona dinàmicament per adaptar-se al diàmetre del broquet actual i a una alçada de capa adequada, cosa que fa que la prova sigui precisa i fàcil de llegir.\n" +"Desactiveu l'escalat només si voleu imprimir el model de referència exactament tal com és." + msgid "PA Calibration" msgstr "Calibratge PA( Pressure Advance )" @@ -19063,6 +19121,14 @@ msgstr "Velocitat d'inici: " msgid "End speed: " msgstr "Velocitat final: " +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "Ajust automàtic a la velocitat volumètrica màxima" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Si la velocitat final superés la velocitat volumètrica màxima del filament, redueix automàticament l'alçada de capa (mantenint valors estàndard i respectant els límits de la màquina) per assolir-la. Si ni tan sols l'alçada de capa mínima és suficient, redueix la velocitat final." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -19074,6 +19140,57 @@ msgstr "" "pas >= 0\n" "final >inici + pas )" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"La velocitat final (%.0f mm/s) supera la velocitat volumètrica màxima del filament (%.1f mm³/s), cosa que limita el perímetre exterior a uns %.0f mm/s amb aquesta amplada de línia i alçada de capa.\n" +" Les velocitats superiors es retallaran, de manera que els blocs superiors de la torre no s'imprimiran a la velocitat sol·licitada.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"La velocitat final (%.0f mm/s) supera la velocitat volumètrica màxima del filament (%.1f mm³/s) amb l'alçada de capa per defecte (%.2f mm).\n" +"\n" +"L'alçada de capa s'ha reduït a %.2f mm (un valor utilitzat pels perfils d'aquesta impressora) perquè la torre pugui assolir la velocitat sol·licitada." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Fins i tot amb l'alçada de capa més petita utilitzada pels perfils d'aquesta impressora (%.2f mm), la velocitat final (%.0f mm/s) supera la velocitat volumètrica màxima del filament (%.1f mm³/s).\n" +"\n" +"L'alçada de capa s'establirà a %.2f mm i la velocitat final es reduirà a %.0f mm/s.\n" +"\n" +"Voleu continuar?" + +# AI Translated +msgid "Continue anyway?" +msgstr "Voleu continuar igualment?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Voleu activar \"Ajust automàtic\" per corregir-ho automàticament o continuar igualment?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Voleu activar \"Escala automàtica segons el broquet\" i \"Ajust automàtic\" per corregir-ho automàticament o continuar igualment?" + msgid "Start retraction length: " msgstr "Longitud de la retracció d'inici: " @@ -21770,6 +21887,9 @@ msgstr "" "Evitar la deformació( warping )\n" "Sabíeu que quan imprimiu materials propensos a deformar-se, com ara l'ABS, augmentar adequadament la temperatura del llit pot reduir la probabilitat de deformació?" +#~ msgid "Print order within a single layer." +#~ msgstr "Ordre d'impressió dins d'una sola capa" + #~ msgid "Bottom" #~ msgstr "Inferior" @@ -21856,9 +21976,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Continue to sync filaments" #~ msgstr "Continua sincronitzant filaments" diff --git a/localization/i18n/cs/OrcaSlicer_cs.po b/localization/i18n/cs/OrcaSlicer_cs.po index 6f991f6996..e21fd3086c 100644 --- a/localization/i18n/cs/OrcaSlicer_cs.po +++ b/localization/i18n/cs/OrcaSlicer_cs.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: \n" "Last-Translator: Jakub Hencl\n" "Language-Team: \n" @@ -3888,6 +3888,10 @@ msgstr "Uspořádání..." msgid "Arranging" msgstr "Uspořádání" +# AI Translated +msgid "Arranging " +msgstr "Rozkládání " + msgid "Arranging canceled." msgstr "Uspořádání zrušeno." @@ -8316,21 +8320,21 @@ msgstr "Nebyla vybrána složka pro nahrazení" msgid "Replaced with 3D files from directory:\n" msgstr "Nahrazeno 3D soubory ze složky:\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ Přeskočeno %1%: stejný soubor.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ Přeskočeno %s: stejný soubor.\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ Přeskočeno %1%: soubor neexistuje.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ Přeskočeno %s: soubor neexistuje.\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ Přeskočeno %1%: nahrazení se nezdařilo.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ Přeskočeno %s: nahrazení se nezdařilo.\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ Nahrazeno %1%.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ Nahrazeno %s.\n" msgid "Replaced volumes" msgstr "Nahrazené objemy" @@ -9305,6 +9309,21 @@ msgstr "Ztmavit nižší vrstvy" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "Při posouvání posuvníku vrstev v náhledu po slicování vykresluje vrstvy pod aktuální ztmavené, takže v plném jasu je zobrazena pouze prohlížená vrstva." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Jas ztmavených vrstev" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"Jak jasně se vykreslují ztmavené vrstvy, když je zapnuta volba „Ztmavit nižší vrstvy“.\n" +"99 % znamená sotva znatelné ztmavení, 0 % je vykreslí černě. Maximum je 99 %, protože 100 % by odpovídalo vypnutí této volby." + msgid "Login region" msgstr "Oblast přihlášení" @@ -13475,12 +13494,37 @@ msgstr "Podle objektu" msgid "Intra-layer order" msgstr "Pořadí v rámci vrstvy" -msgid "Print order within a single layer." -msgstr "Pořadí tisku v rámci jedné vrstvy." +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Pořadí, v jakém se v rámci jedné vrstvy navštěvují instance objektů; určuje, kolik přejezdů se stráví přesuny mezi nimi.\n" +"\n" +"Výchozí: řetězení metodou nejbližšího souseda, doladěné algoritmem 2-opt a odstraněním křížení. Dobrá volba pro obecné použití.\n" +"Jako seznam objektů: instance se tisknou ve stejném pořadí jako v seznamu objektů, bez jakékoli optimalizace dráhy. Použijte, když potřebujete předvídatelné, ručně řízené pořadí.\n" +"Nejlepší ze všech (nejkratší dráha): vyhodnotí se všechny strategie a použije se ta nejkratší. Pořadí instancí objektů se určí jednou pro celý tisk, zatímco pořadí jednotlivých ostrůvků se určuje pro každou vrstvu zvlášť, takže různé vrstvy mohou nakonec používat různé strategie. Slicování je mírně pomalejší.\n" +"Hadovitě: klikaté procházení řádek po řádku, doladěné algoritmem 2-opt. Vhodné pro pravidelné mřížky mnoha malých dílů.\n" +"\n" +"Pokud je v téže vrstvě více filamentů nebo nástrojů, má přednost minimalizace výměn nástroje: objekty se nejprve seskupí podle filamentu a toto nastavení pak řadí pouze instance uvnitř každé skupiny, takže celková posloupnost nemusí vypadat jako nejkratší dráha po desce." msgid "As object list" msgstr "Jako seznam objektů" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "Nejlepší ze všech (nejkratší dráha)" + +# AI Translated +msgid "Snake" +msgstr "Hadovitě" + msgid "Slow printing down for better layer cooling" msgstr "Zpomalit tisk pro lepší chlazení vrstvy" @@ -18850,6 +18894,20 @@ msgstr "" "Ke jménu hostitele %1% je přiřazeno několik IP adres.\n" "Vyberte prosím jednu, která má být použita." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "Automatické měřítko podle trysky" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Tento model je navržen pro trysku 0,4 mm a výšku vrstvy 0,2 mm. \n" +"Je-li volba změny měřítka zapnuta (doporučeno), model se dynamicky přizpůsobí průměru vaší současné trysky a odpovídající výšce vrstvy, takže je test přesný a dobře čitelný.\n" +"Měřítko vypněte pouze tehdy, chcete-li vytisknout referenční model přesně tak, jak je." + msgid "PA Calibration" msgstr "PA kalibrace" @@ -18988,6 +19046,14 @@ msgstr "Počáteční rychlost: " msgid "End speed: " msgstr "Konec rychlosti: " +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "Automaticky přizpůsobit maximální objemové rychlosti" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Pokud by koncová rychlost překročila maximální objemovou rychlost filamentu, automaticky snížit výšku vrstvy (se zachováním standardních hodnot a v rámci limitů stroje), aby jí bylo možné dosáhnout. Pokud nestačí ani minimální výška vrstvy, sníží se místo toho koncová rychlost." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -18999,6 +19065,57 @@ msgstr "" "krok >= 0\n" "konec > start + krok" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"Koncová rychlost (%.0f mm/s) překračuje maximální objemovou rychlost filamentu (%.1f mm³/s), která při této šířce čáry a výšce vrstvy omezuje vnější stěnu na přibližně %.0f mm/s.\n" +" Vyšší rychlosti budou oříznuty, takže horní bloky věže se nevytisknou požadovanou rychlostí.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"Koncová rychlost (%.0f mm/s) překračuje maximální objemovou rychlost filamentu (%.1f mm³/s) při výchozí výšce vrstvy (%.2f mm).\n" +"\n" +"Výška vrstvy byla snížena na %.2f mm (hodnota používaná profily této tiskárny), aby věž mohla dosáhnout požadované rychlosti." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"I při nejmenší výšce vrstvy používané profily této tiskárny (%.2f mm) koncová rychlost (%.0f mm/s) překračuje maximální objemovou rychlost filamentu (%.1f mm³/s).\n" +"\n" +"Výška vrstvy bude nastavena na %.2f mm a koncová rychlost snížena na %.0f mm/s.\n" +"\n" +"Pokračovat?" + +# AI Translated +msgid "Continue anyway?" +msgstr "Přesto pokračovat?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Zapnout „Automaticky přizpůsobit“ pro automatickou nápravu, nebo přesto pokračovat?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Zapnout „Automatické měřítko podle trysky“ a „Automaticky přizpůsobit“ pro automatickou nápravu, nebo přesto pokračovat?" + msgid "Start retraction length: " msgstr "Počáteční délka retrakce: " @@ -21756,6 +21873,9 @@ msgstr "" "Zamezte kroucení\n" "Víte, že při tisku materiálů náchylných ke kroucení, jako je ABS, může vhodné zvýšení teploty vyhřívané desky snížit pravděpodobnost kroucení?" +#~ msgid "Print order within a single layer." +#~ msgstr "Pořadí tisku v rámci jedné vrstvy." + #~ msgid "Bottom" #~ msgstr "Dole" @@ -21824,9 +21944,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Align infill direction to model" #~ msgstr "Zarovnat směr výplně podle modelu" diff --git a/localization/i18n/de/OrcaSlicer_de.po b/localization/i18n/de/OrcaSlicer_de.po index bf304e2e54..50384598e3 100644 --- a/localization/i18n/de/OrcaSlicer_de.po +++ b/localization/i18n/de/OrcaSlicer_de.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: \n" "Last-Translator: Heiko Liebscher \n" "Language-Team: \n" @@ -3804,6 +3804,10 @@ msgstr "Anordnen..." msgid "Arranging" msgstr "Anordnen" +# AI Translated +msgid "Arranging " +msgstr "Anordnen " + msgid "Arranging canceled." msgstr "Anordnen abgebrochen." @@ -8187,21 +8191,21 @@ msgstr "Verzeichnis um daraus zu ersetzen wurde nicht ausgewählt" msgid "Replaced with 3D files from directory:\n" msgstr "Ersetzt durch 3D-Dateien aus Verzeichnis:\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ Übersprungen %1%: gleiche Datei.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ Übersprungen %s: gleiche Datei.\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ Übersprungen %1%: Datei existiert nicht.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ Übersprungen %s: Datei existiert nicht.\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ Übersprungen %1%: Ersetzen fehlgeschlagen.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ Übersprungen %s: Ersetzen fehlgeschlagen.\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ Ersetzt %1%.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ Ersetzt %s.\n" msgid "Replaced volumes" msgstr "Ersetzte Volumen" @@ -9152,6 +9156,21 @@ msgstr "Untere Schichten abdunkeln" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "Beim Bewegen des Schichtreglers in der geslicten Vorschau werden die Schichten unterhalb der aktuellen abgedunkelt dargestellt, sodass nur die betrachtete Schicht in voller Helligkeit angezeigt wird." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Helligkeit abgedunkelter Schichten" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"Wie hell die abgedunkelten Schichten dargestellt werden, wenn \"Untere Schichten abdunkeln\" aktiviert ist.\n" +"99% ist kaum abgedunkelt, 0% stellt sie schwarz dar. Auf 99% begrenzt, da 100% dem Deaktivieren der Option entsprechen würde." + msgid "Login region" msgstr "Anmeldungsregion" @@ -13180,12 +13199,37 @@ msgstr "Nach Objekt" msgid "Intra-layer order" msgstr "Intra-Schicht-Reihenfolge" -msgid "Print order within a single layer." -msgstr "Druckreihenfolge innerhalb einer einzelnen Schicht" +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Reihenfolge, in der die Objektinstanzen innerhalb einer einzelnen Schicht angefahren werden. Sie bestimmt, wie viel Eilgang für die Bewegung zwischen ihnen aufgewendet wird.\n" +"\n" +"Standard: Verkettung nach dem nächsten Nachbarn, verfeinert mit 2-opt und Entfernen von Überkreuzungen. Eine gute allgemeine Wahl.\n" +"Als Objektliste: Die Instanzen werden in derselben Reihenfolge wie in der Objektliste gedruckt, ohne jede Pfadoptimierung. Verwenden Sie diese Option, wenn Sie eine vorhersehbare, manuell gesteuerte Reihenfolge benötigen.\n" +"Bestes Ergebnis (kürzester Weg): Alle Strategien werden ausgewertet und die kürzeste wird verwendet. Die Reihenfolge der Objektinstanzen wird einmal für den gesamten Druck festgelegt, während die Reihenfolge der einzelnen Inseln pro Schicht bestimmt wird, sodass verschiedene Schichten unterschiedliche Strategien verwenden können. Etwas langsameres Slicing.\n" +"Schlangenlinie: Zeilenweiser Mäanderverlauf, verfeinert mit 2-opt. Gut geeignet für regelmäßige Raster aus vielen kleinen Teilen.\n" +"\n" +"Bei mehreren Filamenten oder Werkzeugen in derselben Schicht hat das Minimieren der Werkzeugwechsel Vorrang: Objekte werden zuerst nach Filament gruppiert und diese Einstellung ordnet nur die Instanzen innerhalb jeder Filamentgruppe. Die Gesamtabfolge sieht daher möglicherweise nicht wie der kürzeste Weg über die Platte aus." msgid "As object list" msgstr "Als Objektliste" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "Bestes Ergebnis (kürzester Weg)" + +# AI Translated +msgid "Snake" +msgstr "Schlangenlinie" + msgid "Slow printing down for better layer cooling" msgstr "Verlangsamen Sie den Druck für eine bessere Schichtkühlung" @@ -18487,6 +18531,20 @@ msgstr "" "Es gibt mehrere IP-Adressen, die zu Hostname %1% auflösen.\n" "Bitte wählen Sie eine aus, die verwendet werden soll." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "Automatisch an Düse skalieren" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Dieses Modell ist für eine 0,4 mm Düse mit einer Schichthöhe von 0,2 mm ausgelegt. \n" +"Wenn die Skalierungsoption aktiviert ist (empfohlen), wird das Modell dynamisch an Ihren aktuellen Düsendurchmesser und eine passende Schichthöhe angepasst, sodass der Test sowohl genau als auch gut ablesbar ist.\n" +"Deaktivieren Sie die Skalierung nur, wenn Sie das Referenzmodell exakt so drucken möchten, wie es ist." + msgid "PA Calibration" msgstr "PA Kalibrierung" @@ -18623,6 +18681,14 @@ msgstr "Startgeschwindigkeit" msgid "End speed: " msgstr "Endgeschwindigkeit" +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "Automatisch an maximale Volumengeschwindigkeit anpassen" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Wenn die Endgeschwindigkeit die maximale Volumengeschwindigkeit des Filaments überschreiten würde, wird die Schichthöhe automatisch verringert (unter Beibehaltung üblicher Werte und innerhalb der Grenzen der Maschine), um sie zu erreichen. Reicht selbst die minimale Schichthöhe nicht aus, wird stattdessen die Endgeschwindigkeit gesenkt." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -18634,6 +18700,57 @@ msgstr "" "Schritt >= 0\n" "Ende > Start + Schritt" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"Die Endgeschwindigkeit (%.0f mm/s) überschreitet die maximale Volumengeschwindigkeit des Filaments (%.1f mm³/s), wodurch die Außenwand bei dieser Linienbreite und Schichthöhe auf etwa %.0f mm/s begrenzt wird.\n" +" Höhere Geschwindigkeiten werden begrenzt, sodass die oberen Blöcke des Turms nicht mit der gewünschten Geschwindigkeit gedruckt werden.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"Die Endgeschwindigkeit (%.0f mm/s) überschreitet die maximale Volumengeschwindigkeit des Filaments (%.1f mm³/s) bei der Standard-Schichthöhe (%.2f mm).\n" +"\n" +"Die Schichthöhe wurde auf %.2f mm verringert (ein Wert, der in den Profilen dieses Druckers verwendet wird), damit der Turm die gewünschte Geschwindigkeit erreichen kann." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Selbst bei der kleinsten Schichthöhe, die in den Profilen dieses Druckers verwendet wird (%.2f mm), überschreitet die Endgeschwindigkeit (%.0f mm/s) die maximale Volumengeschwindigkeit des Filaments (%.1f mm³/s).\n" +"\n" +"Die Schichthöhe wird auf %.2f mm gesetzt und die Endgeschwindigkeit auf %.0f mm/s verringert.\n" +"\n" +"Fortfahren?" + +# AI Translated +msgid "Continue anyway?" +msgstr "Trotzdem fortfahren?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "\"Automatisch anpassen\" aktivieren, um dies automatisch zu beheben, oder trotzdem fortfahren?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "\"Automatisch an Düse skalieren\" und \"Automatisch anpassen\" aktivieren, um dies automatisch zu beheben, oder trotzdem fortfahren?" + msgid "Start retraction length: " msgstr "Start Rückzugslänge" @@ -21169,6 +21286,9 @@ msgstr "" "Verwerfungen vermeiden\n" "Wussten Sie, dass beim Drucken von Materialien, die zu Verwerfungen neigen, wie z.B. ABS, durch eine entsprechende Erhöhung der Heizbetttemperatur die Wahrscheinlichkeit von Verwerfungen verringert werden kann?" +#~ msgid "Print order within a single layer." +#~ msgstr "Druckreihenfolge innerhalb einer einzelnen Schicht" + #~ msgid "Bottom" #~ msgstr "Unten" @@ -21261,9 +21381,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Renders cast shadows on the plate in realistic view." #~ msgstr "Zeigt geworfene Schatten auf der Platte in der realistischen Ansicht an." diff --git a/localization/i18n/en/OrcaSlicer_en.po b/localization/i18n/en/OrcaSlicer_en.po index 95d357b79b..232820f681 100644 --- a/localization/i18n/en/OrcaSlicer_en.po +++ b/localization/i18n/en/OrcaSlicer_en.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: 2026-06-17 15:44-0300\n" "Last-Translator: Alexandre Folle de Menezes\n" "Language-Team: \n" @@ -3604,6 +3604,9 @@ msgstr "" msgid "Arranging" msgstr "" +msgid "Arranging " +msgstr "" + msgid "Arranging canceled." msgstr "" @@ -7773,20 +7776,20 @@ msgstr "" msgid "Replaced with 3D files from directory:\n" msgstr "" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" msgstr "" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" msgstr "" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" msgstr "" -#, boost-format -msgid "✔ Replaced %1%.\n" +#, c-format +msgid "✔ Replaced %s.\n" msgstr "" msgid "Replaced volumes" @@ -8657,6 +8660,17 @@ msgstr "" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "" +msgid "Dimmed layer brightness" +msgstr "" + +msgid "%" +msgstr "" + +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" + msgid "Login region" msgstr "" @@ -12353,12 +12367,26 @@ msgstr "" msgid "Intra-layer order" msgstr "" -msgid "Print order within a single layer." +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." msgstr "" msgid "As object list" msgstr "" +msgid "Best of all (shortest path)" +msgstr "" + +msgid "Snake" +msgstr "" + msgid "Slow printing down for better layer cooling" msgstr "" @@ -17214,6 +17242,15 @@ msgid "" "Please select one that should be used." msgstr "" +msgid "Auto-scale for nozzle" +msgstr "" + +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" + msgid "PA Calibration" msgstr "" @@ -17336,6 +17373,12 @@ msgstr "" msgid "End speed: " msgstr "" +msgid "Auto-adjust to max volumetric speed" +msgstr "" + +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "" + msgid "" "Please input valid values:\n" "start > 10\n" @@ -17343,6 +17386,39 @@ msgid "" "end > start + step" msgstr "" +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" + +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" + +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" + +msgid "Continue anyway?" +msgstr "" + +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "" + +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "" + msgid "Start retraction length: " msgstr "" diff --git a/localization/i18n/es/OrcaSlicer_es.po b/localization/i18n/es/OrcaSlicer_es.po index 8bf5a56421..1913c4512a 100644 --- a/localization/i18n/es/OrcaSlicer_es.po +++ b/localization/i18n/es/OrcaSlicer_es.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: \n" "Last-Translator: Ian A. Bassi <>\n" "Language-Team: \n" @@ -3686,6 +3686,10 @@ msgstr "Organizando..." msgid "Arranging" msgstr "Organizando" +# AI Translated +msgid "Arranging " +msgstr "Organizando " + msgid "Arranging canceled." msgstr "Organización cancelada." @@ -7993,21 +7997,21 @@ msgstr "No se seleccionó el directorio para el reemplazo" msgid "Replaced with 3D files from directory:\n" msgstr "Reemplazado con archivos 3D desde el directorio:\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ Omitido %1%: mismo archivo.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ Omitido %s: mismo archivo.\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ Omitido %1%: el archivo no existe.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ Omitido %s: el archivo no existe.\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ Omitido %1%: fallo al reemplazar.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ Omitido %s: fallo al reemplazar.\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ Reemplazado %1%.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ Reemplazado %s.\n" msgid "Replaced volumes" msgstr "Volúmenes reemplazados" @@ -8931,6 +8935,21 @@ msgstr "Atenuar las capas inferiores" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "Al desplazar el control deslizante de capas en la vista previa laminada, oscurece las capas inferiores a la actual para que solo la capa visualizada se muestre a pleno brillo." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Brillo de las capas atenuadas" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"Con qué brillo se muestran las capas atenuadas cuando \"Atenuar las capas inferiores\" está activado.\n" +"99% apenas se oscurece y 0% las muestra en negro. Está limitado al 99% porque el 100% equivaldría a desactivar la opción." + msgid "Login region" msgstr "Región de inicio de sesión" @@ -12881,12 +12900,37 @@ msgstr "Por objeto" msgid "Intra-layer order" msgstr "Orden dentro de la capa" -msgid "Print order within a single layer." -msgstr "Orden de impresión dentro de cada capa." +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Orden en el que se recorren las instancias de objeto dentro de una misma capa, lo que determina cuánto desplazamiento se emplea para moverse entre ellas.\n" +"\n" +"Por defecto: encadenado por vecino más cercano, refinado con 2-opt y eliminación de cruces. Una buena opción general.\n" +"Como lista de objetos: las instancias se imprimen en el mismo orden que la lista de objetos, sin ninguna optimización de trayectoria. Úselo cuando necesite un orden predecible y controlado manualmente.\n" +"La mejor de todas (trayectoria más corta): se evalúan todas las estrategias y se utiliza la más corta. El orden de las instancias de objeto se decide una sola vez para toda la impresión, mientras que el orden de las islas individuales se decide capa por capa, por lo que distintas capas pueden acabar usando estrategias diferentes. El laminado es algo más lento.\n" +"Serpentina: recorrido serpenteante fila por fila, refinado con 2-opt. Muy adecuado para rejillas regulares de muchas piezas pequeñas.\n" +"\n" +"Con varios filamentos o herramientas en la misma capa, minimizar los cambios de herramienta tiene prioridad: los objetos se agrupan primero por filamento y este ajuste solo ordena las instancias dentro de cada grupo de filamento, por lo que la secuencia global puede no parecer la trayectoria más corta a lo largo de la cama." msgid "As object list" msgstr "Como lista de objetos" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "La mejor de todas (trayectoria más corta)" + +# AI Translated +msgid "Snake" +msgstr "Serpentina" + msgid "Slow printing down for better layer cooling" msgstr "Reducir la velocidad de impresión para mejorar la refrigeración de las capas" @@ -18122,6 +18166,20 @@ msgstr "" "Hay varias direcciones IP resueltas del nombre del host %1%.\n" "Por favor, seleccione la que debe usarse." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "Escalar automáticamente para la boquilla" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Este modelo está diseñado para una boquilla de 0,4 mm con una altura de la capa de 0,2 mm. \n" +"Cuando la opción de escalado está activada (recomendado), el modelo se redimensiona dinámicamente para adaptarse al diámetro de boquilla actual y a una altura de capa adecuada, lo que hace que la prueba sea precisa y fácil de leer.\n" +"Desactive el escalado solo si desea imprimir el modelo de referencia exactamente tal cual." + msgid "PA Calibration" msgstr "Calibración PA" @@ -18258,6 +18316,14 @@ msgstr "Velocidad inicial: " msgid "End speed: " msgstr "Velocidad final: " +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "Ajustar automáticamente a la velocidad volumétrica máxima" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Si la velocidad final superara la velocidad volumétrica máxima del filamento, se reduce automáticamente la altura de la capa (manteniendo valores estándar y dentro de los límites de la máquina) para alcanzarla. Si ni siquiera la altura de capa mínima es suficiente, se reduce la velocidad final." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -18269,6 +18335,57 @@ msgstr "" "incremento >=0\n" "final > inicio + paso" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"La velocidad final (%.0f mm/s) supera la velocidad volumétrica máxima del filamento (%.1f mm³/s), lo que limita el perímetro externo a unos %.0f mm/s con este ancho de línea y esta altura de capa.\n" +" Las velocidades superiores se recortarán, por lo que los bloques superiores de la torre no se imprimirán a la velocidad solicitada.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"La velocidad final (%.0f mm/s) supera la velocidad volumétrica máxima del filamento (%.1f mm³/s) con la altura de capa predeterminada (%.2f mm).\n" +"\n" +"La altura de la capa se ha reducido a %.2f mm (un valor usado por los perfiles de esta impresora) para que la torre pueda alcanzar la velocidad solicitada." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Incluso con la altura de capa más pequeña usada por los perfiles de esta impresora (%.2f mm), la velocidad final (%.0f mm/s) supera la velocidad volumétrica máxima del filamento (%.1f mm³/s).\n" +"\n" +"La altura de la capa se establecerá en %.2f mm y la velocidad final se reducirá a %.0f mm/s.\n" +"\n" +"¿Continuar?" + +# AI Translated +msgid "Continue anyway?" +msgstr "¿Continuar de todos modos?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "¿Activar \"Ajuste automático\" para corregir esto automáticamente o continuar de todos modos?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "¿Activar \"Escalar automáticamente para la boquilla\" y \"Ajuste automático\" para corregir esto automáticamente o continuar de todos modos?" + msgid "Start retraction length: " msgstr "Longitud de retracción inicial: " @@ -20744,6 +20861,9 @@ msgstr "" "Evita la deformación\n" "¿Sabías que al imprimir materiales propensos a la deformación como el ABS, aumentar adecuadamente la temperatura de la cama térmica puede reducir la probabilidad de deformaciones?" +#~ msgid "Print order within a single layer." +#~ msgstr "Orden de impresión dentro de cada capa." + #~ msgid "Bottom" #~ msgstr "Inferior" @@ -20837,9 +20957,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Anisotropic surfaces" #~ msgstr "Superficies anisótropas" diff --git a/localization/i18n/eu/OrcaSlicer_eu.po b/localization/i18n/eu/OrcaSlicer_eu.po index ccad5d6d47..fa10cc387f 100644 --- a/localization/i18n/eu/OrcaSlicer_eu.po +++ b/localization/i18n/eu/OrcaSlicer_eu.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: 2026-07-20 13:33+0200\n" "Last-Translator: Manu Goiogana \n" "Language-Team: \n" @@ -3724,6 +3724,10 @@ msgstr "Antolatzen..." msgid "Arranging" msgstr "Antolaketa" +# AI Translated +msgid "Arranging " +msgstr "Antolatzen " + msgid "Arranging canceled." msgstr "Antolaketa bertan behera utzi da." @@ -8060,21 +8064,21 @@ msgstr "Ez da ordezkatzeko direktoriorik hautatu" msgid "Replaced with 3D files from directory:\n" msgstr "Direktorio honetako 3D fitxategiekin ordeztuta:\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ %1% saltatu da: fitxategi bera.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ %s saltatu da: fitxategi bera.\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ %1% saltatu da: fitxategia ez da existitzen.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ %s saltatu da: fitxategia ez da existitzen.\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ %1% saltatu da: ezin izan da ordeztu.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ %s saltatu da: ezin izan da ordeztu.\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ %1% ordezkatu da.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ %s ordezkatu da.\n" msgid "Replaced volumes" msgstr "Ordeztutako bolumenak" @@ -8999,6 +9003,21 @@ msgstr "Ilundu beheko geruzak" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "Xerratutako aurrebistan geruza-graduatzailea mugitzean, unekoaren azpiko geruzak ilunduta erakusten ditu, ikusten ari den geruza soilik distira osoz ager dadin." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Ilundutako geruzen distira" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"\"Ilundu beheko geruzak\" gaituta dagoenean ilundutako geruzak zein distiratsu marrazten diren.\n" +"%99 balioak ozta-ozta iluntzen ditu, %0 balioak beltz bihurtzen ditu. Gehienez %99 onartzen da, %100 balioak aukera desgaitzearen gauza bera egingo bailuke." + msgid "Login region" msgstr "Saio-hasierako eskualdea" @@ -11994,11 +12013,11 @@ msgstr "Purgatze-dorreak euskarriak objektuaren geruza-altuera bera izatea eskat # AI Translated msgid "For Organic supports, two walls are supported only with the Hollow/Default base pattern." -msgstr "Euskarri organikoetan, bi horma Hollow/Default oinarri-patroiarekin soilik onartzen dira." +msgstr "Euskarri organikoetan, bi horma Hutsa/Lehenetsia oinarri-patroiarekin soilik onartzen dira." # AI Translated msgid "The Lightning base pattern is not supported by this support type; Rectilinear will be used instead." -msgstr "Lightning oinarri-patroia ez du euskarri mota honek onartzen; Rectilinear erabiliko da horren ordez." +msgstr "Tximista oinarri-patroia ez du euskarri mota honek onartzen; Lerrozuzena erabiliko da horren ordez." msgid "Organic support tree tip diameter must not be smaller than support material extrusion width." msgstr "Euskarri organikoaren zuhaitz-muturraren diametroak ezin du izan euskarri-materialaren estrusio-zabalera baino txikiagoa." @@ -12011,7 +12030,7 @@ msgstr "Euskarri organikoaren adar-diametroak ezin du izan euskarri-zuhaitzaren # AI Translated msgid "The Hollow base pattern is not supported by this support type; Rectilinear will be used instead." -msgstr "Hollow oinarri-patroia ez du euskarri mota honek onartzen; Rectilinear erabiliko da horren ordez." +msgstr "Hutsa oinarri-patroia ez du euskarri mota honek onartzen; Lerrozuzena erabiliko da horren ordez." msgid "Support enforcers are used but support is not enabled. Please enable support." msgstr "Euskarri-behartzaileak erabiltzen dira, baina euskarria ez dago gaituta. Gaitu euskarriak." @@ -12992,12 +13011,37 @@ msgstr "Objektuka" msgid "Intra-layer order" msgstr "Geruza barruko ordena" -msgid "Print order within a single layer." -msgstr "Geruza bakarreko inprimatze-ordena." +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Geruza bakar baten barruan objektu-instantziak zein ordenatan bisitatzen diren; horrek zehazten du zenbat desplazamendu behar den haien artean mugitzeko.\n" +"\n" +"Lehenetsia: auzokide hurbilenaren araberako kateaketa, 2-opt bidez eta gurutzaketak kenduz findua. Aukera orokor ona.\n" +"Objektu-zerrenda bezala: instantziak objektu-zerrendaren ordena berean inprimatzen dira, ibilbidea batere optimizatu gabe. Erabili ordena aurreikusgarri eta eskuz kontrolatu bat behar duzunean.\n" +"Guztien onena (ibilbide laburrena): estrategia guztiak ebaluatzen dira eta laburrena erabiltzen da. Objektu-instantzien ordena behin erabakitzen da inprimaketa osorako, eta uharte bakoitzaren ordena geruzaz geruza erabakitzen da; beraz, geruza desberdinek estrategia desberdinak erabil ditzakete. Xerratzea apur bat motelagoa da.\n" +"Sigi-saga: errenkadaz errenkadako sigi-saga ibilbidea, 2-opt bidez findua. Oso egokia pieza txiki askoren sareta erregularretarako.\n" +"\n" +"Geruza berean filamentu edo tresna bat baino gehiago daudenean, tresna-aldaketak gutxitzeak du lehentasuna: objektuak filamentuaren arabera multzokatzen dira lehenik, eta ezarpen honek filamentu-multzo bakoitzaren barruko instantziak baino ez ditu ordenatzen; beraz, baliteke sekuentzia orokorrak plaka osoko ibilbide laburrenaren itxurarik ez izatea." msgid "As object list" msgstr "Objektu-zerrenda bezala" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "Guztien onena (ibilbide laburrena)" + +# AI Translated +msgid "Snake" +msgstr "Sigi-saga" + msgid "Slow printing down for better layer cooling" msgstr "Moteldu inprimaketa geruza hobeto hozteko" @@ -13208,7 +13252,7 @@ msgstr "Moderatua" # AI Translated msgid "Top surface pattern" -msgstr "Goiko gainazalaren patroia" +msgstr "Goiko gainazaleko patroia" # AI Translated msgid "This is the line pattern for top surface infill." @@ -13221,13 +13265,13 @@ msgid "Monotonic line" msgstr "Lerro monotonikoa" msgid "Rectilinear" -msgstr "Rectilinear" +msgstr "Lerrozuzena" msgid "Aligned Rectilinear" msgstr "Lerrozuzen lerrokatua" msgid "Concentric" -msgstr "Concentric" +msgstr "Kontzentrikoa" msgid "Hilbert Curve" msgstr "Hilbert kurba" @@ -13293,7 +13337,7 @@ msgstr "Kanporantz" # AI Translated msgid "Bottom surface pattern" -msgstr "Beheko gainazalaren patroia" +msgstr "Beheko gainazaleko patroia" # AI Translated msgid "This is the line pattern of bottom surface infill, not including bridge infill." @@ -13318,7 +13362,7 @@ msgid "" "Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n" "Default uses shortest-path ordering, which may run in either direction." msgstr "" -"Gaineko gainazalak betetzen diren noranzkoa zentroan oinarritutako patroia erabiltzen denean (Konzentrikoa, Arkimedeen Akordeak, Oktograma Espirala).\n" +"Goiko gainazalak betetzen diren noranzkoa zentroan oinarritutako patroia erabiltzen denean (Kontzentrikoa, Arkimedesen kordak, Oktagrama-kiribila).\n" "Kanporanzkoa erdialdean hasten da, beraz, gehiegizko materiala gutxien ikusten den ertzera bultzatzen da. Barruranzkoa ertzean hasten da eta erdian kurba estuekin amaitzen da.\n" "Lehenetsiak bide laburreneko ordena erabiltzen du, zeina norabide batean zein bestean ibil daitekeen." @@ -13331,7 +13375,7 @@ msgid "" "Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n" "Default uses shortest-path ordering, which may run in either direction." msgstr "" -"Beheko gainazalak betetzen diren noranzkoa zentroan oinarritutako patroia erabiltzen denean (Konzentrikoa, Arkimedeen Akordeak, Oktograma Espirala).\n" +"Beheko gainazalak betetzen diren noranzkoa zentroan oinarritutako patroia erabiltzen denean (Kontzentrikoa, Arkimedesen kordak, Oktagrama-kiribila).\n" "Barruranzkoa hasten da gainazal bakoitza kanpoko kurba zabalagoekin, eta horrek lehen geruzaren atxikimendua hobetzen du erdiko kurba estuak itsatsi ez daitezkeen inprimatze-plaketan. Kanporanzkoa erdialdean hasten da, gehiegizko materiala ertzera bultzatuz.\n" "Lehenetsiak bide laburreneko ordena erabiltzen du, zeina norabide batean zein bestean ibil daitekeen." @@ -16387,9 +16431,9 @@ msgid "" msgstr "" "Euskarriaren lerro-patroia.\n" "\n" -"Zuhaitz-euskarrien aukera lehenetsia Hutsa da, hau da, ez dago oinarri-patroirik. Beste euskarri motetarako, aukera lehenetsia patroi zuzenekoa da.\n" +"Zuhaitz-euskarrien aukera lehenetsia Hutsa da, hau da, ez dago oinarri-patroirik. Beste euskarri motetarako, aukera lehenetsia patroi lerrozuzena da.\n" "\n" -"OHARRA: Euskarri organikoetan, bi hormak Hutsa/Lehenetsia oinarri-patroiarekin bakarrik onartzen dira. Tximistetan oinarritutako patroia Zuhaitz mehea/Indartsua/Hibridoa euskarriek bakarrik onartzen dute. Beste euskarri motetarako, Zuzenekoa erabiliko da Tximistenaren ordez." +"OHARRA: Euskarri organikoetan, bi hormak Hutsa/Lehenetsia oinarri-patroiarekin bakarrik onartzen dira. Tximista oinarri-patroia Zuhaitz mehea/Indartsua/Hibridoa euskarriek bakarrik onartzen dute. Beste euskarri motetarako, Lerrozuzena erabiliko da Tximistaren ordez." msgid "Rectilinear grid" msgstr "Sare lerrozuzena" @@ -16669,7 +16713,7 @@ msgid "" " - Each Model: centers the pattern on each connected body. Parts that touch or overlap share one center; parts detached from the rest each get their own.\n" " - Each Assembly: uses a single shared center for the whole object or assembly." msgstr "" -"Goiko eta beheko gainazaleko patroi zentratuen (Arkimedesen kordak, Oktagrama-espirala) zentroa non kokatzen den aukeratzen du.\n" +"Goiko eta beheko gainazaleko patroi zentratuen (Arkimedesen kordak, Oktagrama-kiribila) zentroa non kokatzen den aukeratzen du.\n" " - Gainazal bakoitza: patroia gainazal-eskualde bakoitzean zentratzen du, uharte bakoitza bere kabuz simetrikoa izan dadin.\n" " - Modelo bakoitza: patroia konektatutako gorputz bakoitzean zentratzen du. Elkar ukitzen edo gainjartzen diren piezek zentro bera partekatzen dute; gainerakoetatik bereizitako piezek beren zentroa dute.\n" " - Muntaketa bakoitza: zentro partekatu bakarra erabiltzen du objektu edo muntaketa osorako." @@ -17100,7 +17144,7 @@ msgid "Detect narrow internal solid infills" msgstr "Detektatu barruko betegarri solido estua" msgid "This option will auto-detect narrow internal solid infill areas. If enabled, the concentric pattern will be used for the area to speed up printing. Otherwise, the rectilinear pattern will be used by default." -msgstr "Aukera honek barruko betegarri solido estuko eremuak automatikoki detektatuko ditu. Gaituta badago, eremu horretan patroi zentrokidea erabiliko da inprimaketa azkartzeko. Bestela, patroi lerrozuzena erabiliko da lehenespenez." +msgstr "Aukera honek barruko betegarri solido estuko eremuak automatikoki detektatuko ditu. Gaituta badago, eremu horretan patroi kontzentrikoa erabiliko da inprimaketa azkartzeko. Bestela, patroi lerrozuzena erabiliko da lehenespenez." msgid "invalid value " msgstr "balio baliogabea " @@ -18269,6 +18313,20 @@ msgstr "" "Hainbat IP helbide ebazten dira %1% ostalari-izenerako.\n" "Hautatu erabili beharrekoa." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "Eskalatze automatikoa pitarako" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Modelo hau 0,4 mm-ko pita eta 0,2 mm-ko geruza-altuera kontuan hartuta diseinatu da. \n" +"Eskalatze-aukera gaituta dagoenean (gomendatua), tamaina dinamikoki egokitzen zaie zure uneko pita-diametroari eta geruza-altuera egoki bati, testa zehatza eta irakurterraza izan dadin.\n" +"Itzali eskalatzea erreferentzia-modeloa dagoen-dagoenean inprimatu nahi baduzu bakarrik." + msgid "PA Calibration" msgstr "PA kalibrazioa" @@ -18406,6 +18464,14 @@ msgstr "Hasierako abiadura: " msgid "End speed: " msgstr "Amaierako abiadura: " +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "Doikuntza automatikoa abiadura bolumetriko maximora" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Amaierako abiadurak filamentuaren abiadura bolumetriko maximoa gaindituko balu, geruza-altuera automatikoki jaisten da (balio estandarrak mantenduz eta makinaren mugen barruan) hura lortzeko. Gutxieneko geruza-altuerarekin ere nahikoa ez bada, amaierako abiadura jaisten da haren ordez." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -18417,6 +18483,57 @@ msgstr "" "urratsa >= 0\n" "amaiera > hasiera + urratsa" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"Amaierako abiadurak (%.0f mm/s) filamentuaren abiadura bolumetriko maximoa (%.1f mm³/s) gainditzen du, eta horrek kanpoko horma gutxi gorabehera %.0f mm/s-ra mugatzen du lerro-zabalera eta geruza-altuera honekin.\n" +" Horren gaineko abiadurak mugatu egingo dira, beraz dorrearen goiko blokeak ez dira eskatutako abiaduran inprimatuko.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"Amaierako abiadurak (%.0f mm/s) filamentuaren abiadura bolumetriko maximoa (%.1f mm³/s) gainditzen du geruza-altuera lehenetsian (%.2f mm).\n" +"\n" +"Geruza-altuera %.2f mm-ra jaitsi da (inprimagailu honen aurrezarpenek erabiltzen duten balio bat), dorreak eskatutako abiadura lor dezan." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Inprimagailu honen aurrezarpenek erabiltzen duten geruza-altuera txikienarekin ere (%.2f mm), amaierako abiadurak (%.0f mm/s) filamentuaren abiadura bolumetriko maximoa (%.1f mm³/s) gainditzen du.\n" +"\n" +"Geruza-altuera %.2f mm-ra ezarriko da eta amaierako abiadura %.0f mm/s-ra jaitsiko da.\n" +"\n" +"Jarraitu?" + +# AI Translated +msgid "Continue anyway?" +msgstr "Hala ere jarraitu?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Gaitu \"Doikuntza automatikoa\" hau automatikoki konpontzeko, edo hala ere jarraitu?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Gaitu \"Eskalatze automatikoa pitarako\" eta \"Doikuntza automatikoa\" hau automatikoki konpontzeko, edo hala ere jarraitu?" + msgid "Start retraction length: " msgstr "Hasierako atzera-egite luzera: " @@ -18586,7 +18703,7 @@ msgstr "YOLO (perfekzionista)" # AI Translated msgid "Top Surface Pattern" -msgstr "Goiko gainazalaren patroia" +msgstr "Goiko gainazaleko patroia" msgid "Choose a slot for the selected color" msgstr "Aukeratu zirrikitu bat hautatutako kolorearentzat" @@ -20899,6 +21016,9 @@ msgstr "" "Saihestu okertzea\n" "Ba al zenekien ABS bezalako okertzeko joera duten materialak inprimatzean ohe beroaren tenperatura egoki igotzeak okertzeko probabilitatea murriztu dezakeela?" +#~ msgid "Print order within a single layer." +#~ msgstr "Geruza bakarreko inprimatze-ordena." + #~ msgid "Bottom" #~ msgstr "Behekoa" @@ -21028,9 +21148,6 @@ msgstr "" #~ msgid "°" #~ msgstr "°" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "uniform scale" #~ msgstr "eskala uniformea" diff --git a/localization/i18n/fr/OrcaSlicer_fr.po b/localization/i18n/fr/OrcaSlicer_fr.po index 6357703b45..1257994f16 100644 --- a/localization/i18n/fr/OrcaSlicer_fr.po +++ b/localization/i18n/fr/OrcaSlicer_fr.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: Guislain Cyril, Thomas Lété\n" @@ -3760,6 +3760,10 @@ msgstr "Agencement…" msgid "Arranging" msgstr "Agencement" +# AI Translated +msgid "Arranging " +msgstr "Agencement " + msgid "Arranging canceled." msgstr "Agencement annulé." @@ -8116,21 +8120,21 @@ msgstr "Le répertoire pour le remplacement n'a pas été sélectionné" msgid "Replaced with 3D files from directory:\n" msgstr "Remplacé par des fichiers 3D depuis le répertoire :\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ Ignoré %1% : même fichier.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ Ignoré %s : même fichier.\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ Ignoré %1% : le fichier n'existe pas.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ Ignoré %s : le fichier n'existe pas.\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ Ignoré %1% : échec du remplacement.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ Ignoré %s : échec du remplacement.\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ Remplacé %1%.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ Remplacé %s.\n" msgid "Replaced volumes" msgstr "Volumes remplacés" @@ -9068,6 +9072,21 @@ msgstr "Assombrir les couches inférieures" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "Lors du défilement du curseur de couche dans l'aperçu découpé, affiche les couches situées sous la couche actuelle assombries, de sorte que seule la couche visualisée soit affichée en pleine luminosité." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Luminosité des couches assombries" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"Luminosité de rendu des couches assombries lorsque « Assombrir les couches inférieures » est activé.\n" +"99% correspond à un assombrissement à peine perceptible, 0% les affiche en noir. Limité à 99% car 100% reviendrait à désactiver l’option." + msgid "Login region" msgstr "Région d'origine" @@ -9264,22 +9283,22 @@ msgid "DEV host: api-dev.bambu-lab.com/v1" msgstr "Hôte DEV : api-dev.bambu-lab.com/v1" msgid "QA host: api-qa.bambu-lab.com/v1" -msgstr "Hôte AQ : api-qa.bambu-lab.com/v1" +msgstr "Hôte QA : api-qa.bambu-lab.com/v1" msgid "PRE host: api-pre.bambu-lab.com/v1" -msgstr "Hébergeur PRE : api-pre.bambu-lab.com/v1" +msgstr "Hôte PRE : api-pre.bambu-lab.com/v1" msgid "Product host" msgstr "Hôte du produit" msgid "Debug save button" -msgstr "bouton d'enregistrement de débogage" +msgstr "Bouton d'enregistrement de debugage" msgid "Save debug settings" -msgstr "enregistrer les paramètres de débogage" +msgstr "Enregistrer les paramètres de debugage" msgid "Debug settings have been saved successfully!" -msgstr "Les paramètres DEBUG ont été enregistrés avec succès !" +msgstr "Les paramètres de debug ont été enregistrés avec succès !" msgid "Cloud environment switched; please login again!" msgstr "L'environnement Cloud a changé, veuillez vous reconnecter !" @@ -13087,12 +13106,37 @@ msgstr "Par objet" msgid "Intra-layer order" msgstr "Ordre intra-couche" -msgid "Print order within a single layer." -msgstr "Ordre d’impression au sein d’une même couche" +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Ordre dans lequel les instances d’objets sont parcourues au sein d’une même couche, ce qui détermine la quantité de déplacements effectués entre elles.\n" +"\n" +"Par défaut : chaînage par plus proche voisin, affiné par 2-opt et suppression des croisements. Un bon choix général.\n" +"En tant que liste d’objets : les instances sont imprimées dans le même ordre que la liste d’objets, sans aucune optimisation de trajet. À utiliser lorsque vous avez besoin d’un ordre prévisible et contrôlé manuellement.\n" +"Meilleur de tous (trajet le plus court) : toutes les stratégies sont évaluées et la plus courte est retenue. L’ordre des instances d’objets est déterminé une seule fois pour toute l’impression, tandis que l’ordre des îlots individuels est déterminé couche par couche ; différentes couches peuvent donc utiliser des stratégies différentes. Découpage légèrement plus lent.\n" +"Serpentin : parcours en serpentin, rangée par rangée, affiné par 2-opt. Bien adapté aux grilles régulières de nombreuses petites pièces.\n" +"\n" +"Avec plusieurs filaments ou outils dans la même couche, la réduction des changements d’outil est prioritaire : les objets sont d’abord regroupés par filament et ce réglage n’ordonne que les instances au sein de chaque groupe de filament ; la séquence globale peut donc ne pas ressembler au trajet le plus court sur la plaque." msgid "As object list" msgstr "En tant que liste d’objets" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "Meilleur de tous (trajet le plus court)" + +# AI Translated +msgid "Snake" +msgstr "Serpentin" + msgid "Slow printing down for better layer cooling" msgstr "Impression lente pour un meilleur refroidissement des couches" @@ -18381,6 +18425,20 @@ msgstr "" "Il existe plusieurs adresses IP résolues par le nom d’hôte %1%.\n" "Veuillez en sélectionner une qui doit être utilisée." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "Mise à l’échelle automatique selon la buse" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Ce modèle est conçu pour une buse de 0,4 mm avec une hauteur de couche de 0,2 mm. \n" +"Lorsque l’option de mise à l’échelle est activée (recommandé), il est redimensionné dynamiquement pour correspondre au diamètre de buse actuel et à une hauteur de couche appropriée, ce qui rend le test à la fois précis et facile à lire.\n" +"Ne désactivez la mise à l’échelle que si vous souhaitez imprimer le modèle de référence exactement tel quel." + msgid "PA Calibration" msgstr "Calibration Pressure Advance" @@ -18517,6 +18575,14 @@ msgstr "Vitesse de début: " msgid "End speed: " msgstr "Vitesse de fin: " +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "Ajustement automatique à la vitesse volumétrique maximale" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Si la vitesse finale devait dépasser la vitesse volumétrique maximale du filament, la hauteur de couche est automatiquement réduite (en conservant des valeurs standard et en restant dans les limites de la machine) pour l’atteindre. Si même la hauteur de couche minimale ne suffit pas, c’est la vitesse finale qui est réduite." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -18528,6 +18594,57 @@ msgstr "" "intervalles >= 0\n" "Fin > Début + Intervalle" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"La vitesse finale (%.0f mm/s) dépasse la vitesse volumétrique maximale du filament (%.1f mm³/s), ce qui limite la paroi extérieure à environ %.0f mm/s pour cette largeur de ligne et cette hauteur de couche.\n" +" Les vitesses supérieures seront bridées : les blocs supérieurs de la tour ne seront donc pas imprimés à la vitesse demandée.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"La vitesse finale (%.0f mm/s) dépasse la vitesse volumétrique maximale du filament (%.1f mm³/s) avec la hauteur de couche par défaut (%.2f mm).\n" +"\n" +"La hauteur de couche a été réduite à %.2f mm (une valeur utilisée par les profils de cette imprimante) afin que la tour puisse atteindre la vitesse demandée." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Même avec la plus petite hauteur de couche utilisée par les profils de cette imprimante (%.2f mm), la vitesse finale (%.0f mm/s) dépasse la vitesse volumétrique maximale du filament (%.1f mm³/s).\n" +"\n" +"La hauteur de couche sera réglée sur %.2f mm et la vitesse finale abaissée à %.0f mm/s.\n" +"\n" +"Continuer ?" + +# AI Translated +msgid "Continue anyway?" +msgstr "Continuer quand même ?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Activer « Ajustement automatique » pour corriger cela automatiquement, ou continuer quand même ?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Activer « Mise à l’échelle automatique selon la buse » et « Ajustement automatique » pour corriger cela automatiquement, ou continuer quand même ?" + msgid "Start retraction length: " msgstr "Longueur de rétraction de début: " @@ -21059,6 +21176,9 @@ msgstr "" "Éviter la déformation\n" "Saviez-vous que lors de l’impression de matériaux susceptibles de se déformer, tels que l’ABS, une augmentation appropriée de la température du plateau chauffant peut réduire la probabilité de déformation?" +#~ msgid "Print order within a single layer." +#~ msgstr "Ordre d’impression au sein d’une même couche" + #~ msgid "Bottom" #~ msgstr "Dessous" @@ -21149,9 +21269,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Renders cast shadows on the plate in realistic view." #~ msgstr "Affiche les ombres portées sur la plaque dans la vue réaliste." diff --git a/localization/i18n/hu/OrcaSlicer_hu.po b/localization/i18n/hu/OrcaSlicer_hu.po index 0491f17882..98cd987512 100644 --- a/localization/i18n/hu/OrcaSlicer_hu.po +++ b/localization/i18n/hu/OrcaSlicer_hu.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "Language: hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -300,13 +300,13 @@ msgid "Tungsten Carbide" msgstr "Volfrám-karbid" msgid "The toolhead and hotend rack may move. Please keep your hands away from the chamber." -msgstr "Előfordulhat, hogy a szerszámfej és a hotendtartó megmozdul. Kérjük, ne nyúlj a kamrába." +msgstr "Előfordulhat, hogy a szerszámfej és a fejegységtartó megmozdul. Kérlek, ne nyúlj a kamrába." msgid "Warning" msgstr "Figyelmeztetés" msgid "Hotend information may be inaccurate. Would you like to re-read the hotend? (Hotend information may change during power-off)." -msgstr "A hotendinformációk pontatlanok lehetnek. Szeretnéd újra beolvasni a hotendet? (A hotendinformáció kikapcsolt állapotban megváltozhat)." +msgstr "A fejegység adatai pontatlanok lehetnek. Szeretnéd újra beolvasni a fejegységet? (A fejegység adatai kikapcsolt állapotban megváltozhatnak.)" msgid "I confirm all" msgstr "Összes megerősítése" @@ -315,10 +315,10 @@ msgid "Re-read all" msgstr "Összes újraolvasása" msgid "Reading the hotends, please wait." -msgstr "A hotendek beolvasása folyamatban van, kérjük várj." +msgstr "A fejegységek beolvasása folyamatban van, kérlek, várj." msgid "During the hotend upgrade, the toolhead will move. Don't reach into the chamber." -msgstr "A hotend felismerése során a szerszámfej mozogni fog. Ne nyúlj be a kamrába." +msgstr "A fejegység felismerése közben a szerszámfej mozogni fog. Ne nyúlj be a kamrába." # AI Translated msgid "Update" @@ -370,10 +370,10 @@ msgid "Error" msgstr "Hiba" msgid "Induction Hotend Rack" -msgstr "Indukciós hotendtartó" +msgstr "Indukciós fejegységtartó" msgid "Hotends Info" -msgstr "Hotendek adatai" +msgstr "Fejegységek adatai" msgid "Read All" msgstr "Összes beolvasása" @@ -382,7 +382,7 @@ msgid "Reading " msgstr "Beolvasás " msgid "Please wait" -msgstr "Kérjük, várj" +msgstr "Kérlek, várj" # AI Translated msgid "Reading" @@ -395,10 +395,10 @@ msgid "Raised" msgstr "Felemelve" msgid "The hotend is in an abnormal state and currently unavailable. Please go to 'Device -> Upgrade' to upgrade firmware." -msgstr "A hotend állapota rendellenes, és jelenleg nem elérhető. Kérjük, lépj az „Eszköz -> Frissítés“ oldalra a firmware frissítéséhez." +msgstr "A fejegység állapota rendellenes és jelenleg nem elérhető. Kérlek, lépj az „Eszköz -> Frissítés“ oldalra a firmware frissítéséhez." msgid "Abnormal Hotend" -msgstr "Rendellenes hotend" +msgstr "Rendellenes fejegység" msgid "Cancel" msgstr "Mégse" @@ -413,7 +413,7 @@ msgid "Refreshing" msgstr "Frissítés" msgid "Hotend status abnormal, unavailable at present. Please upgrade the firmware and try again." -msgstr "A hotend állapota nem megfelelő, jelenleg nem kérdezhető le. Frissítsd a firmware-t, és próbáld újra." +msgstr "A fejegység állapota rendellenes, ezért jelenleg nem használható. Frissítsd a firmware-t, majd próbáld újra." # AI Translated msgid "SN" @@ -427,10 +427,10 @@ msgid "Used Time: %s" msgstr "Felhasznált idő: %s" msgid "Dynamic nozzles are allocated on the current plate. Picking hotend is not supported." -msgstr "A dinamikus fúvókák a jelenlegi tálcához vannak kiosztva. A hotend kiválasztása nem támogatott." +msgstr "A dinamikus fúvókák a jelenlegi tálcához vannak kiosztva. A fejegység kiválasztása nem támogatott." msgid "Hotend Rack" -msgstr "Hotendtartó" +msgstr "Fejegységtartó" msgid "ToolHead" msgstr "Szerszámfej" @@ -542,7 +542,7 @@ msgid "Paint-on supports editing" msgstr "Festett támaszok szerkesztése" msgid "Gizmo-Place on Face" -msgstr "Gizmo-Felület Tárgyasztalra Illesztése" +msgstr "Gizmo – felület asztalra illesztése" msgid "Lay on Face" msgstr "Felületre fektetés" @@ -633,22 +633,22 @@ msgid "Color painting editing" msgstr "Színfestés szerkesztése" msgid "Paint-on fuzzy skin" -msgstr "Festett bolyhos felület" +msgstr "Festett barázdált felület" msgid "Add fuzzy skin" -msgstr "Bolyhos felület hozzáadása" +msgstr "Barázdált felület hozzáadása" msgid "Remove fuzzy skin" -msgstr "Bolyhos felület eltávolítása" +msgstr "Barázdált felület eltávolítása" msgid "Reset selection" msgstr "Kijelölés visszaállítása" msgid "Warning: Fuzzy skin is disabled, painted fuzzy skin will not take effect!" -msgstr "Figyelmeztetés: a bolyhos felület ki van kapcsolva, ezért a festett bolyhos felület nem lesz érvényes!" +msgstr "Figyelmeztetés: a barázdált felület ki van kapcsolva, ezért a festett barázdált felület nem lesz érvényes!" msgid "Enable painted fuzzy skin for this object" -msgstr "Festett bolyhos felület engedélyezése ennél az objektumnál" +msgstr "Festett barázdált felület engedélyezése ennél az objektumnál" # AI Translated msgid "Entering Paint-on fuzzy skin" @@ -678,7 +678,7 @@ msgid "Gizmo-Rotate" msgstr "Gizmo-Forgatás" msgid "Optimize orientation" -msgstr "Orientáció optimalizálása" +msgstr "Tájolás optimalizálása" msgctxt "Verb" msgid "Scale" @@ -738,7 +738,7 @@ msgid "Group operations" msgstr "Csoportos műveletek" msgid "Set orientation" -msgstr "Orientáció beállítása" +msgstr "Tájolás beállítása" msgid "Set scale" msgstr "Méretarány beállítása" @@ -799,7 +799,7 @@ msgid "Auto" msgstr "Automatikus" msgid "Manual" -msgstr "Manuális" +msgstr "Kézi" msgid "Plug" msgstr "Dugó" @@ -1092,7 +1092,7 @@ msgstr "Csökkentési arány" #, boost-format msgid "Processing model '%1%' with more than 1M triangles could be slow. It is highly recommended to simplify the model." -msgstr "A több mint 1M háromszöget tartalmazó '%1%' modell feldolgozása lehet, hogy lassú lesz. Erősen ajánlott a modell leegyszerűsítése." +msgstr "A(z) '%1%' modell több mint 1 millió háromszöget tartalmaz, ezért a feldolgozása lassú lehet. Erősen ajánlott egyszerűsíteni a modellt." msgid "Simplify model" msgstr "Modell egyszerűsítése" @@ -1700,8 +1700,8 @@ msgid "" "Do NOT save local path to 3MF file.\n" "Also disables 'reload from disk' option." msgstr "" -"NE mentse a helyi elérési utat a 3MF fájlba.\n" -"Ezzel az \"újratöltés lemezről\" opció is letiltásra kerül." +"Nem menti a helyi elérési utat a 3MF-fájlba.\n" +"Az „Újratöltés lemezről” lehetőséget is kikapcsolja." #. TRN: An menu option to convert the SVG into an unmodifiable model part. msgid "Bake" @@ -1835,7 +1835,7 @@ msgid "Measure" msgstr "Mérés" msgid "Please confirm explosion ratio = 1, and please select at least one object." -msgstr "Erősítsd meg, hogy az explosion ratio = 1, és válassz ki legalább egy objektumot." +msgstr "Állítsd 1-re a széthúzás mértékét, majd válassz ki legalább egy objektumot." msgid "Edit to scale" msgstr "Méretre szerkesztés" @@ -1941,7 +1941,7 @@ msgid "Assemble" msgstr "Összeállítás" msgid "Please confirm explosion ratio = 1 and select at least two volumes." -msgstr "Erősítsd meg, hogy a terjedési arány = 1, és válassz ki legalább két térfogatot." +msgstr "Állítsd 1-re a széthúzás mértékét, majd válassz ki legalább két térfogatot." msgid "Please select at least two volumes." msgstr "Válassz ki legalább két térfogatot." @@ -2101,9 +2101,9 @@ msgid "" msgstr "" "A 2.4.0-s verziótól kezdve az OrcaSlicer a felhasználói profilokat a Bambu Cloud helyett az Orca Cloudon keresztül szinkronizálja.\n" "\n" -"Meglévő profiljai átviteléhez jelentkezzen be az Orca Cloudba, és azok automatikusan átkerülnek. Ha többet szeretne megtudni arról, hogyan tárolja és szinkronizálja az OrcaSlicer a profiljait, vagy ha kézzel szeretné átvinni a beállításait, tekintse meg a wikinket.\n" +"A meglévő profiljaid átviteléhez jelentkezz be az Orca Cloudba, és a rendszer automatikusan átviszi őket. Ha többet szeretnél megtudni arról, hogyan tárolja és szinkronizálja az OrcaSlicer a profiljaidat, vagy hogyan viheted át kézzel a beállításaidat, nézd meg a wikinket.\n" "\n" -"Ha nem használta a Bambu Cloudot a profilok szinkronizálásához, ez a változás nem érinti Önt, és nyugodtan figyelmen kívül hagyhatja ezt az üzenetet." +"Ha nem használtad a Bambu Cloudot a profilok szinkronizálásához, ez a változás nem érint, és nyugodtan figyelmen kívül hagyhatod ezt az üzenetet." # AI Translated msgid "Profile syncing change" @@ -2150,7 +2150,7 @@ msgid "" msgstr "" "A Microsoft WebView2 Runtime telepítése nem sikerült.\n" "Egyes funkciók, köztük a beállítási varázsló, üresen jelenhetnek meg a telepítéséig.\n" -"Kérlek, telepítsd kézzel innen: https://developer.microsoft.com/microsoft-edge/webview2/ , majd indítsd újra az Orca Slicert." +"Kérlek, telepítsd kézzel innen: https://developer.microsoft.com/microsoft-edge/webview2/, majd indítsd újra az Orca Slicert." #, c-format, boost-format msgid "Resources path does not exist or is not a directory: %s" @@ -2172,7 +2172,7 @@ msgid "Click to download new version in default browser: %s" msgstr "Kattints az új verzió letöltéséhez az alapértelmezett böngészőben: %s" msgid "OrcaSlicer needs an update" -msgstr "A Orca Slicert frissíteni kell" +msgstr "Az OrcaSlicert frissíteni kell" msgid "This is the newest version." msgstr "Ez a legújabb verzió." @@ -2271,7 +2271,7 @@ msgid "Open Project" msgstr "Projekt megnyitása" msgid "The version of Orca Slicer is too low and needs to be updated to the latest version before it can be used normally." -msgstr "A Orca Slicer ezen verziója túl régi és a legfrissebb verzióra kell frissíteni, mielőtt rendesen használható lenne" +msgstr "Az Orca Slicer ezen verziója túl régi. A megfelelő működéshez frissítsd a legújabb verzióra." # AI Translated msgid "Cloud sync conflict:" @@ -2391,7 +2391,7 @@ msgstr "Adatvédelmi szabályzat frissítése" #, c-format, boost-format msgid "your Orca Cloud profile (user ID: \"%s\")" -msgstr "a Orca Cloud-profilod (felhasználói azonosító: \"%s\")" +msgstr "az Orca Cloud-profilod (felhasználói azonosító: \"%s\")" msgid "your default profile" msgstr "az alapértelmezett profilod" @@ -2406,9 +2406,9 @@ msgid "" "Do you want to migrate them to your OrcaCloud profile?\n" "This will copy your presets so they are available under your new account." msgstr "" -"Meglévő felhasználói beállítások találhatók a %s-ban.\n" -"Szeretnéd áttelepíteni őket OrcaCloud-profilba?\n" -"Ezzel átmásolja az beállítás értékeket, így azok elérhetők lesznek az új fiókjában." +"Meglévő felhasználói beállításokat találtunk itt: %s.\n" +"Szeretnéd áttelepíteni őket az Orca Cloud-profilodba?\n" +"Ezzel átmásolod a beállításaidat, így azok az új fiókodban is elérhetők lesznek." # AI Translated msgid "Migrate User Presets" @@ -2423,7 +2423,7 @@ msgstr "" "%s" msgid "The number of user presets cached in the cloud has exceeded the upper limit, newly created user presets can only be used locally." -msgstr "A felhőben tárolt felhasználói beállítások száma elérte a limitet, az újonnan létrehozott felhasználói beállítások csak helyben lesznek tárolva." +msgstr "A felhőben tárolt felhasználói beállítások száma elérte a felső korlátot. Az újonnan létrehozott felhasználói beállítások csak helyileg használhatók." msgid "Sync user presets" msgstr "Felhasználói beállítások szinkronizálása" @@ -2547,7 +2547,7 @@ msgid "Rename" msgstr "Átnevezés" msgid "Orca Slicer GUI initialization failed" -msgstr "Nem sikerült a Orca Slicer GUI inicializálása" +msgstr "Nem sikerült inicializálni az Orca Slicer grafikus felületét" #, boost-format msgid "Fatal error, exception: %1%" @@ -2761,7 +2761,7 @@ msgid "Fill bed with copies" msgstr "Asztal kitöltése másolatokkal" msgid "Fill the remaining area of bed with copies of the selected object" -msgstr "A tárgyasztal fennmaradó területének kitöltése a kijelölt objektum másolataival" +msgstr "Az asztal fennmaradó területének kitöltése a kijelölt objektum másolataival" msgid "Printable" msgstr "Nyomtatható" @@ -2770,7 +2770,7 @@ msgid "Auto Drop" msgstr "Automatikus leejtés" msgid "Automatically drops the selected object to the build plate." -msgstr "A kiválasztott objektumot automatikusan az építőlemezre ejti" +msgstr "A kiválasztott objektumot automatikusan az asztalra ejti" msgid "Fix Model" msgstr "Model javítása" @@ -2806,7 +2806,7 @@ msgid "Replace all selected parts with 3D files from folder" msgstr "Az összes kijelölt alkatrész cseréje mappából származó 3D fájlokra" msgid "Change filament" -msgstr "Filament csere" +msgstr "Filamentcsere" msgid "Set filament for selected items" msgstr "Filament beállítása a kiválasztott tárgyakhoz" @@ -2937,7 +2937,7 @@ msgid "Split the selected object" msgstr "Szétválasztja a kijelölt objektumot" msgid "Auto orientation" -msgstr "Automatikus orientáció" +msgstr "Automatikus tájolás" msgid "Auto orient the object to improve print quality" msgstr "Az objektum automatikus tájolása a nyomtatási minőség javítása érdekében." @@ -3015,7 +3015,7 @@ msgid "Fill bed with instances" msgstr "Asztal kitöltése példányokkal" msgid "Fill the remaining area of bed with instances of the selected object" -msgstr "A tárgyasztal fennmaradó területének kitöltése a kijelölt objektum példányaival" +msgstr "Az asztal fennmaradó területének kitöltése a kijelölt objektum példányaival" msgid "Clone" msgstr "Klónozás" @@ -3048,13 +3048,13 @@ msgid "Edit print parameters for a single object" msgstr "Nyomtatási paraméterek szerkesztése egy objektumhoz" msgid "Change Filament" -msgstr "Filament csere" +msgstr "Filamentcsere" msgid "Set Filament for selected items" msgstr "Filament beállítása a kiválasztott tárgyakhoz" msgid "Automatically snaps the selected object to the build plate." -msgstr "A kiválasztott objektumot automatikusan az építőlemezre illeszti" +msgstr "A kiválasztott objektumot automatikusan az asztalra illeszti" msgid "Unlock" msgstr "Feloldás" @@ -3097,7 +3097,7 @@ msgid "Click the icon to repair model object" msgstr "Kattints az ikonra a modellobjektum javításához" msgid "Right click the icon to drop the object settings" -msgstr "Kattints jobb gombbal az ikonra az objektum beállításainak elvetéséhez" +msgstr "Kattints jobb gombbal az ikonra az objektumbeállítások elvetéséhez" msgid "Click the icon to reset all settings of the object" msgstr "Kattints az ikonra az objektum összes beállításának visszaállításához" @@ -3115,7 +3115,7 @@ msgid "Click the icon to edit color painting for the object" msgstr "Kattints az ikonra az objektum színfestésének szerkesztéséhez" msgid "Click the icon to shift this object to the bed" -msgstr "Kattints az ikonra az objektum tárgyasztalra helyezéséhez" +msgstr "Kattints az ikonra az objektum asztalra helyezéséhez" # AI Translated msgid "Rename Object" @@ -3176,7 +3176,7 @@ msgid "Error!" msgstr "Hiba!" msgid "Failed to get the model data in the current file." -msgstr "Nem sikerült beolvasni a modelladatokat az aktuális fájlba." +msgstr "Nem sikerült beolvasni a modelladatokat az aktuális fájlból." # AI Translated msgid "Add primitive" @@ -3192,7 +3192,7 @@ msgid "Switch to per-object setting mode to edit process settings of selected ob msgstr "Válts át objektumonkénti beállítás módba a kiválasztott objektumok folyamatbeállításainak szerkesztéséhez." msgid "Remove paint-on fuzzy skin" -msgstr "Festett bolyhos felület eltávolítása" +msgstr "Festett barázdált felület eltávolítása" # AI Translated msgid "Delete Settings" @@ -3548,7 +3548,7 @@ msgid "Unload" msgstr "Kitöltés" msgid "Choose an AMS slot then press \"Load\" or \"Unload\" button to automatically load or unload filament." -msgstr "Válassz ki egy AMS-helyet, majd nyomd meg a \"Betöltés\" vagy a \"Kitöltés\" gombot az filament automatikus betöltéséhez vagy eltávolításához." +msgstr "Válassz ki egy AMS-helyet, majd nyomd meg a \"Betöltés\" vagy a \"Kihúzás\" gombot a filament automatikus betöltéséhez vagy kihúzásához." msgid "Filament type is unknown which is required to perform this action. Please set target filament's informations." msgstr "A művelethez szükséges filament típusa ismeretlen. Állítsd be a célfilament adatait." @@ -3672,7 +3672,7 @@ msgid "Grab new filament" msgstr "Új filament megragadása" msgid "Purge old filament" -msgstr "Régi filament kiürítése" +msgstr "Régi filament öblítése" msgid "Confirm extruded" msgstr "Extrudálás megerősítése" @@ -3771,7 +3771,7 @@ msgid "Set nozzle count" msgstr "Fúvókaszám beállítása" msgid "Please set nozzle count" -msgstr "Kérjük, állítsd be a fúvókaszámot" +msgstr "Kérlek, állítsd be a fúvókaszámot" msgid "Error: Can not set both nozzle count to zero." msgstr "Hiba: Nem lehet mindkét fúvóka számát nullára állítani." @@ -3813,10 +3813,10 @@ msgid "Unknown nozzle detected. Refresh to update (unrefreshed nozzles will be s msgstr "Ismeretlen fúvóka érzékelve. Frissítsd az adatokat (a nem frissített fúvókákat nem használjuk a szeleteléskor)." msgid "Please confirm whether the required nozzle diameter and flow rate match the currently displayed values." -msgstr "Kérjük, ellenőrizd, hogy a szükséges fúvókaátmérő és áramlási sebesség megegyezik-e a kijelzőn lévővel." +msgstr "Kérlek, ellenőrizd, hogy a szükséges fúvókaátmérő és áramlási sebesség megegyezik-e a kijelzőn látható értékekkel." msgid "Your printer has different nozzles installed. Please select a nozzle for this print." -msgstr "A nyomtatóban különböző fúvókák vannak. Kérjük, válassz egy fúvókát a nyomtatáshoz." +msgstr "A nyomtatóban különböző fúvókák vannak. Kérlek, válassz egy fúvókát a nyomtatáshoz." msgid "Ignore" msgstr "Mellőzés" @@ -3848,11 +3848,15 @@ msgstr "Elrendezés..." msgid "Arranging" msgstr "Elrendezés" +# AI Translated +msgid "Arranging " +msgstr "Elrendezés " + msgid "Arranging canceled." msgstr "Elrendezése törölve." msgid "Arranging complete, but some items were not able to be arranged. Reduce spacing and try again." -msgstr "Az elrendezés megtörtént, de maradtak összeragadt tárgyak. Csökkentsd a térközt, és próbáld meg újra." +msgstr "Az elrendezés elkészült, de néhány tárgyat nem sikerült elhelyezni. Csökkentsd a térközt, majd próbáld újra." msgid "Arranging done." msgstr "Elrendezés kész." @@ -3873,20 +3877,20 @@ msgid "" "Cannot auto-orient these objects." msgstr "" "Az összes kijelölt objektum egy zárolt tálcán van,\n" -"nem lehet automatikus orientációt használni rajtuk." +"nem lehet automatikus tájolást használni rajtuk." msgid "" "This plate is locked.\n" "Cannot auto-orient on this plate." msgstr "" "Ez a tálca zárolva van.\n" -"Nem lehetséges az automatikus orientáció ezen a tálcán." +"Ezen a tálcán nem használható az automatikus tájolás." msgid "Orienting..." -msgstr "Orientáció folyamatban..." +msgstr "Tájolás folyamatban..." msgid "Orienting" -msgstr "Orientáció" +msgstr "Tájolás" msgid "Orienting canceled." msgstr "Tájolás megszakítva." @@ -3937,19 +3941,19 @@ msgid "The print file exceeds the maximum allowable size (1GB). Please simplify msgstr "A nyomtatási fájl mérete meghaladja a megengedett maximumot (1 GB). Egyszerűsítsd a modellt, majd szeletelj újra." msgid "Failed to send the print job. Please try again." -msgstr "Nem sikerült elküldeni a nyomtatási feladatot. Kérlek próbáld újra." +msgstr "Nem sikerült elküldeni a nyomtatási feladatot. Kérlek, próbáld újra." msgid "Failed to upload file to ftp. Please try again." msgstr "Nem sikerült feltölteni a fájlt FTP-re. Próbáld újra." msgid "Check the current status of the Bambu Lab server by clicking on the link above." -msgstr "A Bambu szerver aktuális állapotát a fenti hivatkozásra kattintva ellenőrizheted." +msgstr "A Bambu Lab szerver aktuális állapotát a fenti hivatkozásra kattintva ellenőrizheted." msgid "The size of the print file is too large. Please adjust the file size and try again." -msgstr "A nyomtatási fájl mérete túl nagy. Állítsd be a fájlméretet, és próbáld újra." +msgstr "A nyomtatási fájl mérete túl nagy. Állítsd be a fájlméretet, majd próbáld újra." msgid "Print file not found; please slice it again and send it for printing." -msgstr "A nyomtatási fájl nem található, szeleteld újra, és küldd nyomtatásra." +msgstr "A nyomtatási fájl nem található, szeleteld újra, majd küldd nyomtatásra." msgid "Failed to upload print file via FTP. Please check the network status and try again." msgstr "Nem sikerült feltölteni a nyomtatási fájlt FTP-re. Ellenőrizd a hálózati állapotot, majd próbáld újra." @@ -3988,7 +3992,7 @@ msgid "A Storage needs to be inserted before printing via LAN." msgstr "LAN-on keresztüli nyomtatás előtt be kell helyezni egy tárolót." msgid "Sending print job over LAN, but the Storage in the printer is abnormal and print-issues may be caused by this." -msgstr "A nyomtatási feladat LAN-on keresztül küldésre kerül, de a nyomtatóban lévő tároló rendellenes, ami nyomtatási problémákat okozhat." +msgstr "A nyomtatási feladat LAN-on keresztüli küldése folyamatban van, de a nyomtató tárolója rendellenes, ami nyomtatási problémákat okozhat." msgid "The Storage in the printer is abnormal. Please replace it with a normal Storage before sending print job to printer." msgstr "A nyomtatóban lévő tároló rendellenes. Cseréld normál tárolóra, mielőtt nyomtatási feladatot küldesz a nyomtatóra." @@ -4013,7 +4017,7 @@ msgid "Storage needs to be inserted before sending to printer." msgstr "A nyomtatóra küldés előtt be kell helyezni egy tárolót." msgid "Sending G-code file over LAN, but the Storage in the printer is abnormal and print-issues may be caused by this." -msgstr "A G-kód fájl LAN-on keresztül küldésre kerül, de a nyomtatóban lévő tároló rendellenes, ami nyomtatási problémákat okozhat." +msgstr "A G-kód fájl LAN-on keresztüli küldése folyamatban van, de a nyomtató tárolója rendellenes, ami nyomtatási problémákat okozhat." msgid "The Storage in the printer is abnormal. Please replace it with a normal Storage before sending to printer." msgstr "A nyomtatóban lévő tároló rendellenes. Cseréld normál tárolóra, mielőtt a nyomtatóra küldesz." @@ -4086,7 +4090,7 @@ msgid "The imported SLA archive did not contain any presets. The current SLA pre msgstr "Az importált SLA archívum nem tartalmazott beállításokat. Tartalékként az aktuális SLA beállítások kerültek használatra." msgid "You cannot load an SLA project with a multi-part object on the bed" -msgstr "Nem tölthető be SLA projekt, ha a tárgyasztalon több részből álló objektum van" +msgstr "Nem tölthető be SLA-projekt, ha az asztalon több részből álló objektum van" msgid "Please check your object list before preset changing." msgstr "A beállítás módosítása előtt ellenőrizd az objektumlistát." @@ -4122,13 +4126,13 @@ msgid "License" msgstr "Licenc" msgid "Orca Slicer is licensed under " -msgstr "A Orca Slicer a következő licencet használja " +msgstr "Az Orca Slicer a következő licencet használja " msgid "GNU Affero General Public License, version 3" msgstr "GNU Affero General Public License, 3-as verzió" msgid "Orca Slicer is based on PrusaSlicer and BambuStudio" -msgstr "Az Orca Slicer a PrusaSlicerre és a BambuStudióra épül" +msgstr "Az Orca Slicer a PrusaSlicerre és a BambuStudio-ra épül" msgid "Libraries" msgstr "Könyvtárak" @@ -4175,7 +4179,7 @@ msgid "The input value should be greater than %1% and less than %2%" msgstr "A megadott értéknek nagyobbnak kell lennie, mint %1% és kisebbnek, mint %2%" msgid "Factors of Flow Dynamics Calibration" -msgstr "Anyagáramlás kalibrálásának faktorai" +msgstr "Áramlásdinamika-kalibrálás tényezői" msgid "Wiki Guide" msgstr "Wiki útmutató" @@ -4190,7 +4194,7 @@ msgid "Factor N" msgstr "N-tényező" msgid "Setting AMS slot information while printing is not supported" -msgstr "Nyomtatás közben nem változtathatóak meg a AMS férőhelyek adatai" +msgstr "Nyomtatás közben nem módosíthatók az AMS-férőhelyek adatai" msgid "Setting Virtual slot information while printing is not supported" msgstr "Nyomtatás közben a virtuális férőhely adatai nem módosíthatók" @@ -4229,7 +4233,7 @@ msgid "Dynamic flow calibration" msgstr "Dinamikus anyagáramlás kalibráció" msgid "The nozzle temp and max volumetric speed will affect the calibration results. Please fill in the same values as the actual printing. They can be auto-filled by selecting a filament preset." -msgstr "A fúvóka hőmérséklete és a maximális anyagáramlás sebessége befolyásolja a kalibrációs eredményeket. Kérlek, add meg a nyomtatás használt tényleges értékeket. Ezek automatikusan is kitöltheted a megfelelő filamentbeállítás kiválasztásával." +msgstr "A fúvóka hőmérséklete és a maximális volumetrikus sebesség befolyásolja a kalibrálás eredményét. Add meg a tényleges nyomtatás során használt értékeket. Ezeket a megfelelő filamentbeállítás kiválasztásával automatikusan is kitöltheted." msgid "Nozzle Diameter" msgstr "Fúvóka átmérője" @@ -4263,14 +4267,14 @@ msgid "Next" msgstr "Következő" msgid "Calibration completed. Please find the most uniform extrusion line on your hot bed like the picture below, and fill the value on its left side into the factor K input box." -msgstr "A kalibrálás befejeződött. Kérlek, válaszd ki az alábbi képen láthatóhoz legjobban hasonlító, legegyenletesebb extrudálási vonalat, és írd be a bal oldalán lévő értéket a K-tényező beviteli mezőjébe." +msgstr "A kalibrálás befejeződött. Kérlek, válaszd ki az alábbi képen láthatóhoz legjobban hasonlító, legegyenletesebb extrudálási vonalat, majd írd be a bal oldalán lévő értéket a K-tényező beviteli mezőjébe." msgid "Save" msgstr "Mentés" msgctxt "Navigation" msgid "Back" -msgstr "Hátul" +msgstr "Vissza" msgid "Example" msgstr "Példa" @@ -4298,7 +4302,7 @@ msgid "" "And you can click it to modify" msgstr "" "Felső fél: Eredeti\n" -"Alsó fél: Hozzárendelés nélkül az eredeti projekt filamentje lesz használva.\n" +"Alsó fél: hozzárendelés nélkül az eredeti projekt filamentjét használja.\n" "Kattintással módosíthatod" msgid "" @@ -4381,7 +4385,7 @@ msgid "Please change the desiccant when it is too wet. The indicator may not rep msgstr "Cseréld a nedvszívót, ha túl nedves. A jelző nem mindig pontos az alábbi esetekben: ha a fedél nyitva van, vagy ha a nedvszívó csomag cserélve lett. A nedvesség elnyelése órákat vesz igénybe, és az alacsony hőmérséklet tovább lassítja a folyamatot." msgid "Configure which AMS slot should be used for a filament used in the print job." -msgstr "Add meg, hogy melyik AMS-férőhely legyen legyen hozzárendelve a nyomtatásnál használt filamenthez." +msgstr "Add meg, hogy melyik AMS-férőhely legyen hozzárendelve a nyomtatásnál használt filamenthez." msgid "Filament used in this print job" msgstr "A nyomtatási feladatban használt filament" @@ -4427,7 +4431,7 @@ msgid "The printer does not currently support auto refill." msgstr "A nyomtató jelenleg nem támogatja az automatikus újratöltést." msgid "AMS filament backup is not enabled; please enable it in the AMS settings." -msgstr "Az AMS filament tartalék funkció nincs engedélyezve, kapcsold be az AMS beállításokban." +msgstr "A tartalék filament használata nincs engedélyezve; kapcsold be az AMS beállításaiban." msgid "" "When the current filament runs out, the printer will use identical filament to continue printing.\n" @@ -4451,31 +4455,31 @@ msgid "Insertion update" msgstr "Frissítés" msgid "The AMS will automatically read the filament information when inserting a new Bambu Lab filament spool. This takes about 20 seconds." -msgstr "Az AMS automatikusan kiolvassa a filament információkat egy új Bambu Lab filament tekercs behelyezésekor. Ez körülbelül 20 másodpercet vesz igénybe." +msgstr "Új Bambu Lab filamenttekercs behelyezésekor az AMS automatikusan kiolvassa a filament adatait. Ez körülbelül 20 másodpercet vesz igénybe." msgid "Note: if a new filament is inserted during printing, the AMS will not automatically read any information until printing is completed." -msgstr "Megjegyzés: ha nyomtatás során új filament kerül behelyezésre, az AMS nem fogja automatikusan kiolvasni az információkat a nyomtatás végéig." +msgstr "Megjegyzés: ha nyomtatás közben új filamentet helyezel be, az AMS csak a nyomtatás befejezése után olvassa ki automatikusan az adatait." msgid "When inserting a new filament, the AMS will not automatically read its information, leaving it blank for you to enter manually." -msgstr "Új filament behelyezésekor az AMS nem fogja automatikusan kiolvasni az információkat, hanem üresen hagyja azokat, így kézzel kell megadnod." +msgstr "Új filament behelyezésekor az AMS nem olvassa ki automatikusan az adatait, hanem üresen hagyja őket, hogy kézzel adhasd meg." msgid "Update on startup" msgstr "Frissítés bekapcsoláskor" msgid "The AMS will automatically read the information of inserted filament on start-up. It will take about 1 minute. The reading process will rotate the filament spools." -msgstr "Az AMS indításkor automatikusan kiolvassa a behelyezett filament adatait. Ez körülbelül 1 percet vesz igénybe. A leolvasási folyamat során a filamenttekercsek feltekercselésre kerülnek." +msgstr "Az AMS indításkor automatikusan kiolvassa a behelyezett filament adatait. Ez körülbelül 1 percet vesz igénybe. A leolvasás közben a filamenttekercsek forognak." msgid "The AMS will not automatically read information from inserted filament during startup and will continue to use the information recorded before the last shutdown." -msgstr "Az AMS indításkor nem olvassa ki automatikusan az információkat a behelyezett filamentről, és továbbra is a legutóbbi leállítás előtt rögzített információkat használja." +msgstr "Az AMS indításkor nem olvassa ki automatikusan a behelyezett filament adatait, hanem továbbra is a legutóbbi leállítás előtt rögzített adatokat használja." msgid "Update remaining capacity" -msgstr "Fennmaradó kapacitás frissítése" +msgstr "Hátralévő filamentmennyiség frissítése" msgid "AMS will attempt to estimate the remaining capacity of the Bambu Lab filaments." -msgstr "Az AMS megpróbálja megbecsülni a Bambu Lab filamentek fennmaradó kapacitását." +msgstr "Az AMS megpróbálja megbecsülni a Bambu Lab filamenttekercseken hátralévő mennyiséget." msgid "AMS filament backup" -msgstr "AMS filament tartalék" +msgstr "Automatikus váltás tartalék tekercsre" msgid "AMS will continue to another spool with matching filament properties automatically when current filament runs out." msgstr "Az AMS automatikusan egy másik, azonos tulajdonságú filamentre vált, ha az aktuális filament kifogy." @@ -4484,7 +4488,7 @@ msgid "Air Printing Detection" msgstr "Levegőbe nyomtatás észlelése" msgid "Detects clogging and filament grinding, halting printing immediately to conserve time and filament." -msgstr "Észleli az eltömődést és a filament darálását, és az idő és filament takarékossága érdekében azonnal leállítja a nyomtatást." +msgstr "Észleli az eltömődést és a filament ledarálását, majd azonnal leállítja a nyomtatást, így időt és filamentet takarít meg." msgid "AMS Type" msgstr "AMS típus" @@ -4514,10 +4518,10 @@ msgid "Calibration" msgstr "Kalibrálás" msgid "Failed to download the plug-in. Please check your firewall settings and VPN software and retry." -msgstr "Nem sikerült letölteni a bővítményt. Kérlek, ellenőrizd a tűzfal beállításait és a VPN-szoftvert, majd próbálja meg újra." +msgstr "Nem sikerült letölteni a bővítményt. Kérlek, ellenőrizd a tűzfal beállításait és a VPN-szoftvert, majd próbáld újra." msgid "Failed to install the plug-in. The plug-in file may be in use. Please restart OrcaSlicer and try again. Also check whether it is blocked or has been deleted by anti-virus software." -msgstr "Nem sikerült telepíteni a bővítményt. Lehet, hogy a bővítményfájl használatban van. Indítsd újra az OrcaSlicert, majd próbáld újra. Ellenőrizd azt is, hogy vírusirtó szoftver nem blokkolta vagy törölte-e." +msgstr "Nem sikerült telepíteni a bővítményt. Lehet, hogy a bővítményfájl használatban van. Indítsd újra az OrcaSlicert, majd próbáld újra. Ellenőrizd azt is, hogy nem blokkolta-e vagy törölte-e egy vírusirtó program." msgid "Click here to see more info" msgstr "Kattints ide további információkért" @@ -4529,16 +4533,16 @@ msgid "Restart Required" msgstr "Újraindítás szükséges" msgid "Please home all axes (click " -msgstr "Kérlek, végezd el a tengelyek alaphelyzetbe állítását (kattints" +msgstr "Kérlek, állítsd alaphelyzetbe az összes tengelyt (kattints " msgid ") to locate the toolhead's position. This prevents device moving beyond the printable boundary and causing equipment wear." -msgstr "). Ez megakadályozza, hogy a nyomtató megpróbálja a nyomtatható területen túlra mozgatni a fejet, ezzel az eszköz esetleges meghibásodását kockáztatva." +msgstr "). Így a nyomtató nem mozgatja a fejet a nyomtatható területen túlra, ami az eszköz kopását okozhatná." msgid "Go Home" msgstr "Alaphelyzet" msgid "An error occurred. The system may have run out of memory, or a bug may have occurred." -msgstr "Hiba történt. Lehet, hogy a rendszer memóriája nem elég, vagy a program hibás" +msgstr "Hiba történt. Lehet, hogy elfogyott a rendszer memóriája, vagy programhiba történt." #, boost-format msgid "A fatal error occurred: \"%1%\"" @@ -4588,16 +4592,16 @@ msgid "" "Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\n" "Error message: %1%" msgstr "" -"Az ideiglenes G-kód másolása a kimeneti G-kódba nem sikerült. Lehet, hogy az SD kártya írásvédett?\n" +"Nem sikerült az ideiglenes G-kódot a kimeneti G-kódba másolni. Lehet, hogy az SD-kártya írásvédett?\n" "Hibaüzenet: %1%" #, boost-format msgid "Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp." -msgstr "Az ideiglenes G-kód másolása a kimeneti G-kódba nem sikerült. Probléma lehet a céleszközzel. Kérlek, próbálkozzon újra az exportálással, vagy használjon másik eszközt. A sérült kimeneti G-kód %1%.tmp." +msgstr "Nem sikerült az ideiglenes G-kódot a kimeneti G-kódba másolni. Probléma lehet a céleszközzel. Kérlek, exportáld újra, vagy használj másik eszközt. A sérült kimeneti G-kód helye: %1%.tmp." #, boost-format msgid "Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again." -msgstr "A G-kód átnevezése a kiválasztott célmappába másolás után nem sikerült. A jelenlegi elérési út %1%.tmp. Kérlek, próbálja meg újra az exportálást." +msgstr "A G-kód átnevezése a kiválasztott célmappába másolás után nem sikerült. A jelenlegi elérési út %1%.tmp. Kérlek, próbáld újra az exportálást." #, boost-format msgid "Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp." @@ -4641,7 +4645,7 @@ msgid "Distance of the 0,0 G-code coordinate from the front left corner of the r msgstr "A 0,0 G-kód koordinátájának távolsága a téglalap bal első sarkától." msgid "Diameter of the print bed. It is assumed that origin (0,0) is located in the center." -msgstr "A tárgyasztal átmérője. Feltételezzük, hogy az origó (0,0) középen van." +msgstr "Az asztal átmérője. Feltételezzük, hogy az origó (0,0) középen van." msgid "Rectangular" msgstr "Téglalap" @@ -4843,7 +4847,7 @@ msgstr "" "Visszaállítás a felületi réteg mélységének 50%-ára." msgid "Both [Extrusion] and [Combined] modes of Fuzzy Skin require the Arachne Wall Generator to be enabled." -msgstr "A bolyhos felület [Extrudálás] és [Kombinált] módja is megköveteli az Arachne falgenerátor engedélyezését." +msgstr "A barázdált felület [Extrudálás] és [Kombinált] módja is megköveteli az Arachne falgenerátor engedélyezését." msgid "" "Change these settings automatically?\n" @@ -4852,13 +4856,13 @@ msgid "" msgstr "" "Automatikusan módosítsuk ezeket a beállításokat?\n" "Igen - Engedélyezd az Arachne falgenerátort\n" -"Nem - Tiltsd le az Arachne falgenerátort, és állítsd a bolyhos felületet [Eltolás] módra" +"Nem - Tiltsd le az Arachne falgenerátort, majd állítsd a barázdált felületet [Eltolás] módra" msgid "Spiral mode only works when wall loops is 1, support is disabled, clumping detection by probing is disabled, top shell layers is 0, sparse infill density is 0 and timelapse type is traditional." -msgstr "A spirál mód csak akkor működik, ha a falhurkok száma 1, a támasz le van tiltva, a szondázásos csomósodásészlelés le van tiltva, a felső héjrétegek száma 0, a ritkás kitöltés sűrűsége 0, és az időzített felvétel típusa hagyományos." +msgstr "A spirál mód csak akkor működik, ha a falhurkok száma 1, a támasz és a szondázásos csomósodásészlelés ki van kapcsolva, a felső héjrétegek száma 0, a kitöltés sűrűsége 0, a Timelapse típusa pedig hagyományos." msgid " But machines with I3 structure will not generate timelapse videos." -msgstr " Az I3-szerkezetű gépek azonban nem fognak időfelvétel videókat készíteni." +msgstr " Az I3-szerkezetű gépek azonban nem készítenek Timelapse-videókat." msgid "" "Change these settings automatically?\n" @@ -4866,8 +4870,8 @@ msgid "" "No - Cancel enabling spiral mode" msgstr "" "Automatikusan megváltoztatod ezeket a beállításokat?\n" -"Igen - Módosítsa ezeket a beállításokat, és automatikusan engedélyezze a spirál mód használatát\n" -"Nem - Ne használja a spirál módot ez alkalommal" +"Igen - Módosítsd ezeket a beállításokat, és automatikusan kapcsold be a spirál módot\n" +"Nem - Most ne kapcsold be a spirál módot" msgid "Printing" msgstr "Nyomtatás" @@ -4903,7 +4907,7 @@ msgid "Inspecting first layer" msgstr "Első réteg vizsgálata" msgid "Identifying build plate type" -msgstr "Tárgyasztal azonosítása" +msgstr "Asztaltípus azonosítása" msgid "Calibrating Micro Lidar" msgstr "Micro Lidar kalibrálása" @@ -5059,16 +5063,16 @@ msgid "Update failed." msgstr "A frissítés sikertelen." msgid "Timelapse is not supported on this printer." -msgstr "Az időzített felvétel ezen a nyomtatón nem támogatott." +msgstr "Ez a nyomtató nem támogatja a Timelapse-felvételt." msgid "Timelapse is not supported while the storage does not exist." -msgstr "Az időzített felvétel nem támogatott, ha nincs tároló." +msgstr "A Timelapse-felvétel tároló nélkül nem támogatott." msgid "Timelapse is not supported while the storage is unavailable." -msgstr "Az időzített felvétel nem támogatott, ha a tároló nem érhető el." +msgstr "A Timelapse-felvétel nem támogatott, ha a tároló nem érhető el." msgid "Timelapse is not supported while the storage is readonly." -msgstr "Az időzített felvétel nem támogatott, ha a tároló csak olvasható." +msgstr "A Timelapse-felvétel nem támogatott, ha a tároló csak olvasható." msgid "To ensure your safety, certain processing tasks (such as laser) can only be resumed on printer." msgstr "A biztonság érdekében bizonyos műveletek (például lézeres feladatok) csak a nyomtatón folytathatók." @@ -5258,7 +5262,7 @@ msgid "SLA Materials settings" msgstr "SLA anyagbeállítások" msgid "Printer settings" -msgstr "Nyomtató beállítások" +msgstr "Nyomtatóbeállítások" msgid "parameter name" msgstr "paraméter neve" @@ -5447,7 +5451,7 @@ msgid "Bridge" msgstr "Áthidalás" msgid "Gap infill" -msgstr "Réskitöltés" +msgstr "Hézagok kitöltése" msgid "Skirt" msgstr "Szoknya" @@ -5471,19 +5475,19 @@ msgid "Mixed" msgstr "Vegyes" msgid "Height: " -msgstr "Magasság:" +msgstr "Magasság: " msgid "Width: " -msgstr "Szélesség:" +msgstr "Szélesség: " msgid "Flow: " -msgstr "Anyagáramlás:" +msgstr "Anyagáramlás: " msgid "Fan: " -msgstr "Ventilátor-fordulatszám:" +msgstr "Ventilátor-fordulatszám: " msgid "Temperature: " -msgstr "Hőmérséklet:" +msgstr "Hőmérséklet: " msgid "Layer Time: " msgstr "Rétegidő: " @@ -5522,7 +5526,7 @@ msgid "Time" msgstr "Idő" msgid "Speed: " -msgstr "Sebesség:" +msgstr "Sebesség: " msgid "Actual speed profile" msgstr "Tényleges sebességprofil" @@ -5633,7 +5637,7 @@ msgid "Fan speed (%)" msgstr "Ventilátor fordulatszám (%)" msgid "Temperature (℃)" -msgstr "Hőmérséklet (°C)" +msgstr "Hőmérséklet (℃)" msgid "Volumetric flow rate (mm³/s)" msgstr "Térfogatáramlás (mm³/s)" @@ -5789,7 +5793,7 @@ msgid "Move object" msgstr "Objektum mozgatása" msgid "Auto orientation options" -msgstr "Automatikus orientáció beállításai" +msgstr "Automatikus tájolás beállításai" msgid "Enable rotation" msgstr "Forgatás engedélyezése" @@ -5798,7 +5802,7 @@ msgid "Optimize support interface area" msgstr "Támasz érintkező felületének optimalizálása" msgid "Orient" -msgstr "Orientáció" +msgstr "Tájolás" msgid "Arrange options" msgstr "Elrendezési lehetőségek" @@ -5854,10 +5858,10 @@ msgid "Add plate" msgstr "Tálca hozzáadása" msgid "Auto orient all/selected objects" -msgstr "Összes/kiválasztott objektum automatikus orientációja" +msgstr "Az összes/kiválasztott objektum automatikus tájolása" msgid "Auto orient all objects on current plate" -msgstr "Aktuális tálca összes objektumának automatikus orientációja" +msgstr "A jelenlegi tálca összes objektumának automatikus tájolása" msgid "Arrange all objects" msgstr "Összes objektum elrendezése" @@ -5944,7 +5948,7 @@ msgid "Paint Toolbar" msgstr "Festés eszköztár" msgid "Explosion Ratio" -msgstr "Robbantási arány" +msgstr "Széthúzás mértéke" msgid "Section View" msgstr "Keresztmetszet nézet" @@ -6078,7 +6082,7 @@ msgid "Go Live" msgstr "Streamelés indítása" msgid "Liveview Retry" -msgstr "Élő nézet újra próbálása" +msgstr "Élőkép automatikus újrapróbálása" msgid "Resolution" msgstr "Felbontás" @@ -6156,7 +6160,7 @@ msgid "No" msgstr "Nem" msgid "will be closed before creating a new model. Do you want to continue?" -msgstr "bezárásra kerül új modell létrehozása előtt. Folytatod?" +msgstr "bezárul az új modell létrehozása előtt. Folytatod?" msgid "Slice plate" msgstr "Tálca szeletelése" @@ -6631,28 +6635,28 @@ msgid "Synchronization" msgstr "Szinkronizálás" msgid "The device cannot handle more conversations. Please retry later." -msgstr "Az eszköz nem tud több kapcsolatot kezelni. Kérlek, próbálkozz később." +msgstr "Az eszköz nem tud több kapcsolatot kezelni. Kérlek, próbáld újra később." msgid "Player is malfunctioning. Please reinstall the system player." -msgstr "A lejátszó hibásan működik. Kérlek, telepítsd újra." +msgstr "A rendszer médialejátszója nem működik megfelelően. Kérlek, telepítsd újra." msgid "The player is not loaded; please click the \"play\" button to retry." -msgstr "A lejátszó nem töltődött be; kérlek, kattints a \"lejátszás\" gombra az újra próbálkozáshoz." +msgstr "A lejátszó nem töltődött be. Kérlek, kattints a \"Lejátszás\" gombra az újbóli próbálkozáshoz." msgid "The player is not loaded because the GStreamer GTK video sink is missing or failed to initialize." msgstr "A lejátszó nem töltődik be, mert hiányzik a GStreamer GTK videonyelő, vagy nem sikerült inicializálni." msgid "Please confirm if the printer is connected." -msgstr "Kérlek, ellenőrizd, hogy a nyomtató csatlakoztatva van." +msgstr "Kérlek, ellenőrizd, hogy a nyomtató csatlakoztatva van-e." msgid "The printer is currently busy downloading. Please try again after it finishes." msgstr "A nyomtató a letöltéssel van elfoglalva. Kérlek, várd meg, amíg a letöltés befejeződik." msgid "Printer camera is malfunctioning." -msgstr "A nyomtató kamerája hibásan működik." +msgstr "A nyomtató kamerája nem működik megfelelően." msgid "A problem occurred. Please update the printer firmware and try again." -msgstr "Probléma merült fel. Kérlek, frissítsd a nyomtató firmware-ét, és próbáld meg újra." +msgstr "Probléma merült fel. Kérlek, frissítsd a nyomtató firmware-ét, majd próbáld újra." msgid "LAN Only Liveview is off. Please turn on the liveview on printer screen." msgstr "A csak LAN élőkép ki van kapcsolva. Kapcsold be az élőképet a nyomtató kijelzőjén." @@ -6664,10 +6668,10 @@ msgid "Initializing..." msgstr "Inicializálás…" msgid "Connection Failed. Please check the network and try again" -msgstr "Csatlakozás sikertelen. Kérlek, ellenőrizd a hálózatot, és próbáld újra" +msgstr "Csatlakozás sikertelen. Kérlek, ellenőrizd a hálózatot, majd próbáld újra" msgid "Please check the network and try again. You can restart or update the printer if the issue persists." -msgstr "Kérlek, ellenőrizd a hálózatot, és próbáld újra. Ha a probléma továbbra is fennáll, indítsd újra vagy frissítsd a nyomtatót." +msgstr "Kérlek, ellenőrizd a hálózatot, majd próbáld újra. Ha a probléma továbbra is fennáll, indítsd újra vagy frissítsd a nyomtatót." msgid "The printer has been logged out and cannot connect." msgstr "A nyomtató ki van jelentkezve, és nem tud csatlakozni." @@ -6694,7 +6698,7 @@ msgid "" "Do you want to stop this virtual camera?" msgstr "" "Már fut egy másik virtuális kamera.\n" -"A Orca Slicer csak egy virtuális kamerát támogat.\n" +"Az Orca Slicer csak egy virtuális kamerát támogat.\n" "Leállítod ezt a virtuális kamerát?" #, c-format, boost-format @@ -6735,7 +6739,7 @@ msgid "Timelapse" msgstr "Timelapse" msgid "Switch to timelapse files." -msgstr "Váltás timelapse fájlokra." +msgstr "Váltás Timelapse-fájlokra." # AI Translated msgid "Video" @@ -6809,11 +6813,11 @@ msgid "Failed to parse model information." msgstr "Nem sikerült feldolgozni a modellinformációkat" msgid "The .gcode.3mf file contains no G-code data. Please slice it with Orca Slicer and export a new .gcode.3mf file." -msgstr "A .gcode.3mf fájl nem tartalmaz G-kód adatot. Szeleteld újra Orca Slicerrel és exportálj egy új .gcode.3mf fájlt." +msgstr "A .gcode.3mf fájl nem tartalmaz G-kód-adatot. Szeleteld újra Orca Slicerrel, majd exportálj egy új .gcode.3mf fájlt." #, c-format, boost-format msgid "File '%s' was lost! Please download it again." -msgstr "A (z) '%s' fájl elveszett! Kérlek, töltsd le újra." +msgstr "A(z) '%s' fájl elveszett! Kérlek, töltsd le újra." #, c-format, boost-format msgid "" @@ -6852,7 +6856,7 @@ msgid "File does not exist." msgstr "A fájl nem létezik." msgid "File checksum error. Please retry." -msgstr "Fájl checksum hiba. Kérlek, próbáld újra." +msgstr "A fájl ellenőrzőösszege hibás. Kérlek, próbáld újra." msgid "Not supported on the current printer version." msgstr "A nyomtató jelenlegi szoftvere nem támogatja." @@ -7070,7 +7074,7 @@ msgid "Safety Options" msgstr "Biztonsági beállítások" msgid "Hotends" -msgstr "Hotendek" +msgstr "Fejegységek" msgid "Lamp" msgstr "Világítás" @@ -7142,7 +7146,7 @@ msgid "Layer: %d/%d" msgstr "Réteg: %d/%d" msgid "Please heat the nozzle to above 170℃ before loading or unloading filament." -msgstr "Kérlek, melegítsd a fúvókát 170 fok fölé a filament betöltése vagy kihúzása előtt." +msgstr "Kérlek, melegítsd a fúvókát 170℃ fölé a filament betöltése vagy kihúzása előtt." msgid "Chamber temperature cannot be changed in cooling mode while printing." msgstr "Nyomtatás közben hűtési módban a kamrahőmérséklet nem módosítható." @@ -7208,7 +7212,7 @@ msgid "Submit" msgstr "Elküldés" msgid "Please click on the star first." -msgstr "Kérlek, először kattints a csillagokra." +msgstr "Kérlek, először kattints a csillagra." msgid "Get oss config failed." msgstr "OSS-konfiguráció letöltése sikertelen." @@ -7454,8 +7458,8 @@ msgstr[1] "%1$d objektum vágott objektum részeként lett betöltve." #, c-format, boost-format msgid "%1$d object was loaded with fuzzy skin painting." msgid_plural "%1$d objects were loaded with fuzzy skin painting." -msgstr[0] "%1$d objektum bolyhos felület festéssel lett betöltve." -msgstr[1] "%1$d objektum bolyhos felület festéssel lett betöltve." +msgstr[0] "%1$d objektum barázdáltfelület-festéssel lett betöltve." +msgstr[1] "%1$d objektum barázdáltfelület-festéssel lett betöltve." msgid "ERROR" msgstr "HIBA" @@ -7582,7 +7586,7 @@ msgid "Enable detection of build plate position" msgstr "Nyomtatótálca helyzetének érzékelése" msgid "The localization tag of the build plate will be detected, and printing will be paused if the tag is not in predefined range." -msgstr "A nyomtató megkeresi a nyomtatótálca lokalizációs címkéjét, és szünetelteti a nyomtatást, ha az nem egy előre meghatározott tartományban van." +msgstr "A rendszer ellenőrzi a nyomtatótálca helyzetjelölő címkéjét, és szünetelteti a nyomtatást, ha a címke az előre meghatározott tartományon kívül esik." msgid "Build Plate Detection" msgstr "Tálcaészlelés" @@ -7771,7 +7775,7 @@ msgid "Compare presets" msgstr "Beállítások összehasonlítása" msgid "View all object's settings" -msgstr "Összes objektum beállításainak megtekintése" +msgstr "Az összes objektum beállításainak megtekintése" msgid "Material settings" msgstr "Anyagbeállítások" @@ -7877,7 +7881,7 @@ msgstr "Filamentváltó észlelve. Az összes AMS filament mostantól mindkét e # AI Translated msgid "A filament switcher is detected but not calibrated and thus currently unavailable. Please calibrate it on the printer and synchronize before use." -msgstr "A rendszer filamentváltót észlelt, de az nincs kalibrálva, ezért jelenleg nem használható. Kérlek, kalibráld a nyomtatón, és szinkronizáld a használat előtt." +msgstr "A rendszer filamentváltót észlelt, de az nincs kalibrálva, ezért jelenleg nem használható. Kérlek, kalibráld a nyomtatón, majd használat előtt szinkronizáld." msgid "Tips" msgstr "Tippek" @@ -7940,7 +7944,7 @@ msgstr "Pelletek" #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." -msgstr "A művelet befejezése után a(z) %s projekt bezárul, és egy új projekt jön létre." +msgstr "A művelet befejezésekor a(z) %s projekt bezárul, majd új projekt jön létre." msgid "There are no compatible filaments, and sync is not performed." msgstr "Nincs kompatibilis filament és nem történt szinkronizálás." @@ -7956,10 +7960,10 @@ msgstr "" "Frissítsd az Orca Slicert, vagy indítsd újra, hogy ellenőrizhesd a rendszerbeállítások frissítését." msgid "Only filament color information has been synchronized from printer." -msgstr "Csak a filament színinformációi lettek szinkronizálva a nyomtatóról." +msgstr "A nyomtatóról csak a filament színadatai szinkronizálódtak." msgid "Filament type and color information have been synchronized, but slot information is not included." -msgstr "A filament típus- és színinformációk szinkronizálva lettek, de a férőhelyinformáció nincs benne." +msgstr "A filament típus- és színadatai szinkronizálódtak, a férőhely adatai azonban nem." #, boost-format msgid "Do you want to save changes to \"%1%\"?" @@ -7986,10 +7990,10 @@ msgid "The nozzle hardness required by the filament is higher than the default n msgstr "Ez a filament nagyobb keménységű fúvókát igényel. Kérlek, cseréld ki a fúvókát vagy válassz másik filamentet, különben előfordulhat, hogy a fúvóka idő előtt elhasználódik vagy megsérül." msgid "Enabling traditional timelapse photography may cause surface imperfections. It is recommended to change to smooth mode." -msgstr "A hagyományos időfelvétel engedélyezése felületi hibákat okozhat. Javasoljuk, hogy válts a sima módra." +msgstr "A hagyományos Timelapse bekapcsolása felületi hibákat okozhat. Javasoljuk, hogy válts sima módra." msgid "Smooth mode for timelapse is enabled, but the prime tower is off, which may cause print defects. Please enable the prime tower, re-slice and print again." -msgstr "A időfelvétel sima módja engedélyezett, de a törlőtorony ki van kapcsolva, ami nyomtatási hibákat okozhat. Kapcsold be a törlőtornyot, szeletelj újra, majd nyomtass ismét." +msgstr "A sima Timelapse mód be van kapcsolva, a törlőtorony azonban nincs, ami nyomtatási hibákat okozhat. Kapcsold be a törlőtornyot, szeletelj újra, majd nyomtass ismét." msgid "Expand sidebar" msgstr "Az oldalsáv kibontása" @@ -8024,7 +8028,7 @@ msgid "The 3MF file was generated by BambuStudio, loading geometry data only." msgstr "A 3MF fájlt a BambuStudio hozta létre, csak a geometriai adatok töltődnek be." msgid "This project was created with an OrcaSlicer 2.3.1-alpha and uses infill rotation template settings that may not work properly with your current infill pattern. This could result in weak support or print quality issues." -msgstr "Ez a projekt OrcaSlicer 2.3.1-alpha verzióval készült, és olyan kitöltésforgatási sablonbeállításokat használ, amelyek lehet, hogy nem működnek megfelelően a jelenlegi kitöltési mintával. Ez gyenge támaszt vagy nyomtatási minőségi problémákat okozhat." +msgstr "Ez a projekt az OrcaSlicer 2.3.1-alpha verziójával készült, és olyan kitöltésforgatási sablonbeállításokat használ, amelyek a jelenlegi kitöltési mintával nem feltétlenül működnek megfelelően. Ez gyenge alátámasztást vagy nyomtatási hibákat okozhat." msgid "Would you like OrcaSlicer to automatically fix this by clearing the rotation template settings?" msgstr "Szeretnéd, hogy az OrcaSlicer ezt automatikusan javítsa a forgatási sablonbeállítások törlésével?" @@ -8134,7 +8138,7 @@ msgid "Connected printer is %s. It must match the project preset for printing.\n msgstr "A csatlakoztatott nyomtató: %s. Ennek egyeznie kell a projekt nyomtatásához használt beállítással.\n" msgid "Do you want to sync the printer information and automatically switch the preset?" -msgstr "Szeretnéd szinkronizálni a nyomtató adatait, és automatikusan átváltani a beállítást?" +msgstr "Szeretnéd szinkronizálni a nyomtató adatait és automatikusan átváltani a beállítást?" msgid "The file does not contain any geometry data." msgstr "A fájl nem tartalmaz geometriai adatokat." @@ -8225,7 +8229,7 @@ msgid "Select a new file" msgstr "Válassz egy új fájlt" msgid "File for the replacement wasn't selected" -msgstr "A cserefájl nem lett kiválasztva" +msgstr "Nincs kiválasztva cserefájl" # AI Translated msgid "Replace with 3D file" @@ -8240,21 +8244,21 @@ msgstr "A cseréhez nem lett mappa kiválasztva" msgid "Replaced with 3D files from directory:\n" msgstr "Cserélve a mappából származó 3D fájlokra:\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ Kihagyva %1%: azonos fájl.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ %s kihagyva: azonos fájl.\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ Kihagyva %1%: a fájl nem létezik.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ %s kihagyva: a fájl nem létezik.\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ Kihagyva %1%: a csere sikertelen.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ %s kihagyva: a csere sikertelen.\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ Lecserélve: %1%.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔%s lecserélve.\n" msgid "Replaced volumes" msgstr "Lecserélt térfogatok" @@ -8298,7 +8302,7 @@ msgid "Slicing Plate %d" msgstr "%d tálca szeletelése" msgid "Please resolve the slicing errors and publish again." -msgstr "Kérlek, orvosold a szeletelési hibákat, és próbáld meg újra." +msgstr "Kérlek, javítsd ki a szeletelési hibákat, majd tedd közzé újra." msgid "Network plug-in switched successfully." msgstr "A hálózati bővítmény sikeresen átváltva." @@ -8360,7 +8364,7 @@ msgid "Download failed; unknown file format." msgstr "Letöltés sikertelen, ismeretlen fájlformátum." msgid "Downloading project..." -msgstr "projekt letöltése ..." +msgstr "Projekt letöltése..." msgid "Download failed; File size exception." msgstr "Letöltés sikertelen, fájlméret kivétel." @@ -8370,7 +8374,7 @@ msgid "Project downloaded %d%%" msgstr "Projekt letöltve %d%%" msgid "Importing to Orca Slicer failed. Please download the file and manually import it." -msgstr "Az Orca Slicerbe importálás sikertelen. Töltsd le a fájlt és manuálisan importáljad." +msgstr "Az Orca Slicerbe importálás sikertelen. Töltsd le a fájlt, majd importáld kézzel." # AI Translated msgid "INFO:" @@ -8461,7 +8465,7 @@ msgstr "Szeletelt fájl mentése mint:" #, c-format, boost-format msgid "The file %s has been sent to the printer's storage space and can be viewed on the printer." -msgstr "A(z) %s fájl elküldésre került a nyomtatóra, és megtekinthető a nyomtatón." +msgstr "A(z) %s fájlt elküldtük a nyomtató tárhelyére. A fájl a nyomtatón tekinthető meg." msgid "The nozzle type is not set. Please set the nozzle and try again." msgstr "A fúvókatípus nincs beállítva. Állítsd be a fúvókát, majd próbáld újra." @@ -8792,7 +8796,7 @@ msgid "Units" msgstr "Mértékegység" msgid "Home" -msgstr "Haza" +msgstr "Kezdőlap" msgid "Default page" msgstr "Alapértelmezett oldal" @@ -9210,6 +9214,21 @@ msgstr "Alsó rétegek elhalványítása" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "A rétegcsúszka mozgatásakor a szeletelt előnézetben az aktuális réteg alatti rétegeket sötétítve jeleníti meg, így csak az éppen megtekintett réteg látszik teljes fényerővel." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Elhalványított rétegek fényereje" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"Milyen fényesen jelenjenek meg az elhalványított rétegek, ha az \"Alsó rétegek elhalványítása\" be van kapcsolva.\n" +"A 99% alig sötétít, a 0% feketére vált. A felső határ 99%, mert a 100% ugyanaz lenne, mint az opció kikapcsolása." + msgid "Login region" msgstr "Régió" @@ -9292,7 +9311,7 @@ msgid "Select the network plug-in version to use" msgstr "A használandó hálózati bővítmény verzió kiválasztása" msgid "Associate files to OrcaSlicer" -msgstr "Fájlok társítása a OrcaSlicerhoz" +msgstr "Fájlok társítása az OrcaSlicerhez" # AI Translated msgid "File associations for the Microsoft Store version are managed by Windows Settings." @@ -9303,10 +9322,10 @@ msgid "Open Windows Default Apps Settings" msgstr "A Windows alapértelmezett alkalmazások beállításainak megnyitása" msgid "Associate 3MF files to OrcaSlicer" -msgstr ".3mf fájlok társítása a OrcaSlicerhoz" +msgstr ".3mf fájlok társítása az OrcaSlicerhez" msgid "If enabled, this sets OrcaSlicer as the default application to open 3MF files." -msgstr "Ha engedélyezve van, a OrcaSlicer-t állítja be alapértelmezett alkalmazásként a 3MF file fájlok megnyitásához" +msgstr "Bekapcsolva az OrcaSlicert állítja be alapértelmezett alkalmazásként a 3MF-fájlok megnyitásához" msgid "Associate DRC files to OrcaSlicer" msgstr "DRC fájlok társítása OrcaSlicerhez" @@ -9315,16 +9334,16 @@ msgid "If enabled, sets OrcaSlicer as default application to open DRC files." msgstr "Ha engedélyezve van, az OrcaSlicer lesz az alapértelmezett alkalmazás DRC fájlok megnyitásához." msgid "Associate STL files to OrcaSlicer" -msgstr ".stl fájlok társítása a OrcaSlicerhoz" +msgstr ".stl fájlok társítása az OrcaSlicerhez" msgid "If enabled, this sets OrcaSlicer as the default application to open STL files." -msgstr "Ha engedélyezve van, a OrcaSlicer-t állítja be alapértelmezett alkalmazásként az .stl fájlok megnyitásához" +msgstr "Bekapcsolva az OrcaSlicert állítja be alapértelmezett alkalmazásként az .stl fájlok megnyitásához" msgid "Associate STEP files to OrcaSlicer" -msgstr ".step/.stp fájlok társítása a OrcaSlicerhoz" +msgstr ".step/.stp fájlok társítása az OrcaSlicerhez" msgid "If enabled, this sets OrcaSlicer as the default application to open STEP files." -msgstr "Ha engedélyezve van, a OrcaSlicer-t állítja be alapértelmezett alkalmazásként a .step fájlok megnyitásához" +msgstr "Bekapcsolva az OrcaSlicert állítja be alapértelmezett alkalmazásként a .step fájlok megnyitásához" msgid "Associate web links to OrcaSlicer" msgstr "Webhivatkozások társítása OrcaSlicerhez" @@ -9583,7 +9602,7 @@ msgid "Jump to model publish web page" msgstr "Ugrás a modell közzététele weboldalra" msgid "Note: The preparation may take several minutes. Please be patient." -msgstr "Megjegyzés: Az előkészítés több percig is eltarthat. Kérlek várj." +msgstr "Megjegyzés: Az előkészítés több percig is eltarthat. Kérlek, várj." msgid "Publish" msgstr "Közzététel" @@ -9694,7 +9713,7 @@ msgid "Not satisfied with the grouping of filaments? Regroup and slice ->" msgstr "Nem elégedett a filamentek csoportosításával? Csoportosítsd újra és szeleteld ->" msgid "Manually change external spool during printing for multi-color printing" -msgstr "Többszínű nyomtatáshoz manuálisan cseréld a külső tekercset nyomtatás közben" +msgstr "Többszínű nyomtatáskor kézzel kell cserélni a külső tekercset" msgid "Multi-color with external" msgstr "Többszínű nyomtatás külső tekercssel" @@ -9708,7 +9727,7 @@ msgstr "A nyomtatási minőség biztosítása érdekében a szárítási hőmér # AI Translated msgid "Select timelapse storage location" -msgstr "Válaszd ki a timelapse tárolási helyét" +msgstr "Válaszd ki a Timelapse tárolási helyét" msgid "Auto Bed Leveling" msgstr "Automatikus asztalszintezés" @@ -9818,10 +9837,10 @@ msgstr "A kiválasztott nyomtató (%s) nem kompatibilis a nyomtatási fájl konf # AI Translated msgid "When spiral vase mode is enabled, machines with I3 structure will not generate timelapse videos." -msgstr "Ha a spirál (váza) mód be van kapcsolva, az I3 felépítésű gépek nem készítenek timelapse videót." +msgstr "Ha a spirál (váza) mód be van kapcsolva, az I3 felépítésű gépek nem készítenek Timelapse-videót." msgid "The current printer does not support timelapse in Traditional Mode when printing By-Object." -msgstr "Az aktuális nyomtató nem támogatja az időfelvételt hagyományos módban, ha a nyomtatás objektumonként történik." +msgstr "A jelenlegi nyomtató tárgyankénti nyomtatásnál nem támogatja a hagyományos Timelapse módot." # AI Translated msgid "I have checked the installed nozzle and want to print anyway." @@ -9863,7 +9882,7 @@ msgstr "Belső" # AI Translated #, c-format, boost-format msgid "%s space less than 20MB. Timelapse may not save properly. You can turn it off or" -msgstr "A(z) %s szabad területe kevesebb mint 20 MB. Előfordulhat, hogy a timelapse nem mentődik el megfelelően. Kikapcsolhatod, vagy" +msgstr "A(z) %s eszközön kevesebb mint 20 MB szabad hely van. Előfordulhat, hogy a Timelapse nem menthető megfelelően. Kikapcsolhatod, vagy" # AI Translated msgid "Clean up files" @@ -9871,15 +9890,15 @@ msgstr "Fájlok törlése" # AI Translated msgid "Low internal storage. This timelapse will overwrite the oldest video files." -msgstr "Kevés a belső tárhely. Ez a timelapse felülírja a legrégebbi videofájlokat." +msgstr "Kevés a belső tárhely. Ez a Timelapse felülírja a legrégebbi videofájlokat." # AI Translated msgid "Low external storage. This timelapse will overwrite the oldest video files." -msgstr "Kevés a külső tárhely. Ez a timelapse felülírja a legrégebbi videofájlokat." +msgstr "Kevés a külső tárhely. Ez a Timelapse felülírja a legrégebbi videofájlokat." # AI Translated msgid "Insufficient external storage for time-lapse photography. Connect to computer to delete files, or use a larger memory card." -msgstr "Nincs elég külső tárhely a timelapse felvételhez. Csatlakoztasd számítógéphez a fájlok törléséhez, vagy használj nagyobb memóriakártyát." +msgstr "Nincs elég külső tárhely a Timelapse-felvételhez. A fájlok törléséhez csatlakoztasd a számítógéphez, vagy használj nagyobb memóriakártyát." # AI Translated msgid "Storage Space Not Enough" @@ -9921,11 +9940,11 @@ msgstr "Jelenleg nincs elég elérhető fejegység." # AI Translated msgid "Please complete the hotend rack setup and try again." -msgstr "Kérlek, fejezd be a fejegységtartó beállítását, és próbáld újra." +msgstr "Kérlek, fejezd be a fejegységtartó beállítását, majd próbáld újra." # AI Translated msgid "Please refresh the nozzle information and try again." -msgstr "Kérlek, frissítsd a fúvókaadatokat, és próbáld újra." +msgstr "Kérlek, frissítsd a fúvókaadatokat, majd próbáld újra." # AI Translated msgid "Please re-slice to avoid filament waste." @@ -9950,7 +9969,7 @@ msgstr "A szerszámfej és a fejegységtartó tele van. Kérlek, távolíts el l #, c-format, boost-format msgid "The nozzle flow setting of %s(%s) doesn't match with the slicing file(%s). Please make sure the nozzle installed matches with settings in printer, then set the corresponding printer preset while slicing." -msgstr "A(z) %s(%s) fúvókaáramlási beállítása nem egyezik a szeletelési fájl értékével (%s). Győződj meg róla, hogy a beszerelt fúvóka megegyezik a nyomtató beállításaival, majd szeleteléskor állítsd be a megfelelő nyomtató-előbeállítást." +msgstr "A(z) %s(%s) fúvókaáramlási beállítása nem egyezik a szeletelési fájl értékével (%s). Győződj meg róla, hogy a beszerelt fúvóka megfelel a nyomtatóbeállításoknak, majd szeleteléskor válaszd ki a megfelelő nyomtatóbeállítást." msgid "Tips: If you changed your nozzle of your printer lately, please go to 'Device -> Printer parts' to change your nozzle setting." msgstr "Tipp: Ha nemrég cseréltél fúvókát a nyomtatón, lépj az 'Eszköz -> Nyomtató alkatrészei' menübe, és módosítsd a fúvóka beállítását." @@ -9972,7 +9991,7 @@ msgstr "A jelenlegi anyag keménysége (%s) meghaladja a(z) %s (%s) keménység # AI Translated msgid "Your current firmware version cannot start this print job. Please update to the latest version and try again." -msgstr "A jelenlegi firmware-verzió nem tudja elindítani ezt a nyomtatási feladatot. Kérlek, frissíts a legújabb verzióra, és próbáld újra." +msgstr "Ezzel a firmware-verzióval nem indítható el a nyomtatási feladat. Frissíts a legújabb verzióra, majd próbáld újra." # AI Translated #, c-format, boost-format @@ -9981,7 +10000,7 @@ msgstr "A jelenlegi anyag (%s) keménysége meghaladja a következő keménység # AI Translated msgid "Some filaments may switch between extruders during printing. Manual K-value calibration cannot be applied throughout the entire print, which may affect print quality. Enabling Flow Dynamics Calibration is recommended." -msgstr "Egyes filamentek nyomtatás közben extrudert válthatnak. A kézi K-érték kalibrálás nem alkalmazható a teljes nyomtatás során, ami befolyásolhatja a nyomtatási minőséget. Javasolt a dinamikus anyagáramlás-kalibrálás bekapcsolása." +msgstr "Egyes filamentek nyomtatás közben extrudert válthatnak. A kézi K-érték kalibrálás nem alkalmazható a teljes nyomtatás során, ami ronthatja a nyomtatási minőséget. Javasolt az áramlásdinamika-kalibrálás bekapcsolása." # AI Translated msgid "There is stringing-prone filament in this file. For best print quality, we recommend switching nozzle clumping detection to Auto mode." @@ -10001,14 +10020,14 @@ msgstr "[ %s ] magas hőmérsékletű környezetben történő nyomtatást igén #, c-format, boost-format msgid "The filament on %s may soften. Please unload." -msgstr "A(z) %s filament meglágyulhat. Kérlek, töltsd ki." +msgstr "A(z) %s filament meglágyulhat. Kérlek, vedd ki a filamentet." #, c-format, boost-format msgid "The filament on %s is unknown and may soften. Please set filament." msgstr "A(z) %s filament ismeretlen és meglágyulhat. Állítsd be a filamentet." msgid "Unable to automatically match to suitable filament. Please click to manually match." -msgstr "Nem sikerült automatikusan megfelelő filamentet párosítani. Kattints a manuális párosításhoz." +msgstr "Nem sikerült automatikusan megfelelő filamentet párosítani. Kattints rá a kézi párosításhoz." msgid "Install toolhead enhanced cooling fan to prevent filament softening." msgstr "Szerelj fel nyomtatófejhez való megerősített hűtőventilátort a filament meglágyulásának megelőzéséhez." @@ -10062,7 +10081,7 @@ msgid "Please do not mix-use the Ext with AMS." msgstr "Kérlek, ne használd vegyesen az Ext-et az AMS-sel." msgid "Invalid nozzle information, please refresh or manually set nozzle information." -msgstr "Érvénytelen fúvóka-információ, frissítsd vagy állítsd be manuálisan a fúvókaadatokat." +msgstr "Érvénytelenek a fúvóka adatai. Frissítsd őket, vagy add meg az adatokat kézzel." msgid "Storage needs to be inserted before printing via LAN." msgstr "LAN-on történő nyomtatás előtt be kell helyezni a tárolót." @@ -10080,13 +10099,13 @@ msgid "Cannot send a print job for an empty plate." msgstr "Nem küldhetsz nyomtatási feladatot egy üres tálcával." msgid "Storage needs to be inserted to record timelapse." -msgstr "Időfelvétel rögzítéséhez be kell helyezni a tárolót." +msgstr "Timelapse-felvételhez be kell helyezni a tárolót." msgid "You have selected both external and AMS filaments for an extruder. You will need to manually switch the external filament during printing." -msgstr "Egy extruderhez külső és AMS filamentet is kiválasztottál. Nyomtatás közben manuálisan kell váltanod a külső filamentet." +msgstr "Egy extruderhez külső és AMS-filamentet is kiválasztottál. Nyomtatás közben kézzel kell cserélned a külső filamentet." msgid "TPU 90A/TPU 85A is too soft and does not support automatic Flow Dynamics calibration." -msgstr "A TPU 90A/TPU 85A túl puha, nem támogatja az automatikus Flow Dynamics kalibrálást." +msgstr "A TPU 90A/TPU 85A túl puha, ezért nem támogatja az automatikus áramlásdinamika-kalibrálást." msgid "Set dynamic flow calibration to 'OFF' to enable custom dynamic flow value." msgstr "Állítsd a dinamikus áramlás kalibrálást 'KI'-re az egyéni dinamikus áramlásérték engedélyezéséhez." @@ -10126,7 +10145,7 @@ msgid "External Storage" msgstr "Külső tároló" msgid "Upload file timeout, please check if the firmware version supports it." -msgstr "Fájlfeltöltés időtúllépés, ellenőrizd, hogy a firmware verzió támogatja-e." +msgstr "A fájl feltöltése időtúllépés miatt megszakadt. Ellenőrizd, hogy a firmware-verzió támogatja-e a feltöltést." msgid "Connection timed out, please check your network." msgstr "Kapcsolat időtúllépés, ellenőrizd a hálózatot." @@ -10154,7 +10173,7 @@ msgid "Sending..." msgstr "Küldés..." msgid "File upload timed out. Please check if the firmware version supports this operation or verify if the printer is functioning properly." -msgstr "Fájlfeltöltés időtúllépés. Ellenőrizd, hogy a firmware verzió támogatja-e ezt a műveletet, és hogy a nyomtató megfelelően működik-e." +msgstr "A fájl feltöltése időtúllépés miatt megszakadt. Ellenőrizd, hogy a firmware-verzió támogatja-e ezt a műveletet, és hogy a nyomtató megfelelően működik-e." # AI Translated msgid "Sending failed, please try again!" @@ -10231,7 +10250,7 @@ msgid "Terms and Conditions" msgstr "Felhasználási feltételek" msgid "Thank you for purchasing a Bambu Lab device. Before using your Bambu Lab device, please read the terms and conditions. By clicking to agree to use your Bambu Lab device, you agree to abide by the Privacy Policy and Terms of Use (collectively, the \"Terms\"). If you do not comply with or agree to the Bambu Lab Privacy Policy, please do not use Bambu Lab equipment and services." -msgstr "Köszönjük, hogy Bambu Lab eszközt vásároltál. A Bambu Lab eszköz használata előtt kérlek, olvasd el a felhasználási feltételeket. Azzal, hogy rákattintasz az elfogadásra, hozzájárulsz ahhoz, hogy a Bambu Lab eszközt a adatvédelmi irányelvek és a Felhasználási feltételek (együttesen: \"Feltételek\") szerint használd. Ha nem fogadod el vagy nem tartod be a Bambu Lab adatvédelmi irányelvek rendelkezéseit, kérlek, ne használd a Bambu Lab eszközöket és szolgáltatásokat." +msgstr "Köszönjük, hogy Bambu Lab eszközt vásároltál. A Bambu Lab eszköz használata előtt kérlek, olvasd el a felhasználási feltételeket. Azzal, hogy rákattintasz az elfogadásra, hozzájárulsz ahhoz, hogy a Bambu Lab eszközt az adatvédelmi irányelvek és a Felhasználási feltételek (együttesen: \"Feltételek\") szerint használd. Ha nem fogadod el vagy nem tartod be a Bambu Lab adatvédelmi irányelvek rendelkezéseit, kérlek, ne használd a Bambu Lab eszközöket és szolgáltatásokat." msgid "and" msgstr "és" @@ -10240,14 +10259,14 @@ msgid "Privacy Policy" msgstr "Adatvédelmi szabályzat" msgid "We ask for your help to improve everyone's printer" -msgstr "Kérlek a segítségedet, hogy mindenki nyomtatója jobb legyen" +msgstr "Segíts, hogy mindenki nyomtatója jobb legyen" msgid "Statement about User Experience Improvement Program" msgstr "Nyilatkozat a Felhasználói Élmény Fejlesztési Programról" #, c-format, boost-format msgid "In the 3D Printing community, we learn from each other's successes and failures to adjust our own slicing parameters and settings. %s follows the same principle and uses machine learning to improve its performance from the successes and failures of the vast number of prints by our users. We are training %s to be smarter by feeding them the real-world data. If you are willing, this service will access information from your error logs and usage logs, which may include information described in Privacy Policy. We will not collect any Personal Data by which an individual can be identified directly or indirectly, including without limitation names, addresses, payment information, or phone numbers. By enabling this service, you agree to these terms and the statement about Privacy Policy." -msgstr "A 3D nyomtatási közösségben egymás sikereiből és hibáiból tanulunk, hogy saját szeletelési paramétereinket és beállításainkat finomhangoljuk. %s ugyanezt az elvet követi, és gépi tanulást használ arra, hogy a felhasználóink nagyszámú nyomtatásának sikereiből és hibáiból javítsa a teljesítményét. Valós adatokkal tesszük okosabbá %s működését. Ha hozzájárulsz, ez a szolgáltatás hozzáfér az error logokhoz és a használati naplókhoz, amelyek az adatvédelmi irányelvek által leírt információkat is tartalmazhatják. Nem gyűjtünk olyan személyes adatokat, amelyek alapján egy személy közvetlenül vagy közvetve azonosítható, ideértve korlátozás nélkül a neveket, címeket, fizetési információkat vagy telefonszámokat. A szolgáltatás engedélyezésével elfogadod ezeket a feltételeket és a adatvédelmi irányelvekre vonatkozó nyilatkozatot." +msgstr "A 3D nyomtatási közösségben egymás sikereiből és hibáiból tanulunk, hogy saját szeletelési paramétereinket és beállításainkat finomhangoljuk. %s ugyanezt az elvet követi és gépi tanulást használ arra, hogy a felhasználóink nagyszámú nyomtatásának sikereiből és hibáiból javítsa a teljesítményét. Valós adatokkal tesszük okosabbá %s működését. Ha hozzájárulsz, ez a szolgáltatás hozzáfér a hibanaplókhoz és a használati naplókhoz, amelyek az adatvédelmi irányelvek által leírt információkat is tartalmazhatják. Nem gyűjtünk olyan személyes adatokat, amelyek alapján egy személy közvetlenül vagy közvetve azonosítható, ideértve korlátozás nélkül a neveket, címeket, fizetési információkat vagy telefonszámokat. A szolgáltatás engedélyezésével elfogadod ezeket a feltételeket és az adatvédelmi irányelvekre vonatkozó nyilatkozatot." msgid "Statement on User Experience Improvement Plan" msgstr "Nyilatkozat a Felhasználói Élmény Fejlesztési Tervről" @@ -10296,7 +10315,7 @@ msgid "Prime tower is required for nozzle changing. There may be flaws on the mo msgstr "A fúvókacsere miatt szükség van a törlőtoronyra. Nélküle előfordulhatnak hibák a nyomtatott tárgyon. Biztos, hogy kikapcsolod a törlőtornyot?" msgid "A prime tower is required for smooth timelapse mode. There may be flaws on the model without a prime tower. Are you sure you want to disable the prime tower?" -msgstr "A sima időfelvétel miatt szükség van a törlőtoronyra. Nélküle előfordulhatnak hibák a nyomtatott tárgyon. Biztos, hogy kikapcsolod a törlőtornyot?" +msgstr "A sima Timelapse módhoz törlőtorony szükséges. Nélküle hibák jelenhetnek meg a nyomtatott tárgyon. Biztosan kikapcsolod a törlőtornyot?" msgid "A prime tower is required for clumping detection. There may be flaws on the model without prime tower. Are you sure you want to disable prime tower?" msgstr "A csomósodás-észleléshez szükség van a törlőtoronyra. Nélküle előfordulhatnak hibák a nyomtatott tárgyon. Biztos, hogy kikapcsolod a törlőtornyot?" @@ -10311,7 +10330,7 @@ msgid "Enabling both precise Z height and the prime tower may cause slicing erro msgstr "A pontos Z magasság és a törlőtorony egyidejű engedélyezése szeletelési hibákat okozhat. Továbbra is engedélyezi a pontos Z magasságot?" msgid "A prime tower is required for smooth timelapse mode. There may be flaws on the model without prime tower. Do you want to enable the prime tower?" -msgstr "A sima időfelvétel miatt szükség van a törlőtoronyra. Nélküle előfordulhatnak hibák a nyomtatott tárgyon. Engedélyezed a törlőtornyot?" +msgstr "A sima Timelapse módhoz törlőtorony szükséges. Nélküle hibák jelenhetnek meg a nyomtatott tárgyon. Bekapcsolod a törlőtornyot?" msgid "Still print by object?" msgstr "Továbbra is tárgyanként szeretnél nyomtatni?" @@ -10336,8 +10355,8 @@ msgid "" "No - Do not change these settings for me." msgstr "" "Automatikusan megváltoztatod ezeket a beállításokat?\n" -"Igen - Módosítsa ezeket a beállításokat\n" -"Nem - Ne változtassa meg a beállításokat" +"Igen - Módosítsd ezeket a beállításokat\n" +"Nem - Ne módosítsd a beállításokat" msgid "" "When using soluble material for the support interface, we recommend the following settings:\n" @@ -10355,7 +10374,7 @@ msgid "Are you sure you want to enable this option?" msgstr "Biztos, hogy engedélyezed ezt az opciót?" msgid "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. Please proceed with caution and thoroughly check for any potential printing issues. Are you sure you want to enable this option?" -msgstr "A kitöltési minták általában úgy vannak kialakítva, hogy a forgatást automatikusan kezeljék a megfelelő nyomtatás és a kívánt hatás elérése érdekében (pl. Gyroid, Cubic). Az aktuális ritka kitöltési minta forgatása elégtelen alátámasztáshoz vezethet. Kérlek, körültekintően járj el, és alaposan ellenőrizd a lehetséges nyomtatási problémákat. Biztos, hogy engedélyezed ezt az opciót?" +msgstr "A kitöltési minták általában maguk kezelik a forgatást a megfelelő nyomtatás és a kívánt hatás elérése érdekében (pl. Gyroid, Cubic). A jelenlegi kitöltési minta elforgatása elégtelen alátámasztáshoz vezethet. Kérlek, járj el körültekintően, és alaposan ellenőrizd a lehetséges nyomtatási problémákat. Biztos, hogy engedélyezed ezt a beállítást?" msgid "" "Layer height is too small.\n" @@ -10382,7 +10401,9 @@ msgstr "Kísérleti funkció: Filamentcsere közben nagyobb távolságon törté msgid "" "When recording timelapse without toolhead, it is recommended to add a \"Timelapse Wipe Tower\" \n" "by right-click the empty position of build plate and choose \"Add Primitive\"->\"Timelapse Wipe Tower\"." -msgstr "Ha a nyomtatófej nélküli időfelvétel engedélyezve van, javasoljuk, hogy helyezz el a tálcán egy \"Időfelvétel törlőtornyot\". Ehhez kattints jobb gombbal a tálca egy üres részére, majd válaszd a \"Primitív hozzáadása\" -> \"Időfelvétel törlőtorony\" lehetőséget." +msgstr "" +"Ha nyomtatófej nélküli Timelapse-felvételt készítesz, érdemes hozzáadni egy „Timelapse törlőtornyot”.\n" +"Kattints jobb gombbal az asztal egy üres részére, majd válaszd a „Primitív hozzáadása” -> „Timelapse törlőtorony” lehetőséget." msgid "A copy of the current system preset will be created, which will be detached from the system preset." msgstr "Létrejön az aktuális rendszer-előbeállítás másolata, amely leválik a rendszer-előbeállításról." @@ -10391,7 +10412,7 @@ msgid "The current custom preset will be detached from the parent system preset. msgstr "Az aktuális egyéni-előbeállítás leválik a szülő rendszer-előbeállításáról." msgid "Modifications to the current profile will be saved." -msgstr "Az aktuális profil módosításai mentésre kerülnek." +msgstr "Menti az aktuális profil módosításait." msgid "" "This action is not revertible.\n" @@ -10485,7 +10506,7 @@ msgid "Overhang speed" msgstr "Sebesség túlnyúlásnál" msgid "This is the speed for various overhang degrees. Overhang degrees are expressed as a percentage of line width. 0 speed means no slowing down for the overhang degree range and wall speed is used" -msgstr "Nyomtatási sebesség a különböző mértékű túlnyúlásoknál. A túlnyúlás mértéke a vonalszélesség százalékában van kifejezve. A 0 sebesség azt jelenti, hogy nem történik lassítás, és a fal nyomtatási sebessége kerül alkalmazásra." +msgstr "Nyomtatási sebesség a különböző mértékű túlnyúlásoknál. A túlnyúlás mértéke a vonalszélesség százalékában van kifejezve. A 0 sebesség azt jelenti, hogy nincs lassítás, és a rendszer a fal nyomtatási sebességét használja." msgid "Set speed for external and internal bridges" msgstr "Sebesség beállítása a külső és belső hidakhoz" @@ -10576,7 +10597,7 @@ msgid "Recommended nozzle temperature range of this filament. 0 means not set" msgstr "Az ajánlott fúvóka hőmérséklet-tartomány ehhez a filamenthez. A 0 azt jelenti, hogy nincs beállítva" msgid "Flow ratio and Pressure Advance" -msgstr "Anyagáramlási arány és nyomáskiegyenlítés" +msgstr "Anyagáramlás és nyomáselőtolás" msgid "Print chamber temperature" msgstr "Nyomtatókamra hőmérséklete" @@ -10603,34 +10624,34 @@ msgid "Nozzle temperature when printing" msgstr "Fúvóka hőmérséklete nyomtatáskor" msgid "Bed temperature when the Cool Plate SuperTack is installed. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." -msgstr "Asztalhőmérséklet a Cool Plate SuperTack használatakor. A 0 érték azt jelenti, hogy a filament nem támogatja a Cool Plate SuperTack-re történő nyomtatást." +msgstr "Asztalhőmérséklet a SuperTack hűvös tálca használatakor. A 0 azt jelenti, hogy a filament nem nyomtatható erre a tálcára." # AI Translated msgid "Cool Plate" msgstr "Hűvös tálca" msgid "This is the bed temperature when the Cool Plate is installed. A value of 0 means the filament does not support printing on the Cool Plate." -msgstr "Asztalhőmérséklet a hideg tálca használatával. A 0 érték azt jelenti, hogy a filament nem támogatja a Cool Plate-re történő nyomtatást" +msgstr "Asztalhőmérséklet a hűvös tálca használatakor. A 0 azt jelenti, hogy a filament nem nyomtatható erre a tálcára." # AI Translated msgid "Textured Cool Plate" msgstr "Texturált hűvös tálca" msgid "This is the bed temperature when the Textured Cool Plate is installed. A value of 0 means the filament does not support printing on the Textured Cool Plate." -msgstr "Asztalhőmérséklet a Textured Cool Plate használatakor. A 0 érték azt jelenti, hogy a filament nem támogatja a Textured Cool Plate-re történő nyomtatást." +msgstr "Asztalhőmérséklet a texturált hűvös tálca használatakor. A 0 azt jelenti, hogy a filament nem nyomtatható erre a tálcára." msgid "This is the bed temperature when the engineering plate is installed. A value of 0 means the filament does not support printing on the Engineering Plate." -msgstr "Asztalhőmérséklet a mérnöki tálca használatával. A 0 érték azt jelenti, hogy a filament nem támogatja az Engineering Plate-re történő nyomtatást" +msgstr "Asztalhőmérséklet a műszaki tálca használatakor. A 0 azt jelenti, hogy a filament nem nyomtatható erre a tálcára." msgid "Smooth PEI Plate / High Temp Plate" msgstr "Sima PEI tálca / magas hőmérsékletű tálca" msgid "This is the bed temperature when the Smooth PEI Plate/High Temperature Plate is installed. A value of 0 means the filament does not support printing on the Smooth PEI Plate/High Temp Plate." -msgstr "Az asztal hőmérséklete Smooth PEI / High Temperature tálca használatakor. A 0 érték azt jelenti, hogy a filament nem támogatja Smooth PEI / High Temperature tálcára történő nyomtatást" +msgstr "Asztalhőmérséklet a sima PEI / magas hőmérsékletű tálca használatakor. A 0 azt jelenti, hogy a filament nem nyomtatható ezekre a tálcákra." # AI Translated msgid "This is the bed temperature when the Textured PEI Plate is installed. A value of 0 means the filament does not support printing on the Textured PEI Plate." -msgstr "Asztalhőmérséklet a texturált PEI tálca használatával. A 0 érték azt jelenti, hogy a filament nem támogatja a Textured PEI Plate-re történő nyomtatást" +msgstr "Asztalhőmérséklet a texturált PEI tálca használatakor. A 0 azt jelenti, hogy a filament nem nyomtatható erre a tálcára." msgid "Volumetric speed limitation" msgstr "Volumetrikus sebességhatár" @@ -10744,13 +10765,13 @@ msgid "Layer change G-code" msgstr "Rétegváltás G-kód" msgid "Timelapse G-code" -msgstr "Időfelvétel G-kód" +msgstr "Timelapse G-kód" msgid "Clumping Detection G-code" msgstr "Csomósodásészlelés G-kód" msgid "Change filament G-code" -msgstr "Filament csere G-kód" +msgstr "Filamentcsere G-kód" msgid "Pause G-code" msgstr "Szünet G-kód" @@ -10858,8 +10879,8 @@ msgstr "A más beállítások által örökölt beállítások nem törölhetők msgid "The following presets inherit this preset." msgid_plural "The following preset inherits this preset." -msgstr[0] "A következő profilok öröklik ezt a profilt." -msgstr[1] "A következő profil örökli ezt a profilt." +msgstr[0] "A következő profil örökli ezt a profilt." +msgstr[1] "A következő profilok öröklik ezt a profilt." #. TRN Remove/Delete #, boost-format @@ -11008,9 +11029,9 @@ msgid "" "will be transferred to\n" "\"%2%\"." msgstr "" -"Minden „Új érték” beállítás módosítva\n" +"A(z)\n" "\"%1%\"\n" -"címre kerülnek át\n" +"beállításban módosított összes „Új érték” átkerül ide:\n" "\"%2%\"." #, boost-format @@ -11019,15 +11040,15 @@ msgid "" "\"%1%\"\n" "and \"%2%\" will open without any changes." msgstr "" -"Minden „Új érték” beállítás mentésre kerül\n" +"Az összes „Új érték” mentési helye:\n" "\"%1%\"\n" -"és a \"%2%\" változtatás nélkül nyílik meg." +"A(z) \"%2%\" módosítás nélkül nyílik meg." msgid "Click the right mouse button to display the full text." msgstr "Kattints a jobb egérgombbal a teljes szöveg megjelenítéséhez." msgid "No changes will be saved." -msgstr "A módosítások nem kerülnek mentésre" +msgstr "Nem menti a módosításokat." msgid "All changes will be discarded." msgstr "Minden változtatás el lesz vetve." @@ -11273,8 +11294,8 @@ msgid "" "The color has been selected, you can choose OK \n" " to continue or manually adjust it." msgstr "" -"A szín ki lett választva, az OK gombbal folytathatod,\n" -" vagy akár manuálisan is módosíthatod." +"A szín ki van választva. Az OK gombbal folytathatod, \n" +" vagy kézzel is módosíthatod." msgid "—> " msgstr "—> " @@ -11385,10 +11406,10 @@ msgid "The selected printer (%s) is incompatible with the chosen printer profile msgstr "A kiválasztott nyomtató (%s) nem kompatibilis a szeletelőben kiválasztott nyomtatóprofillal (%s)." msgid "Timelapse is not supported because Print sequence is set to \"By object\"." -msgstr "Az időfelvétel nem támogatott ebben a módban, mert a nyomtatási sorrend \"Tárgyanként\" értékre van állítva." +msgstr "A Timelapse ebben a módban nem támogatott, mert a nyomtatási sorrend \"Tárgyanként\" értékre van állítva." msgid "You selected external and AMS filament at the same time in an extruder, you will need manually change external filament." -msgstr "Ugyanabban az extruderben egyszerre választottál külső és AMS filamentet, ezért a külső filamentet manuálisan kell majd cserélned." +msgstr "Ugyanabban az extruderben egyszerre választottál külső és AMS-filamentet, ezért nyomtatás közben kézzel kell cserélned a külső filamentet." msgid "Successfully synchronized nozzle information." msgstr "A fúvókainformációk szinkronizálása sikerült." @@ -11469,7 +11490,7 @@ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please ins msgstr "A natív Wayland élőképhez a GStreamer GTK videonyelő szükséges. Telepítsd a gtksink beépülő modult a GStreamerhez, majd indítsd újra az OrcaSlicert." msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Nem sikerült inicializálni a natív Wayland GStreamer videonyelőt.Ellenőrizd a GStreamer GTK bővítmény telepítését." +msgstr "Nem sikerült inicializálni a natív Wayland GStreamer videonyelőt. Ellenőrizd a GStreamer GTK bővítmény telepítését." msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" msgstr "Ehhez a művelethez Windows Media Player szükséges. Szeretnéd engedélyezni a \"Windows Media Player\"-t az operációs rendszerben?" @@ -11478,16 +11499,16 @@ msgid "BambuSource has not correctly been registered for media playing! Press Ye msgstr "A BambuSource nincs megfelelően regisztrálva médialejátszáshoz. Kattints az Igen gombra az újbóli regisztráláshoz. Kétszer kapsz majd megerősítési kérést." msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Hiányzó BambuSource komponens a média lejátszáshoz! Kérjük, telepítse újra az OrcaSlicert, vagy kérjen segítséget a közösségtől." +msgstr "A médialejátszáshoz szükséges BambuSource-összetevő hiányzik. Kérlek, telepítsd újra az OrcaSlicert, vagy kérj segítséget a közösségtől." msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Másik telepítésből származó BambuSource használata esetén a videólejátszás nem biztos, hogy megfelelően működik. Kattints az Igen gombra a javításhoz." +msgstr "Ha egy másik telepítésből származó BambuSource van használatban, előfordulhat, hogy a videólejátszás nem működik megfelelően. Kattints az Igen gombra a javításhoz." msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" msgstr "A rendszerből hiányoznak a GStreamer H.264 kodekjei, amelyek szükségesek a videolejátszáshoz. (Próbáld telepíteni a gstreamer1.0-plugins-bad vagy a gstreamer1.0-libav csomagokat, majd indítsd újra az Orca Slicert.)" msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." -msgstr "A cloud ügynök nem érhető el. Indítsd újra az OrcaSlicert és próbáljd újra." +msgstr "A felhőszolgáltatás nem érhető el. Indítsd újra az OrcaSlicert, majd próbáld újra." msgid "Bambu Network plug-in not detected." msgstr "A Bambu Network plug-in nem található." @@ -11649,7 +11670,7 @@ msgid "Gizmo scale" msgstr "Gizmo átméretezés" msgid "Gizmo place face on bed" -msgstr "Gizmo felület tárgyasztalra illesztése" +msgstr "Gizmo felület asztalra illesztése" msgid "Gizmo cut" msgstr "Gizmo vágás" @@ -11658,7 +11679,7 @@ msgid "Gizmo mesh boolean" msgstr "Gizmo modellháló logikai műveletek" msgid "Gizmo FDM paint-on fuzzy skin" -msgstr "Gizmo FDM bolyhos felület festése" +msgstr "Gizmo FDM barázdált felület festése" msgid "Gizmo SLA support points" msgstr "Gizmo SLA támaszpontok" @@ -11676,7 +11697,7 @@ msgid "Gizmo assemble" msgstr "Gizmo összeállítás" msgid "Gizmo brim ears" -msgstr "Gizmo karimás fülek" +msgstr "Gizmo peremfülek" msgid "Zoom in" msgstr "Zoom közelítés" @@ -11727,13 +11748,13 @@ msgid "Delete objects, parts, modifiers" msgstr "Objektumok, tárgyak, módosítók törlése" msgid "Select the object/part and press space to change the name" -msgstr "Válaszd ki az objektumot/tárgyat, és nyomd meg a szóközt a név megváltoztatásához" +msgstr "Válaszd ki az objektumot vagy alkatrészt, majd nyomd meg a szóközt a név megváltoztatásához" msgid "Mouse click" msgstr "Egérkattintás" msgid "Select the object/part and mouse click to change the name" -msgstr "Válaszd ki az objektumot/tárgyat, és kattints az egérrel a név megváltoztatásához" +msgstr "Válaszd ki az objektumot vagy alkatrészt, majd kattints a nevére az átnevezéshez" msgid "Objects List" msgstr "Tárgyak listája" @@ -11798,7 +11819,7 @@ msgid "A new Network plug-in (%s) is available. Do you want to install it?" msgstr "Új hálózati bővítmény (%s) érhető el. Szeretnéd telepíteni?" msgid "New version of Orca Slicer" -msgstr "A Orca Slicer új verziója" +msgstr "Az Orca Slicer új verziója" # AI Translated msgid "Check on Microsoft Store" @@ -11835,7 +11856,7 @@ msgid "2. If the IP and Access Code below are different from the actual values o msgstr "2. Ha az alábbi IP-cím és hozzáférési kód eltér a nyomtatón látható valós értékektől, javítsd ki őket." msgid "3. Please obtain the device SN from the printer side; it is usually found in the device information on the printer screen." -msgstr "3. Kérjük, szerezd be az eszköz sorozatszámát a nyomtatóról; ez általában a nyomtató kijelzőjén, az eszközinformációk között található." +msgstr "3. Kérlek, keresd meg az eszköz sorozatszámát a nyomtatón; ez általában a nyomtató kijelzőjén, az eszközinformációk között található." msgid "IP" msgstr "IP" @@ -11878,7 +11899,7 @@ msgid "The printer has already been bound." msgstr "A nyomtató már hozzá lett rendelve." msgid "The printer mode is incorrect, please switch to LAN Only." -msgstr "A nyomtató módja hibás, kérjük, állítsd LAN Only módra." +msgstr "A nyomtató módja hibás, kérlek, állítsd LAN Only módra." msgid "Connecting to printer... The dialog will close later" msgstr "Kapcsolódás a nyomtatóhoz... A párbeszédablak később bezárul" @@ -11943,7 +11964,7 @@ msgid "Update successful" msgstr "Sikeres frissítés" msgid "Hotends on Rack" -msgstr "Hotendek a tartón" +msgstr "Fejegységek a tartón" msgid "Are you sure you want to update? This will take about 10 minutes. Do not turn off the power while the printer is updating." msgstr "Biztos, hogy frissíteni akarsz? Ez körülbelül 10 percet vesz igénybe. Ne kapcsold ki a nyomtatót, amíg a frissítés tart." @@ -11953,7 +11974,7 @@ msgstr "Fontos frissítést találtunk, amelyet a nyomtatás előtt telepíteni # AI Translated msgid "The firmware version is abnormal. Repairing and updating are required before printing. Do you want to update now? You can also update later on the printer or update next time you start Orca Slicer." -msgstr "A firmware verziója rendellenes. A nyomtatás előtt javításra és frissítésre van szükség. Szeretnél frissíteni most? A frissítés később a nyomtatón, vagy az Orca Slicer következő indításakor is elvégezhető." +msgstr "A firmware-verzió hibás. Nyomtatás előtt javítani és frissíteni kell. Szeretnéd most frissíteni? Ezt később a nyomtatón vagy az Orca Slicer következő indításakor is megteheted." msgid "Extension Board" msgstr "Bővítőpanel" @@ -12011,7 +12032,7 @@ msgid "No object can be printed. It may be too small." msgstr "Objektum nem nyomtatható ki. Lehet, hogy túl kicsi." msgid "Your print is very close to the priming regions. Make sure there is no collision." -msgstr "A nyomtatás nagyon közel van az alapozó régiókhoz. Győződjön meg róla, hogy nincs ütközés." +msgstr "A nyomat nagyon közel van az előkészítő extrudálás területéhez. Ellenőrizd, hogy nem ütköznek-e." msgid "" "Failed to generate G-code for invalid custom G-code.\n" @@ -12038,7 +12059,7 @@ msgid "" "Check your firmware version and update your G-code flavor to ´Marlin 2´." msgstr "" "A rezgéskompenzációt a Marlin < 2.1.2 nem támogatja.\n" -"Ellenőrizd a firmware verzióját és állítsd a G-kód változatot „Marlin 2”-re" +"Ellenőrizd a firmware-verziót, majd állítsd a G-kód változatát „Marlin 2”-re" msgid "Input shaping is only supported by Klipper, RepRapFirmware and Marlin 2." msgstr "A rezgéskompenzációt csak a Klipper, a RepRapFirmware és a Marlin 2 támogatja" @@ -12192,7 +12213,7 @@ msgid "No extrusions under current settings." msgstr "A jelenlegi beállításokkal nincsenek extrudálások." msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." -msgstr "A sima időfelvétel funkció nem használható, ha a nyomtatás \"Tárgyanként\" sorrendre van állítva." +msgstr "A sima Timelapse nem használható, ha a nyomtatási sorrend \"Tárgyanként\"." msgid "Clumping detection is not supported when \"by object\" sequence is enabled." msgstr "A csomósodásészlelés nem támogatott, ha a nyomtatási sorrend \"Tárgyanként\" értékre van állítva." @@ -12222,7 +12243,7 @@ msgid "While the object %1% itself fits the build volume, its last layer exceeds msgstr "Bár a(z) %1% objektum önmagában belefér a nyomtatási térfogatba, az utolsó rétege túllépi a maximális nyomtatási magasságot." msgid "You might want to reduce the size of your model or change current print settings and retry." -msgstr "Lehet, hogy csökkentened kell a modell méretét, vagy módosítanod kell a jelenlegi nyomtatási beállításokat, majd újra próbálkoznod." +msgstr "Próbáld meg csökkenteni a modell méretét vagy módosítani a jelenlegi nyomtatási beállításokat, majd próbáld újra." msgid "Variable layer height is not supported with Organic supports." msgstr "A változó rétegmagasság nem működik az organikus támaszokkal." @@ -12237,7 +12258,7 @@ msgid "Ooze prevention is only supported with the wipe tower when 'single_extrud msgstr "A szivárgás megelőzése csak akkor támogatott a törlőtoronnyal, ha a 'single_extruder_multi_material' ki van kapcsolva." msgid "The prime tower is currently only supported for the Marlin, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors." -msgstr "A törlőtorony jelenleg csak a Marlin, RepRap/Sprinter, RepRapFirmware és Repetier G-kód változatokkal használható." +msgstr "A törlőtorony jelenleg csak a Marlin, RepRap/Sprinter, RepRapFirmware és Repetier G-kód-változatokkal használható." msgid "A prime tower is not supported in “By object” print." msgstr "A törlőtorony nem támogatott \"Tárgyanként\" nyomtatás esetén." @@ -12282,7 +12303,7 @@ msgid "For Organic supports, two walls are supported only with the Hollow/Defaul msgstr "Organikus támaszok esetén a két fal csak Üreges/Alapértelmezett alapmintázattal támogatott." msgid "The Lightning base pattern is not supported by this support type; Rectilinear will be used instead." -msgstr "A Lightning alapmintázat ennél a támasztípusnál nem támogatott; helyette egyenes vonalú mintázat lesz használva." +msgstr "Ez a támasztípus nem támogatja a Villám alapmintázatot; helyette egyenes vonalú mintázatot használ." msgid "Organic support tree tip diameter must not be smaller than support material extrusion width." msgstr "Az organikus támaszfa csúcsátmérője nem lehet kisebb, mint a támaszanyag extrudálási szélessége." @@ -12294,7 +12315,7 @@ msgid "Organic support branch diameter must not be smaller than support tree tip msgstr "Az organikus támaszfa ágának átmérője nem lehet kisebb, mint a támaszfa csúcsának átmérője." msgid "The Hollow base pattern is not supported by this support type; Rectilinear will be used instead." -msgstr "Az üreges alap mintát ez a támasztéktípus nem támogatja; helyette az egyenes vonalú lesz használva." +msgstr "Ez a támasztípus nem támogatja az üreges alapmintázatot; helyette egyenes vonalú mintázatot használ." msgid "Support enforcers are used but support is not enabled. Please enable support." msgstr "Támasz kényszerítőket használtál, de a támaszok nincsenek engedélyezve. Kérlek, engedélyezd a támaszokat." @@ -12369,7 +12390,7 @@ msgstr "" "A nagyobb sebesség eléréséhez módosíthatod a machine_max_acceleration_travel értéket a nyomtató konfigurációjában." msgid "The precise wall option will be ignored for outer-inner or inner-outer-inner wall sequences." -msgstr "A pontos fal opció figyelmen kívül lesz hagyva külső-belső vagy belső-külső-belső fali sorrend esetén." +msgstr "A szeletelő figyelmen kívül hagyja a pontos fal beállítást Külső/Belső vagy Belső/Külső/Belső falsorrendnél." # AI Translated msgid "The Adaptive Pressure Advance model for one or more extruders may contain invalid values." @@ -12441,16 +12462,16 @@ msgid "Unprintable area in XY plane. For example, X1 Series printers use the fro msgstr "A nyomtatásra nem használható terület az XY síkban. Az X1 nyomtatók például a bal első sarkot használják a filament elvágására filamentcserét követően. A terület sokszögként van meghatározva a következő formátumban: XxY, XxY, ..." msgid "Bed custom texture" -msgstr "Egyedi tárgyasztal textúra" +msgstr "Egyedi asztaltextúra" msgid "Bed custom model" -msgstr "Egyedi tárgyasztal modell" +msgstr "Egyedi asztalmodell" msgid "Elephant foot compensation" msgstr "Elefántláb kompenzáció" msgid "This shrinks the first layer on the build plate to compensate for elephant foot effect." -msgstr "Zsugorítja a kezdőréteget a tárgyasztalon, hogy kompenzálja az elefántláb-hatást" +msgstr "Zsugorítja a kezdőréteget az asztalon, hogy kompenzálja az elefántláb-hatást" msgid "Elephant foot compensation layers" msgstr "Elefántláb-kompenzáció rétegei" @@ -12466,8 +12487,8 @@ msgid "" "The initial value for the second layer is set.\n" "Subsequent layers become linearly denser by the height specified in elefant_foot_compensation_layers." msgstr "" -"A belső szilárd töltés sűrűsége az elefánt lábrétegeinek kompenzálásához.\n" -"A második réteg kezdeti értéke van állítva.\n" +"A belső tömör kitöltés sűrűsége az elefántláb rétegeinek kompenzálásához.\n" +"A kezdeti értéket a második réteg használja.\n" "A következő rétegek lineárisan sűrűbbé válnak az elefant_foot_compensation_layers paraméterben megadott magassággal." msgid "This is the height for each layer. Smaller layer heights give greater accuracy but longer printing time." @@ -12487,13 +12508,13 @@ msgid "Maximum printable height of this extruder which is limited by mechanism o msgstr "Ennek az extrudernek a maximális nyomtatható magassága, amelyet a nyomtató mechanikája korlátoz." msgid "Preferred orientation" -msgstr "Előnyben részesített orientáció" +msgstr "Előnyben részesített tájolás" msgid "Automatically orient STL files on the Z axis upon initial import." msgstr "Az STL fájlok automatikus Z tengely szerinti tájolása első importáláskor." msgid "Printer preset names" -msgstr "Nyomtató beállítások neve" +msgstr "Nyomtatóbeállítások nevei" msgid "Use 3rd-party print host" msgstr "Külső nyomtatási gazdagép használata" @@ -12519,7 +12540,7 @@ msgid "Hostname, IP or URL" msgstr "Gazdagépnév, IP vagy URL" msgid "Orca Slicer can upload G-code files to a printer host. This field should contain the hostname, IP address or URL of the printer host instance. Print host behind HAProxy with basic auth enabled can be accessed by putting the user name and password into the URL in the following format: https://username:password@your-octopi-address/" -msgstr "A Orca Slicer képes G-kód fájlokat feltölteni a nyomtatóra. Ennek a mezőnek tartalmaznia kell a nyomtató hostnevét, IP-címét vagy URL-címét. A HAProxy mögött lévő nyomtató alapszintű hitelesítéssel érhető el, ha a felhasználónevet és a jelszót a következő formátumban beleírod az URL-be: https://username:password@your-octopi-address/" +msgstr "Az Orca Slicer képes G-kód fájlokat feltölteni a nyomtatóra. Ennek a mezőnek a nyomtató gazdagépnevét, IP-címét vagy URL-címét kell tartalmaznia. A HAProxy mögött lévő nyomtató alapszintű hitelesítéssel érhető el, ha a felhasználónevet és a jelszót a következő formátumban írod az URL-be: https://username:password@your-octopi-address/" msgid "Device UI" msgstr "Eszköz UI" @@ -12531,7 +12552,7 @@ msgid "API Key / Password" msgstr "API kulcs / jelszó" msgid "Orca Slicer can upload G-code files to a printer host. This field should contain the API Key or the password required for authentication." -msgstr "A Orca Slicer képes G-kód fájlokat feltölteni a nyomtatóra. Ennek a mezőnek tartalmaznia kell a hitelesítéshez szükséges API-kulcsot vagy jelszót." +msgstr "Az Orca Slicer képes G-kód fájlokat feltölteni a nyomtatóra. Ennek a mezőnek a hitelesítéshez szükséges API-kulcsot vagy jelszót kell tartalmaznia." # AI Translated msgid "Serial Number" @@ -12548,7 +12569,7 @@ msgid "HTTPS CA File" msgstr "HTTPS CA fájl" msgid "Custom CA certificate file can be specified for HTTPS OctoPrint connections, in crt/pem format. If left blank, the default OS CA certificate repository is used." -msgstr "A HTTP-alapú OctoPrint kapcsolatokhoz megadható egy egyedi CA-tanúsítvány, crt/pem formátumban. Ha üresen hagyod, az alapértelmezett OS CA tanúsítvány lesz használva." +msgstr "A HTTPS-alapú OctoPrint-kapcsolatokhoz egyedi CA-tanúsítványfájlt adhatsz meg crt/pem formátumban. Ha üresen hagyod, az operációs rendszer alapértelmezett CA-tanúsítványát használja." msgid "User" msgstr "Felhasználó" @@ -12598,22 +12619,22 @@ msgid "Other layers" msgstr "Többi réteg" msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." -msgstr "A kezdőrétegen kívüli rétegek tárgyasztalhőmérséklete. A 0 érték azt jelenti, hogy a filament nem támogatja a nyomtatást a SuperTac hűvös tálcán." +msgstr "A kezdőréteg utáni asztalhőmérséklet. A 0 azt jelenti, hogy a filament nem nyomtatható a SuperTack hűvös tálcára." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." -msgstr "Az asztal hőmérséklete a kezdőréteg kivételével. A 0 érték azt jelenti, hogy a filament nem támogatja a Cool Plate-re történő nyomtatást" +msgstr "A kezdőréteg utáni asztalhőmérséklet. A 0 azt jelenti, hogy a filament nem nyomtatható a hűvös tálcára." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured Cool Plate." -msgstr "A kezdőrétegen kívüli rétegek tárgyasztalhőmérséklete. A 0 érték azt jelenti, hogy a filament nem támogatja a nyomtatást a texturált hűvös tálcán." +msgstr "A kezdőréteg utáni asztalhőmérséklet. A 0 azt jelenti, hogy a filament nem nyomtatható a texturált hűvös tálcára." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Engineering Plate." -msgstr "Az asztal hőmérséklete a kezdeti réteg kivételével. A 0 érték azt jelenti, hogy a szál nem támogatja az Engineering Plate-re történő nyomtatást" +msgstr "A kezdőréteg utáni asztalhőmérséklet. A 0 azt jelenti, hogy a filament nem nyomtatható a műszaki tálcára." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the High Temp Plate." -msgstr "Az asztal hőmérséklete a kezdeti réteg kivételével. A 0 érték azt jelenti, hogy a szál nem támogatja a High Temp Plate-re történő nyomtatást" +msgstr "A kezdőréteg utáni asztalhőmérséklet. A 0 azt jelenti, hogy a filament nem nyomtatható a magas hőmérsékletű tálcára." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured PEI Plate." -msgstr "Asztalhőmérséklet az első réteg után. A 0 érték azt jelenti, hogy a filament nem támogatja texturált PEI tálcára történő nyomtatást." +msgstr "A kezdőréteg utáni asztalhőmérséklet. A 0 azt jelenti, hogy a filament nem nyomtatható a texturált PEI tálcára." msgid "First layer" msgstr "Kezdőréteg" @@ -12622,19 +12643,19 @@ msgid "First layer bed temperature" msgstr "Első réteg asztalhőmérséklete" msgid "This is the bed temperature of the first layer. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." -msgstr "A kezdőréteg tárgyasztalhőmérséklete. A 0 érték azt jelenti, hogy a filament nem támogatja a nyomtatást a SuperTac hűvös tálcán." +msgstr "A kezdőréteg asztalhőmérséklete. A 0 azt jelenti, hogy a filament nem nyomtatható a SuperTack hűvös tálcára." msgid "This is the bed temperature of the first layer. A value of 0 means the filament does not support printing on the Cool Plate." -msgstr "A kezdőréteg asztalhőmérséklete. A 0 érték azt jelenti, hogy a filament nem támogatja a Cool Plate-re történő nyomtatást" +msgstr "A kezdőréteg asztalhőmérséklete. A 0 azt jelenti, hogy a filament nem nyomtatható a hűvös tálcára." msgid "This is the bed temperature of the first layer. A value of 0 means the filament does not support printing on the Textured Cool Plate." -msgstr "A kezdőréteg tárgyasztalhőmérséklete. A 0 érték azt jelenti, hogy a filament nem támogatja a nyomtatást a texturált hűvös tálcán." +msgstr "A kezdőréteg asztalhőmérséklete. A 0 azt jelenti, hogy a filament nem nyomtatható a texturált hűvös tálcára." msgid "This is the bed temperature of the first layer. A value of 0 means the filament does not support printing on the Engineering Plate." -msgstr "A kezdőréteg asztalhőmérséklete. A 0 érték azt jelenti, hogy a filament nem támogatja a Engineering Plate-re történő nyomtatást" +msgstr "A kezdőréteg asztalhőmérséklete. A 0 azt jelenti, hogy a filament nem nyomtatható a műszaki tálcára." msgid "This is the bed temperature of the first layer. A value of 0 means the filament does not support printing on the High Temp Plate." -msgstr "A kezdőréteg asztalhőmérséklete. A 0 érték azt jelenti, hogy a filament nem támogatja a High Temp Plate-re történő nyomtatást" +msgstr "A kezdőréteg asztalhőmérséklete. A 0 azt jelenti, hogy a filament nem nyomtatható a magas hőmérsékletű tálcára." # AI Translated msgid "This is the bed temperature of the first layer. A value of 0 means the filament does not support printing on the Textured PEI Plate." @@ -12647,7 +12668,7 @@ msgid "Default bed type" msgstr "Alapértelmezett asztaltípus" msgid "Default bed type for the printer (supports both numeric and string format)." -msgstr "A nyomtató alapértelmezett tárgyasztaltípusa (szám- és szöveges formátumot is támogat)." +msgstr "A nyomtató alapértelmezett asztaltípusa (szám- és szöveges formátumot is támogat)." msgid "First layer print sequence" msgstr "Az első réteg nyomtatási sorrendje" @@ -12677,7 +12698,7 @@ msgid "The number of bottom solid layers is increased when slicing if the thickn msgstr "Az alsó szilárd rétegek száma szeleteléskor megnő, ha az alsó héjrétegek vastagsága kisebb ennél az értéknél. Ezzel elkerülhető, hogy túl vékony legyen a héj, ha a rétegmagasság kicsi. A 0 azt jelenti, hogy ez a beállítás ki van kapcsolva, és az alsó héj vastagságát egyszerűen az alsó héjrétegek száma határozza meg." msgid "Apply gap fill" -msgstr "Réskitöltés alkalmazása" +msgstr "Hézagkitöltés alkalmazása" msgid "" "Enables gap fill for the selected solid surfaces. The minimum gap length that will be filled can be controlled from the filter out tiny gaps option below.\n" @@ -12693,18 +12714,18 @@ msgid "" "\n" "However this is not advised, as gap fill between perimeters is contributing to the model's strength. For models where excessive gap fill is generated between perimeters, a better option would be to switch to the arachne wall generator and use this option to control whether the cosmetic top and bottom surface gap fill is generated." msgstr "" -"Engedélyezi a réskitöltést a kijelölt tömör felületeken. A kitöltendő minimális rés hosszát az alábbi apró rések szűrése beállítással lehet szabályozni.\n" +"Engedélyezi a hézagkitöltést a kijelölt tömör felületeken. A kitöltendő hézagok minimális hosszát az alábbi apró hézagok szűrése beállítással lehet szabályozni.\n" "\n" "Lehetőségek:\n" -"1. Mindenhol: A réskitöltést a felső, alsó és belső tömör felületeken is alkalmazza a maximális szilárdság érdekében\n" -"2. Felső és alsó felületek: Csak a felső és alsó felületeken alkalmazza a réskitöltést, egyensúlyt teremtve a nyomtatási sebesség, a tömör kitöltés esetleges túlextrudálásának csökkentése, valamint a felső és alsó felületek tűlyukmentessége között\n" -"3. Sehol: Letiltja a réskitöltést minden tömör kitöltési területen\n" +"1. Mindenhol: A hézagkitöltést a felső, alsó és belső tömör felületeken is alkalmazza a maximális szilárdság érdekében\n" +"2. Felső és alsó felületek: Csak a felső és alsó felületeken alkalmazza a hézagkitöltést, egyensúlyt teremtve a nyomtatási sebesség, a tömör kitöltés esetleges túlextrudálásának csökkentése, valamint a felső és alsó felületek tűlyukmentessége között\n" +"3. Sehol: Letiltja a hézagkitöltést minden tömör kitöltési területen\n" "\n" -"Vedd figyelembe, hogy klasszikus falgenerátor használatakor a falak között is keletkezhet réskitöltés, ha közéjük nem fér el egy teljes szélességű vonal. Ezt a falak közötti réskitöltést ez a beállítás nem szabályozza.\n" +"Vedd figyelembe, hogy klasszikus falgenerátor használatakor a falak között is keletkezhet hézagkitöltés, ha közéjük nem fér el egy teljes szélességű vonal. Ezt a falak közötti hézagkitöltést ez a beállítás nem szabályozza.\n" "\n" -"Ha minden réskitöltést, beleértve a klasszikus falgenerátor által létrehozottat is, el szeretnél távolítani, állítsd az apró rések szűrése értékét egy nagy számra, például 999999-re.\n" +"Ha minden hézagkitöltést, beleértve a klasszikus falgenerátor által létrehozottat is, el szeretnél távolítani, állítsd az apró hézagok szűrése értékét egy nagy számra, például 999999-re.\n" "\n" -"Ez azonban nem ajánlott, mert a falak közötti réskitöltés hozzájárul a modell szilárdságához. Olyan modelleknél, ahol túl sok réskitöltés keletkezik a falak között, jobb megoldás lehet az Arachne falgenerátorra váltani, és ezzel a beállítással szabályozni, hogy létrejöjjön-e a felső és alsó felületek esztétikai réskitöltése." +"Ez azonban nem ajánlott, mert a falak közötti hézagkitöltés hozzájárul a modell szilárdságához. Olyan modelleknél, ahol túl sok hézagkitöltés keletkezik a falak között, jobb megoldás lehet az Arachne falgenerátorra váltani, és ezzel a beállítással szabályozni, hogy létrejöjjön-e a felső és alsó felületek esztétikai hézagkitöltése." msgid "Everywhere" msgstr "Mindenhol" @@ -12854,7 +12875,7 @@ msgstr "" "Ez a beállítás különösen jól működik a második belső híd a kitöltés felett lehetőséggel együtt, tovább javítva az áthidalást, mielőtt a tömör kitöltés extrudálásra kerül." msgid "Bridge flow ratio" -msgstr "Áthidalás áramlási sebessége" +msgstr "Áthidalás anyagáramlása" # AI Translated msgid "" @@ -12885,7 +12906,7 @@ msgstr "" "Ha 0-ra van állítva, a vonalszélesség megegyezik a belső tömör kitöltés szélességével." msgid "Internal bridge flow ratio" -msgstr "Belső híd áramlási aránya" +msgstr "Belső híd anyagáramlása" # AI Translated msgid "" @@ -12911,10 +12932,10 @@ msgid "" msgstr "" "Ez a tényező befolyásolja a felső tömör kitöltéshez felhasznált anyag mennyiségét. Kissé csökkentheted az értéket, hogy simább felületi megjelenést kapj.\n" "\n" -"A ténylegesen használt felső felületi áramlás ennek az értéknek, a filament áramlási arányának, valamint ha be van állítva, az objektum áramlási arányának a szorzatából adódik." +"A felső felület tényleges anyagáramlása ennek az értéknek, a filament anyagáramlásának, valamint – ha be van állítva – az objektum anyagáramlásának a szorzata." msgid "Bottom surface flow ratio" -msgstr "Alsó felület áramlási aránya" +msgstr "Alsó felület anyagáramlása" msgid "" "This factor affects the amount of material for bottom solid infill.\n" @@ -12923,16 +12944,16 @@ msgid "" msgstr "" "Ez a tényező befolyásolja az alsó tömör kitöltéshez felhasznált anyag mennyiségét.\n" "\n" -"A ténylegesen használt alsó tömör kitöltési áramlás ennek az értéknek, a filament áramlási arányának, valamint ha be van állítva, az objektum áramlási arányának a szorzatából adódik." +"Az alsó tömör kitöltés tényleges anyagáramlása ennek az értéknek, a filament anyagáramlásának, valamint – ha be van állítva – az objektum anyagáramlásának a szorzata." msgid "Set other flow ratios" -msgstr "Egyéb áramlási arányok beállítása" +msgstr "Egyéb anyagáramlások beállítása" msgid "Change flow ratios for other extrusion path types." -msgstr "Anyagáramlási arányok módosítása más extrudálási úttípusokhoz." +msgstr "Anyagáramlások módosítása más extrudálási úttípusokhoz." msgid "First layer flow ratio" -msgstr "Első réteg áramlási aránya" +msgstr "Első réteg anyagáramlása" msgid "" "This factor affects the amount of material on the first layer for the extrusion path roles listed in this section.\n" @@ -12941,10 +12962,10 @@ msgid "" msgstr "" "Ez a tényező az ebben a szakaszban felsorolt extrudálási útszerepek első rétegén felhasznált anyagmennyiséget befolyásolja.\n" "\n" -"Az első rétegen az egyes útszerepek tényleges áramlási aránya (a peremeket és szoknyákat nem érinti) ezzel az értékkel lesz megszorozva." +"Az első rétegen az egyes úttípusok tényleges anyagáramlását ezzel az értékkel szorozza meg (a peremeket és szoknyákat nem érinti)." msgid "Outer wall flow ratio" -msgstr "Külső fal áramlási aránya" +msgstr "Külső fal anyagáramlása" msgid "" "This factor affects the amount of material for outer walls.\n" @@ -12953,10 +12974,10 @@ msgid "" msgstr "" "Ez a tényező a külső falakhoz felhasznált anyagmennyiséget befolyásolja.\n" "\n" -"A tényleges külső fali áramlás úgy számolódik, hogy ezt az értéket megszorozza a filament áramlási arányával, valamint ha be van állítva, az objektum áramlási arányával." +"A külső fal tényleges anyagáramlása ennek az értéknek, a filament anyagáramlásának, valamint – ha be van állítva – az objektum anyagáramlásának a szorzata." msgid "Inner wall flow ratio" -msgstr "Belső fal áramlási aránya" +msgstr "Belső fal anyagáramlása" msgid "" "This factor affects the amount of material for inner walls.\n" @@ -12965,10 +12986,10 @@ msgid "" msgstr "" "Ez a tényező a belső falakhoz felhasznált anyagmennyiséget befolyásolja.\n" "\n" -"A tényleges belső fali áramlás úgy számolódik, hogy ezt az értéket megszorozza a filament áramlási arányával, valamint ha be van állítva, az objektum áramlási arányával." +"A belső fal tényleges anyagáramlása ennek az értéknek, a filament anyagáramlásának, valamint – ha be van állítva – az objektum anyagáramlásának a szorzata." msgid "Overhang flow ratio" -msgstr "Túlnyúlás áramlási aránya" +msgstr "Túlnyúlás anyagáramlása" msgid "" "This factor affects the amount of material for overhangs.\n" @@ -12977,22 +12998,22 @@ msgid "" msgstr "" "Ez a tényező a túlnyúlásokhoz felhasznált anyagmennyiséget befolyásolja.\n" "\n" -"A tényleges túlnyúlási áramlás úgy számolódik, hogy ezt az értéket megszorozza a filament áramlási arányával, valamint ha be van állítva, az objektum áramlási arányával." +"A túlnyúlás tényleges anyagáramlása ennek az értéknek, a filament anyagáramlásának, valamint – ha be van állítva – az objektum anyagáramlásának a szorzata." msgid "Sparse infill flow ratio" -msgstr "Ritka kitöltés áramlási aránya" +msgstr "Kitöltés anyagáramlása" msgid "" "This factor affects the amount of material for sparse infill.\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." msgstr "" -"Ez a tényező a ritka kitöltéshez felhasznált anyagmennyiséget befolyásolja.\n" +"Ez a tényező a kitöltéshez felhasznált anyagmennyiséget befolyásolja.\n" "\n" -"A tényleges ritka kitöltési áramlás úgy számolódik, hogy ezt az értéket megszorozza a filament áramlási arányával, valamint ha be van állítva, az objektum áramlási arányával." +"A tényleges kitöltési anyagáramlást úgy számítja ki, hogy ezt az értéket megszorozza a filament anyagáramlásával, valamint ha be van állítva, az objektum anyagáramlásával." msgid "Internal solid infill flow ratio" -msgstr "Belső tömör kitöltés áramlási aránya" +msgstr "Belső tömör kitöltés anyagáramlása" msgid "" "This factor affects the amount of material for internal solid infill.\n" @@ -13001,10 +13022,10 @@ msgid "" msgstr "" "Ez a tényező a belső tömör kitöltéshez felhasznált anyagmennyiséget befolyásolja.\n" "\n" -"A tényleges belső tömör kitöltési áramlás úgy számolódik, hogy ezt az értéket megszorozza a filament áramlási arányával, valamint ha be van állítva, az objektum áramlási arányával." +"A belső tömör kitöltés tényleges anyagáramlása ennek az értéknek, a filament anyagáramlásának, valamint – ha be van állítva – az objektum anyagáramlásának a szorzata." msgid "Gap fill flow ratio" -msgstr "Réskitöltés áramlási aránya" +msgstr "Hézagkitöltés anyagáramlása" msgid "" "This factor affects the amount of material for filling the gaps.\n" @@ -13013,10 +13034,10 @@ msgid "" msgstr "" "Ez a tényező a rések kitöltéséhez felhasznált anyagmennyiséget befolyásolja.\n" "\n" -"A tényleges réskitöltési áramlás úgy számolódik, hogy ezt az értéket megszorozza a filament áramlási arányával, valamint ha be van állítva, az objektum áramlási arányával." +"A tényleges hézagkitöltési anyagáramlást úgy számítja ki, hogy ezt az értéket megszorozza a filament anyagáramlásával, valamint ha be van állítva, az objektum anyagáramlásával." msgid "Support flow ratio" -msgstr "Támasz áramlási aránya" +msgstr "Támasz anyagáramlása" msgid "" "This factor affects the amount of material for support.\n" @@ -13025,10 +13046,10 @@ msgid "" msgstr "" "Ez a tényező a támaszhoz felhasznált anyagmennyiséget befolyásolja.\n" "\n" -"A tényleges támaszáramlás úgy számolódik, hogy ezt az értéket megszorozza a filament áramlási arányával, valamint ha be van állítva, az objektum áramlási arányával." +"A támasz tényleges anyagáramlása ennek az értéknek, a filament anyagáramlásának, valamint – ha be van állítva – az objektum anyagáramlásának a szorzata." msgid "Support interface flow ratio" -msgstr "Támasz érintkező felület áramlási aránya" +msgstr "Támasz érintkező felületének anyagáramlása" msgid "" "This factor affects the amount of material for the support interface.\n" @@ -13037,13 +13058,13 @@ msgid "" msgstr "" "Ez a tényező a támasz érintkező felületéhez felhasznált anyagmennyiséget befolyásolja.\n" "\n" -"A tényleges támasz érintkező felületi áramlás úgy számolódik, hogy ezt az értéket megszorozza a filament áramlási arányával, valamint ha be van állítva, az objektum áramlási arányával." +"A támasz érintkező felületének tényleges anyagáramlása ennek az értéknek, a filament anyagáramlásának, valamint – ha be van állítva – az objektum anyagáramlásának a szorzata." msgid "Precise wall" msgstr "Pontos fal" msgid "Improve shell precision by adjusting outer wall spacing. This also improves layer consistency. NOTE: This option will be ignored for outer-inner or inner-outer-inner wall sequences." -msgstr "Javítja a héj pontosságát a külső fal távolságának finomhangolásával. Ez a rétegek egyenletességét is javítja. MEGJEGYZÉS: Ez az opció figyelmen kívül lesz hagyva külső-belső vagy belső-külső-belső fali sorrend esetén." +msgstr "A külső fal térközének finomhangolásával javítja a héj pontosságát és a rétegek egyenletességét. MEGJEGYZÉS: a szeletelő figyelmen kívül hagyja ezt a beállítást Külső/Belső vagy Belső/Külső/Belső falsorrendnél." msgid "Only one wall on top surfaces" msgstr "Csak egy fal a felső felületeken" @@ -13218,7 +13239,7 @@ msgid "This creates a gap between the innermost brim line and the object and can msgstr "A legbelső peremvonal és a tárgy közötti rés, ami megkönnyítheti a perem eltávolítását" msgid "Brim flow ratio" -msgstr "Perem áramlási arány" +msgstr "Perem anyagáramlása" msgid "" "This factor affects the amount of material for brims.\n" @@ -13227,11 +13248,11 @@ msgid "" "\n" "Note: The resulting value will not be affected by the first-layer flow ratio." msgstr "" -"Ez a tényező befolyásolja a karimák anyagának mennyiségét.\n" +"Ez a tényező befolyásolja a peremek anyagmennyiségét.\n" "\n" -"A ténylegesen használt peremáramlást úgy számítjuk ki, hogy ezt az értéket megszorozzuk a filament áramlási arányával, és ha be van állítva, akkor az objektum áramlási arányával.\n" +"A perem tényleges anyagáramlása ennek az értéknek, a filament anyagáramlásának, valamint – ha be van állítva – az objektum anyagáramlásának a szorzata.\n" "\n" -"Megjegyzés: A kapott értéket nem befolyásolja az első réteg áramlási aránya." +"Megjegyzés: A kapott értéket nem befolyásolja az első réteg anyagáramlása." msgid "Brim follows compensated outline" msgstr "A Perem a kompenzált körvonalat követi" @@ -13242,8 +13263,8 @@ msgid "" "\n" "If your current setup already works well, enabling it may be unnecessary and can cause the brim to fuse with upper layers." msgstr "" -"Ha engedélyezve van, a perem igazodik az első réteg kerületi geometriájához az elefánttalp-kompenzáció alkalmazása után.\n" -"Ez az opció arra az esetre szolgál, amikor az elefánttalp-kompenzáció jelentősen megváltoztatja az első réteg alapterületét.\n" +"Ha engedélyezve van, a perem igazodik az első réteg kerületi geometriájához az elefántláb-kompenzáció alkalmazása után.\n" +"Ez az opció akkor hasznos, ha az elefántláb-kompenzáció jelentősen megváltoztatja az első réteg alapterületét.\n" "\n" "Ha a jelenlegi beállítás már jól működik, előfordulhat, hogy az engedélyezése felesleges és a perem összeolvadását okozhatja a felső rétegekkel." @@ -13254,7 +13275,7 @@ msgid "Combine multiple brims into one when they are close to each other. This c msgstr "Karimák egybevonása, ha azok közel vannak egymáshoz. Ez javíthatja a perem tapadását." msgid "Brim ears" -msgstr "Karimás fülek" +msgstr "Peremfülek" msgid "Only draw brim over the sharp edges of the model." msgstr "Csak a modell éles szélei fölé rajzoljon peremet." @@ -13305,12 +13326,37 @@ msgstr "Tárgyanként" msgid "Intra-layer order" msgstr "Rétegen belüli sorrend" -msgid "Print order within a single layer." -msgstr "Nyomtatási sorrend egyetlen rétegen belül." +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Az a sorrend, amelyben az objektumpéldányokat egyetlen rétegen belül bejárja a nyomtató, ami meghatározza, mennyi mozgás megy el a köztük való áthaladásra.\n" +"\n" +"Alapértelmezett: legközelebbi szomszéd szerinti láncolás, 2-opt eljárással és a keresztezések megszüntetésével finomítva. Jó általános választás.\n" +"Objektumlista szerint: a példányok az objektumlista sorrendjében nyomtatódnak, bármilyen útvonal-optimalizálás nélkül. Akkor használd, ha kiszámítható, kézzel vezérelt sorrendre van szükséged.\n" +"Legjobb az összes közül (legrövidebb útvonal): minden stratégia kiértékelésre kerül, és a legrövidebb kerül felhasználásra. Az objektumpéldányok sorrendje egyszer dől el az egész nyomtatásra, míg az egyes szigetek sorrendje rétegenként, így a különböző rétegek eltérő stratégiát is használhatnak. Kissé lassabb szeletelés.\n" +"Kígyóvonal: kanyargós, soronkénti bejárás, 2-opt eljárással finomítva. Jól illik sok kis alkatrész szabályos rácsához.\n" +"\n" +"Ha egy rétegen belül több filament vagy szerszám szerepel, a szerszámcserék minimalizálása élvez elsőbbséget: az objektumok először filament szerint csoportosulnak, és ez a beállítás csak az egyes filamentcsoportokon belüli példánysorrendet szabja meg, így a teljes sorrend nem feltétlenül a tálcán átvezető legrövidebb útvonalnak tűnik." msgid "As object list" msgstr "Objektumlista szerint" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "Legjobb az összes közül (legrövidebb útvonal)" + +# AI Translated +msgid "Snake" +msgstr "Kígyóvonal" + msgid "Slow printing down for better layer cooling" msgstr "Nyomtatás lelassítása a jobb hűtés érdekében" @@ -13380,7 +13426,7 @@ msgid "No cooling for the first" msgstr "Nincs hűtés az első" msgid "Turn off all cooling fans for the first few layers. This can be used to improve build plate adhesion." -msgstr "Kikapcsolja a hűtést a megadott első pár rétegnél. A hűtés kikapcsolása segítheti a jobb tárgyasztalhoz való tapadást" +msgstr "Kikapcsolja a hűtést a megadott első néhány rétegnél. A hűtés kikapcsolása javíthatja az asztalhoz való tapadást" msgid "Don't support bridges" msgstr "Ne támassza alá az áthidalásokat" @@ -13439,7 +13485,7 @@ msgstr "" "Lehetőségek:\n" "1. Letiltva - nem hoz létre második hídréteget. Ez az alapértelmezett és kompatibilitási okokból így van beállítva\n" "2. Csak külső híd - csak a kifelé néző hidaknál hoz létre második hídréteget. A beállított kerületszámnál rövidebb vagy keskenyebb kis hidak kimaradnak, mert nem profitálnának a második hídrétegből. Ha létrejön, a második hídréteg az első hídréteggel párhuzamosan kerül extrudálásra a híd megerősítése érdekében\n" -"3. Csak belső híd - csak a ritka kitöltés feletti belső hidaknál hoz létre második hídréteget. Vedd figyelembe, hogy a belső hidak beleszámítanak a modell felső héjrétegeinek számába. A második belső hídréteg lehetőség szerint az elsőre merőlegesen kerül extrudálásra. Ha ugyanazon a szigeten több eltérő hídszögű régió van, akkor a sziget utolsó régiója lesz a szögreferencia\n" +"3. Csak belső híd - csak a kitöltés feletti belső hidaknál hoz létre második hídréteget. Vedd figyelembe, hogy a belső hidak beleszámítanak a modell felső héjrétegeinek számába. A második belső hídréteget lehetőség szerint az elsőre merőlegesen extrudálja. Ha ugyanazon a szigeten több eltérő hídszögű régió van, akkor a sziget utolsó régiója lesz a szögreferencia\n" "4. Alkalmazás mindenre - második hídréteget hoz létre mind a belső, mind a kifelé néző hidakhoz\n" msgid "External bridge only" @@ -13464,8 +13510,8 @@ msgid "" "3. No filtering - creates internal bridges on every potential internal overhang. This option is useful for heavily slanted top surface models; however, in most cases, it creates too many unnecessary bridges." msgstr "" "Ez az opció segíthet csökkenteni a felső felületek párnásodását erősen lejtős vagy ívelt modelleknél.\n" -"Alapértelmezés szerint a kis belső hidak kiszűrésre kerülnek, és a belső tömör kitöltés közvetlenül a ritka kitöltés fölé nyomtatódik. Ez a legtöbb esetben jól működik, felgyorsítja a nyomtatást anélkül, hogy túl nagy kompromisszumot kellene kötni a felső felület minőségében.\n" -"Erősen lejtős vagy ívelt modelleknél azonban, különösen túl alacsony ritka kitöltési sűrűség esetén, ez a támasz nélküli tömör kitöltés felkunkorodását okozhatja, ami párnásodáshoz vezet.\n" +"Alapértelmezés szerint a szeletelő kiszűri a kis belső hidakat, és a belső tömör kitöltést közvetlenül a kitöltés fölé nyomtatja. Ez a legtöbb esetben jól működik, és úgy gyorsítja fel a nyomtatást, hogy közben alig rontja a felső felület minőségét.\n" +"Erősen lejtős vagy ívelt modelleknél azonban, különösen túl alacsony kitöltési sűrűség esetén, ez a támasz nélküli tömör kitöltés felkunkorodását okozhatja, ami párnásodáshoz vezet.\n" "A korlátozott szűrés vagy a szűrés kikapcsolása belső hídréteget nyomtat a kissé alátámasztatlan belső tömör kitöltés fölé. Az alábbi opciók a szűrés érzékenységét szabályozzák, azaz azt, hogy hol jöjjenek létre belső hidak:\n" "1. Szűrés - engedélyezi ezt az opciót. Ez az alapértelmezett működés, és a legtöbb esetben jól működik\n" "2. Korlátozott szűrés - erősen lejtős felületeken hoz létre belső hidakat, miközben elkerüli a felesleges hidakat. Ez a legtöbb nehéz modellnél jól működik\n" @@ -13626,7 +13672,7 @@ msgid "" "WARNING: Lowering this value may negatively affect bed adhesion." msgstr "" "Az alsó felületi réteg sűrűsége. Esztétikai vagy funkcionális célokra szolgál, nem pedig olyan problémák javítására, mint a túlextrudálás.\n" -"FIGYELMEZTETÉS: Ennek az értéknek a csökkentése kedvezőtlenül befolyásolhatja a tárgyasztalhoz való tapadást." +"FIGYELMEZTETÉS: Ennek az értéknek a csökkentése ronthatja az asztalhoz való tapadást." # AI Translated msgid "Top surface fill order" @@ -13825,7 +13871,7 @@ msgid "" msgstr "" "Az anyag térfogata megváltozhat az olvadt és a kristályos állapot közötti átmenet során. Ez a beállítás arányosan megváltoztatja ennek a filamentnek az összes extrudálási áramlását a G-kódban. Az ajánlott értéktartomány 0,95 és 1,05 között van. Ennek az értéknek a finomhangolásával szép sík felület érhető el enyhe túl- vagy alulextrudálás esetén.\n" "\n" -"Az objektum végső áramlási aránya ennek az értéknek és a filament áramlási arányának a szorzata." +"Az objektum végső anyagáramlása ennek az értéknek és a filament anyagáramlásának a szorzata." msgid "Enable pressure advance" msgstr "Nyomáselőtolás engedélyezése" @@ -13923,7 +13969,7 @@ msgid "Keep fan always on" msgstr "Ventilátor mindig bekapcsolva" msgid "Enabling this setting means that part cooling fan will never stop entirely and will instead run at least at minimum speed to reduce the frequency of starting and stopping." -msgstr "Ezen beállítás engedélyezése esetén a tárgyhűtő ventilátor soha nem áll le, és legalább a minimális fordulatszámon fog járni, hogy csökkentse az indítás és leállítás gyakoriságát" +msgstr "Ezen beállítás engedélyezése esetén a tárgyhűtő ventilátor soha nem áll le és legalább a minimális fordulatszámon fog járni, hogy csökkentse az indítás és leállítás gyakoriságát" msgid "Don't slow down outer walls" msgstr "Lassítás nélküli külső falak" @@ -13984,7 +14030,7 @@ msgstr "Automatikus egyeztetéshez" # AI Translated msgid "Nozzle Manual" -msgstr "Fúvóka kézikönyv" +msgstr "Kézi fúvókakiosztás" msgid "Flush temperature" msgstr "Öblítési hőmérséklet" @@ -14027,7 +14073,7 @@ msgid "Bed temperature type" msgstr "Asztalhőmérséklet típusa" msgid "This option determines how the bed temperature is set during slicing: based on the temperature of the first filament or the highest temperature of the printed filaments." -msgstr "Ez az opció határozza meg, hogyan kerüljön beállításra az asztalhőmérséklet a szeletelés során: az első filament hőmérséklete vagy a nyomtatott filamentek közül a legmagasabb hőmérséklet alapján." +msgstr "Ez az opció határozza meg, hogyan állítsa be az asztalhőmérsékletet szeleteléskor: az első filament hőmérséklete vagy a nyomtatott filamentek legmagasabb hőmérséklete alapján." msgid "By First filament" msgstr "Az első filament alapján" @@ -14118,16 +14164,16 @@ msgid "Speed used for unloading the tip of the filament immediately after rammin msgstr "A filament kiürítésének sebessége közvetlenül a tömörítés után." msgid "Delay after unloading" -msgstr "Várakozás a kiürítés után" +msgstr "Várakozás a filament kihúzása után" msgid "Time to wait after the filament is unloaded. May help to get reliable tool changes with flexible materials that may need more time to shrink to original dimensions." -msgstr "A várakozási idő az filament kiürítése után. Segíthet megbízható szerszámcserét elérni rugalmas anyagok esetén, amelyeknek több időre lehet szükségük ahhoz, hogy az eredeti méretükre zsugorodjanak." +msgstr "Várakozási idő a filament kihúzása után. Rugalmas anyagoknál megbízhatóbbá teheti a szerszámcserét, mert ezeknek több időre lehet szükségük, hogy visszanyerjék eredeti méretüket." msgid "Number of cooling moves" msgstr "Hűtési lépések száma" msgid "Filament is cooled by being moved back and forth in the cooling tubes. Specify desired number of these moves." -msgstr "A filament hűtése úgy történik, hogy oda-vissza mozgatják a hűtőcsőben. Adja meg a kívánt lépések számát." +msgstr "A filament azáltal hűl le, hogy a hűtőcsövekben oda-vissza mozog. Add meg ezeknek a mozgásoknak a kívánt számát." msgid "Stamping loading speed" msgstr "Bélyegző betöltési sebesség" @@ -14148,7 +14194,7 @@ msgid "Cooling moves are gradually accelerating beginning at this speed." msgstr "A hűtési lépések fokozatosan felgyorsulnak ettől a sebességtől kezdve." msgid "Minimal purge on wipe tower" -msgstr "Minimális kiürítés a törlőtoronyban" +msgstr "Minimális öblítés a törlőtoronyban" msgid "After a tool change, the exact position of the newly loaded filament inside the nozzle may not be known, and the filament pressure is likely not yet stable. Before purging the print head into an infill or a sacrificial object, Orca Slicer will always prime this amount of material into the wipe tower to produce successive infill or sacrificial object extrusions reliably." msgstr "Szerszámváltás után az újonnan betöltött filament pontos helyzete a fúvókában nem feltétlenül ismert, és a filament nyomása valószínűleg még nem stabil. Mielőtt a nyomtatófej egy kitöltésbe vagy áldozati objektumba ürítene, az Orca Slicer ezt az anyagmennyiséget mindig először a törlőtoronyba extrudálja, hogy a későbbi kitöltési vagy áldozati objektum extrudálások megbízhatóan történjenek." @@ -14157,7 +14203,7 @@ msgid "Wipe tower cooling" msgstr "Törlőtorony hűtése" msgid "Temperature drop before entering filament tower" -msgstr "Hőmérsékletcsökkenés az filamenttoronyba lépés előtt" +msgstr "Hőmérsékletcsökkenés a filamenttoronyba lépés előtt" msgid "Interface layer pre-extrusion distance" msgstr "Érintkezőréteg előextrudálási távolsága" @@ -14181,7 +14227,7 @@ msgid "mm²" msgstr "mm²" msgid "Interface layer purge length" -msgstr "Érintkezőréteg kiürítési hossza" +msgstr "Érintkezőréteg öblítési hossza" msgid "Purge length for prime tower interface layer (where different materials meet)." msgstr "Kiürítési hossz a törlőtorony érintkezőrétegéhez (ahol a különböző anyagok találkoznak)." @@ -14202,7 +14248,7 @@ msgid "Ramming parameters" msgstr "Tömörítési paraméterek" msgid "This string is edited by RammingDialog and contains ramming specific parameters." -msgstr "Ez a karakterlánc a TömörítésPárbeszéd ablakban szerkeszthető, és a tömörítéssel kapcsolatos paramétereket tartalmaz." +msgstr "Ez a karakterlánc a tömörítési párbeszédablakban szerkeszthető, és a tömörítés paramétereit tartalmazza." msgid "Enable ramming for multi-tool setups" msgstr "Tömörítés engedélyezése több szerszámos beállításokhoz" @@ -14226,7 +14272,7 @@ msgid "Density" msgstr "Sűrűség" msgid "Filament density, for statistical purposes only." -msgstr "Filament sűrűsége. Csak statisztikákhoz kerül felhasználásra" +msgstr "A filament sűrűsége, kizárólag statisztikai célokra." msgid "g/cm³" msgstr "g/cm³" @@ -14250,7 +14296,7 @@ msgid "Support material" msgstr "Támaszanyag" msgid "Support material is commonly used to print supports and support interfaces." -msgstr "A támaszanyag a támaszok és a támasz érintkező felületeinek nyomtatásához van használva." +msgstr "A támaszanyagot általában a támaszok és azok érintkező felületeinek nyomtatására használják." msgid "Filament printable" msgstr "Filament nyomtatható" @@ -14276,7 +14322,7 @@ msgid "Price" msgstr "Költség" msgid "Filament price, for statistical purposes only." -msgstr "Filament költsége. Csak statisztikákhoz kerül felhasználásra" +msgstr "A filament ára, kizárólag statisztikai célokra." msgid "money/kg" msgstr "pénz/kg" @@ -14291,10 +14337,10 @@ msgid "(Undefined)" msgstr "(Nincs meghatározva)" msgid "Sparse infill direction" -msgstr "Ritka kitöltés iránya" +msgstr "Kitöltés iránya" msgid "This is the angle for sparse infill pattern, which controls the start or main direction of lines." -msgstr "A ritkás kitöltési minta szöge, amely a vonal kezdő- vagy fő irányát szabályozza" +msgstr "A kitöltési minta szöge, amely a vonal kezdő- vagy fő irányát szabályozza" msgid "Solid infill direction" msgstr "Tömör kitöltés iránya" @@ -14331,7 +14377,7 @@ msgstr "Kitöltés sűrűsége" #, no-c-format, no-boost-format msgid "Density of internal sparse infill, 100% turns all sparse infill into solid infill and internal solid infill pattern will be used." -msgstr "A belső ritka kitöltés sűrűsége. A 100% minden ritka kitöltést tömör kitöltéssé alakít, és a belső tömör kitöltési minta kerül használatra." +msgstr "A belső kitöltés sűrűsége. 100%-os értéknél minden kitöltés tömör kitöltéssé alakul, a szeletelő pedig a belső tömör kitöltési mintát használja." # AI Translated msgid "Align directions to model" @@ -14363,13 +14409,13 @@ msgstr "Z-kihajlási torzítás optimalizálása (kísérleti)" # AI Translated #, no-c-format, no-boost-format msgid "Tightens the gyroid wave along the Z (vertical) axis at low infill density to shorten the effective vertical column length and improve Z-axis compression buckling resistance. Filament use is preserved. No effect at ~30% sparse infill density and above. Only applies when Sparse infill pattern is set to Gyroid." -msgstr "Alacsony feltöltési sűrűség mellett megfeszíti a gyroid hullámot a Z (függőleges) tengely mentén, hogy lerövidítse a tényleges függőleges oszlophosszt és javítsa a Z-tengely összenyomódási kihajlási ellenállását. A filamenthasználat megmarad. Nincs hatása ~30% vagy annál nagyobb ritka kitöltési sűrűségnél. Csak akkor érvényes, ha a Ritka kitöltési minta Gyroid-ra van állítva." +msgstr "Alacsony kitöltési sűrűségnél megfeszíti a Gyroid hullámot a Z (függőleges) tengely mentén, hogy lerövidítse a tényleges függőleges oszlophosszt, és javítsa a Z irányú kihajlással szembeni ellenállást. A filamentfelhasználás nem változik. Körülbelül 30%-os vagy nagyobb kitöltési sűrűségnél nincs hatása. Csak akkor érvényes, ha a kitöltési minta Gyroid." msgid "Sparse infill pattern" msgstr "Kitöltési mintázat" msgid "This is the line pattern for internal sparse infill." -msgstr "Ez a belső ritkás kitöltés mintája." +msgstr "A belső kitöltés mintázata." msgid "Zig Zag" msgstr "Cikkcakk" @@ -14439,13 +14485,13 @@ msgid "Acceleration of inner walls." msgstr "A belső falak gyorsulása." msgid "Acceleration of sparse infill. If the value is expressed as a percentage (e.g. 100%), it will be calculated based on the default acceleration." -msgstr "Gyorsulás a ritkás kitöltéseknél. Ha az érték százalékban van megadva (pl. 100%), akkor az alapértelmezett gyorsulás alapján kerül kiszámításra." +msgstr "A kitöltés gyorsulása. Ha százalékban adod meg (pl. 100%), a szeletelő az alapértelmezett gyorsulásból számítja ki." msgid "Acceleration of internal solid infill. If the value is expressed as a percentage (e.g. 100%), it will be calculated based on the default acceleration." msgstr "A belső tömör kitöltés gyorsulása. Ha az érték százalékban van megadva (pl. 100%), az alapértelmezett gyorsulás alapján lesz kiszámítva." msgid "This is the printing acceleration for the first layer. Using limited acceleration can improve build plate adhesion." -msgstr "A kezdőréteg gyorsulása. Alacsonyabb érték használata javíthatja a tárgyasztalhoz való tapadást" +msgstr "A kezdőréteg gyorsulása. Alacsonyabb érték használata javíthatja az asztalhoz való tapadást" msgid "Enable accel_to_decel" msgstr "accel_to_decel engedélyezése" @@ -14458,7 +14504,7 @@ msgstr "accel_to_decel" #, c-format, boost-format msgid "Klipper's max_accel_to_decel will be adjusted to this %% of acceleration." -msgstr "A Klipper max_accel_to_decel értéke a gyorsulás erre a százalékra lesz állítva." +msgstr "A Klipper max_accel_to_decel értékét a gyorsulás ezen %%-ára állítja." msgid "Default jerk." msgstr "Alapértelmezett jerk." @@ -14633,25 +14679,25 @@ msgid "All walls" msgstr "Összes fal" msgid "Fuzzy skin thickness" -msgstr "A bolyhos felület vastagsága" +msgstr "A barázdált felület vastagsága" msgid "The width of jittering: it’s recommended to keep this lower than the outer wall line width." msgstr "A rezgés szélessége: ezt ajánlott kisebbre állítani, mint a külső fal szélessége." msgid "Fuzzy skin point distance" -msgstr "A bolyhos felület ponttávolsága" +msgstr "A barázdált felület ponttávolsága" msgid "The average distance between the random points introduced on each line segment." msgstr "Az egyes vonalszakaszokon használt véletlen pontok közötti átlagos távolság" msgid "Apply fuzzy skin to first layer" -msgstr "Bolyhos felület alkalmazása az első rétegre" +msgstr "Barázdált felület alkalmazása az első rétegre" msgid "Whether to apply fuzzy skin on the first layer." -msgstr "Alkalmazzon-e bolyhos felületet az első rétegen." +msgstr "Meghatározza, hogy legyen-e barázdált felület az első rétegen." msgid "Fuzzy skin generator mode" -msgstr "A bolyhos felület generálási módja" +msgstr "A barázdált felület generálási módja" #, c-format, boost-format msgid "" @@ -14662,12 +14708,12 @@ msgid "" "\n" "Attention! The [Extrusion] and [Combined] modes works only the fuzzy_skin_thickness parameter not more than the thickness of printed loop. At the same time, the width of the extrusion for a particular layer should also not be below a certain level. It is usually equal 15-25%% of a layer height. Therefore, the maximum fuzzy skin thickness with a perimeter width of 0.4 mm and a layer height of 0.2 mm will be 0.4-(0.2*0.25)=±0.35mm! If you enter a higher parameter than this, the error Flow::spacing() will displayed, and the model will not be sliced. You can choose this number until this error is repeated." msgstr "" -"Bolyhos felület generálási mód. Csak az Arachne-nal működik!\n" +"A barázdált felület generálási módja. Csak az Arachne használatával működik!\n" "Eltolás: Klasszikus mód, amikor a mintázat úgy jön létre, hogy a fúvóka oldalirányban eltér az eredeti útvonaltól.\n" "Extrudálás: Olyan mód, amikor a mintázatot az extrudált műanyag mennyisége alakítja ki. Ez egy gyors és egyenes algoritmus, felesleges fúvókarázás nélkül, amely sima mintázatot ad. Ugyanakkor inkább a teljes felületen lazább falak kialakítására hasznos.\n" "Kombinált: Egyesített mód [Eltolás] + [Extrudálás]. A falak megjelenése hasonló az [Eltolás] módhoz, de nem hagy pórusokat a kerületek között.\n" "\n" -"Figyelem! Az [Extrudálás] és a [Kombinált] mód csak akkor működik, ha a fuzzy_skin_thickness paraméter nem nagyobb a nyomtatott hurok vastagságánál. Emellett egy adott réteg extrudálási szélessége sem lehet egy bizonyos szint alá csökkentve. Ez általában a rétegmagasság 15-25%%-a. Ezért 0,4 mm kerületszélesség és 0,2 mm rétegmagasság mellett a maximális bolyhos felület vastagság 0,4-(0,2*0,25)=±0,35 mm lesz. Ha ennél nagyobb értéket adsz meg, a Flow::spacing() hiba jelenik meg, és a modell nem lesz szeletelhető. Ezt az értéket addig választhatod, amíg ez a hiba meg nem ismétlődik." +"Figyelem! Az [Extrudálás] és a [Kombinált] mód csak akkor működik, ha a fuzzy_skin_thickness paraméter nem nagyobb a nyomtatott hurok vastagságánál. Emellett egy adott réteg extrudálási szélessége sem lehet egy bizonyos szint alá csökkentve. Ez általában a rétegmagasság 15-25%%-a. Ezért 0,4 mm kerületszélesség és 0,2 mm rétegmagasság mellett a barázdált felület maximális vastagsága 0,4-(0,2*0,25)=±0,35 mm lesz. Ha ennél nagyobb értéket adsz meg, a Flow::spacing() hiba jelenik meg, és a modell nem lesz szeletelhető. Ezt az értéket addig választhatod, amíg ez a hiba meg nem ismétlődik." msgid "Displacement" msgstr "Eltolás" @@ -14679,7 +14725,7 @@ msgid "Combined" msgstr "Kombinált" msgid "Fuzzy skin noise type" -msgstr "A bolyhos felület zajtípusa" +msgstr "A barázdált felület zajtípusa" msgid "" "Noise type to use for fuzzy skin generation:\n" @@ -14690,7 +14736,7 @@ msgid "" "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." msgstr "" -"A bolyhos felület generálására használható zajtípus:\n" +"A barázdált felület generálására használható zajtípus:\n" "Klasszikus: Klasszikus egységes véletlenszerű zaj.\n" "Perlin: Perlin zaj, amely egyenletesebb textúrát ad.\n" "Billow: Hasonló a perlin zajhoz, de csomósabb.\n" @@ -14717,19 +14763,19 @@ msgid "Ripple" msgstr "Fodrozódás" msgid "Fuzzy skin feature size" -msgstr "A bolyhos felület mintázatmérete" +msgstr "A barázdált felület mintázatmérete" msgid "The base size of the coherent noise features, in mm. Higher values will result in larger features." msgstr "Az összefüggő zajmintázat jellemzőinek alapmérete mm-ben. A nagyobb értékek nagyobb mintázatelemeket eredményeznek." msgid "Fuzzy Skin Noise Octaves" -msgstr "A bolyhos felület zajának oktávjai" +msgstr "A barázdált felület zajának oktávjai" msgid "The number of octaves of coherent noise to use. Higher values increase the detail of the noise, but also increase computation time." msgstr "A használt összefüggő zaj oktávjainak száma. A nagyobb értékek részletesebb zajt eredményeznek, de növelik a számítási időt is." msgid "Fuzzy skin noise persistence" -msgstr "A bolyhos felület zajának perzisztenciája" +msgstr "A barázdált felület zajának perzisztenciája" msgid "The decay rate for higher octaves of the coherent noise. Lower values will result in smoother noise." msgstr "Az összefüggő zaj magasabb oktávjainak lecsengési aránya. Az alacsonyabb értékek simább zajt eredményeznek." @@ -14738,7 +14784,7 @@ msgid "Number of ripples per layer" msgstr "A fodrozódások száma rétegenként" msgid "Controls how many full cycles of ripples will be added per layer." -msgstr "Azt szabályozza, hogy hány teljes ciklus hullámzás kerüljön hozzáadásra rétegenként." +msgstr "A rétegenként hozzáadott teljes hullámciklusok számát szabályozza." msgid "Ripple offset" msgstr "Fodrozódás eltolás" @@ -14779,10 +14825,10 @@ msgid "Layers and Perimeters" msgstr "Rétegek és peremek" msgid "Don't print gap fill with a length is smaller than the threshold specified (in mm). This setting applies to top, bottom and solid infill and, if using the classic perimeter generator, to wall gap fill." -msgstr "Ne nyomtasson olyan réskitöltést, amelynek hossza kisebb a megadott küszöbértéknél (mm-ben). Ez a beállítás a felső, alsó és tömör kitöltésre vonatkozik, valamint klasszikus kerületgenerátor használata esetén a falréskitöltésre is." +msgstr "Nem nyomtat a megadott küszöbértéknél rövidebb hézagkitöltést. Ez a beállítás a felső, alsó és tömör kitöltésre, valamint klasszikus falgenerátornál a falak közötti hézagkitöltésre vonatkozik." msgid "This is the speed for gap infill. Gaps usually have irregular line width and should be printed more slowly." -msgstr "A hézagkitöltés nyomtatási sebessége. A rés általában szabálytalan vonalszélességű, és lassabban kell nyomtatni" +msgstr "A hézagkitöltés nyomtatási sebessége. A hézagok vonalszélessége általában szabálytalan, ezért lassabban kell nyomtatni őket" msgid "Precise Z height" msgstr "Pontos Z-magasság" @@ -14869,7 +14915,7 @@ msgid "Best object position" msgstr "Legjobb tárgypozíció" msgid "Best auto arranging position in range [0,1] w.r.t. bed shape." -msgstr "A legjobb automatikus elrendezés tartománya [0,1] a tárgyasztal alakja szerint." +msgstr "A legjobb automatikus elrendezés tartománya [0,1] az asztal alakja szerint." msgid "Enable this option if machine has auxiliary part cooling fan. G-code command: M106 P2 S(0-255)." msgstr "Engedélyezd ezt az opciót, ha a gép rendelkezik kiegészítő tárgyhűtő ventilátorral. G-kód parancs: M106 P2 S(0-255)." @@ -14916,7 +14962,7 @@ msgstr "" "A kikapcsoláshoz állítsd 0-ra." msgid "Minimum non-zero part cooling fan speed" -msgstr "Minimális nem nulla rész-hűtőventilátor fordulatszáma" +msgstr "A tárgyhűtő ventilátor minimális nem nulla fordulatszáma" msgid "" "Some part-cooling fans cannot start spinning when commanded below a certain PWM duty cycle. When set above 0, any non-zero part-cooling fan command will be raised to at least this percentage so the fan reliably starts. A fan command of 0 (fan off) is always honoured exactly. This clamp is applied after every other fan calculation (first-layer ramp, layer-time interpolation, overhang/bridge/support-interface/ironing overrides), so scaling still operates within the range [this value, 100%].\n" @@ -14963,7 +15009,7 @@ msgid "Enable this if printer support cooling filter" msgstr "Engedélyezd a beállítást, ha a nyomtató támogatja a hűtőszűrőt" msgid "G-code flavor" -msgstr "G-kód változat" +msgstr "G-kód-változat" msgid "What kind of G-code the printer is compatible with." msgstr "Milyen G-kóddal kompatibilis a nyomtató." @@ -15005,7 +15051,7 @@ msgid "Infill combination" msgstr "Kitöltés összevonása" msgid "Automatically combine sparse infill of several layers to print together in order to reduce time. Walls are still printed with original layer height." -msgstr "Több réteg ritkás kitöltésének automatikus kombinálása a nyomtatási idő csökkentése érdekében. A fal továbbra is az eredeti rétegmagassággal kerül kinyomtatásra." +msgstr "Több réteg kitöltésének automatikus összevonása a nyomtatási idő csökkentéséhez. A falat továbbra is az eredeti rétegmagassággal nyomtatja." msgid "Infill shift step" msgstr "Kitöltés eltolási lépése" @@ -15014,10 +15060,10 @@ msgid "This parameter adds a slight displacement to each layer of infill to crea msgstr "Ez a paraméter enyhe eltolást ad a kitöltéshez minden rétegen, hogy keresztmintás textúra jöjjön létre." msgid "Sparse infill rotation template" -msgstr "Ritka kitöltés forgatási sablonja" +msgstr "Kitöltés forgatási sablonja" msgid "Rotate the sparse infill direction per layer using a template of angles. Enter comma-separated degrees (e.g., '0,30,60,90'). Angles are applied in order by layer and repeat when the list ends. Advanced syntax is supported: '+5' rotates +5° every layer; '+5#5' rotates +5° every 5 layers. See the Wiki for details. When a template is set, the standard infill direction setting is ignored. Note: some infill patterns (e.g., Gyroid) control rotation themselves; use with care." -msgstr "A ritka kitöltés irányát rétegenként forgatja egy szögsablon alapján. Adj meg vesszővel elválasztott fokértékeket (pl. '0,30,60,90'). A szögek rétegenként sorban lesznek alkalmazva, majd a lista végén ismétlődnek. Támogatott a haladó szintaxis is: a '+5' minden rétegen +5°-kal forgat; a '+5#5' minden 5 rétegenként +5°-kal forgat. A részletekért lásd a Wikit. Ha sablon van megadva, a normál kitöltési irány beállítás figyelmen kívül marad. Megjegyzés: egyes kitöltési minták (pl. Gyroid) saját maguk kezelik a forgatást; körültekintően használd." +msgstr "A kitöltés irányát rétegenként forgatja egy szögsablon alapján. Adj meg vesszővel elválasztott fokértékeket (pl. '0,30,60,90'). A szögeket rétegenként, sorban alkalmazza, majd a lista végén elölről kezdi. A haladó szintaxis is használható: a '+5' minden rétegen +5°-kal forgat; a '+5#5' minden 5 rétegenként +5°-kal forgat. A részletekért lásd a Wikit. Ha megadsz egy sablont, a normál kitöltési irány beállítását figyelmen kívül hagyja. Megjegyzés: egyes kitöltési minták (pl. Gyroid) maguk kezelik a forgatást; körültekintően használd." msgid "Solid infill rotation template" msgstr "Tömör kitöltés forgatási sablonja" @@ -15029,13 +15075,13 @@ msgid "Skeleton infill density" msgstr "Vázkitöltés sűrűsége" msgid "The remaining part of the model contour after removing a certain depth from the surface is called the skeleton. This parameter is used to adjust the density of this section. When two regions have the same sparse infill settings but different skeleton densities, their skeleton areas will develop overlapping sections. Default is as same as infill density." -msgstr "A modell körvonalának a felületről egy bizonyos mélység eltávolítása után megmaradó részét vázként értelmezzük. Ez a paraméter ennek a résznek a sűrűségét szabályozza. Ha két régió ugyanazzal a ritka kitöltési beállítással, de eltérő vázsűrűséggel rendelkezik, a vázterületeik átfedésbe kerülnek. Alapértelmezés szerint megegyezik a kitöltési sűrűséggel." +msgstr "A modell körvonalának a felületről egy bizonyos mélység eltávolítása után megmaradó részét váznak nevezzük. Ez a paraméter ennek a résznek a sűrűségét szabályozza. Ha két régió kitöltési beállítása azonos, de a vázsűrűségük eltér, a vázterületeik átfedik egymást. Alapértelmezés szerint megegyezik a kitöltési sűrűséggel." msgid "Skin infill density" msgstr "Felületi kitöltés sűrűsége" msgid "The portion of the model's outer surface within a certain depth range is called the skin. This parameter is used to adjust the density of this section. When two regions have the same sparse infill settings but different skin densities, this area will not be split into two separate regions. Default is as same as infill density." -msgstr "A modell külső felületének egy adott mélységtartományba eső részét felületi rétegnek nevezzük. Ez a paraméter ennek a szakasznak a sűrűségét szabályozza. Ha két régió ugyanazzal a ritka kitöltési beállítással, de eltérő felületi réteg-sűrűséggel rendelkezik, ez a terület nem lesz két külön régióra bontva. Alapértelmezés szerint megegyezik a kitöltési sűrűséggel." +msgstr "A modell külső felületének egy adott mélységtartományba eső részét felületi rétegnek nevezzük. Ez a paraméter ennek a résznek a sűrűségét szabályozza. Ha két régió kitöltési beállítása azonos, de a felületi rétegük sűrűsége eltér, ez a terület nem válik két külön régióra. Alapértelmezés szerint megegyezik a kitöltési sűrűséggel." msgid "Skin infill depth" msgstr "Felületi kitöltés mélysége" @@ -15079,9 +15125,9 @@ msgid "" "\n" "Use either absolute mm values (eg. 0.32mm for a 0.4mm nozzle) or % values (eg 80%). This value must not be larger than the nozzle diameter." msgstr "" -"A kombinált ritka kitöltés maximális rétegmagassága.\n" +"A kombinált kitöltés maximális rétegmagassága.\n" "\n" -"Állítsd 0-ra vagy 100%-ra a fúvókaátmérő használatához (a nyomtatási idő maximális csökkentéséhez), vagy kb. 80%-ra a ritka kitöltés szilárdságának maximalizálásához.\n" +"Állítsd 0-ra vagy 100%-ra a fúvókaátmérő használatához (a nyomtatási idő lehető legnagyobb csökkentéséhez), vagy kb. 80%-ra a kitöltés szilárdságának maximalizálásához.\n" "\n" "Az a rétegszám, amelyen a kitöltés összevonásra kerül, úgy számolódik, hogy ezt az értéket elosztja a rétegmagassággal, majd lefelé kerekíti a legközelebbi egészre.\n" "\n" @@ -15149,7 +15195,7 @@ msgid "Maximum straightening angle used to simplify Lightning branches." msgstr "A Villám ágak egyszerűsítéséhez használt maximális kiegyenesítési szög." msgid "Sparse infill anchor length" -msgstr "Ritka kitöltés horgonyhossza" +msgstr "Kitöltés horgonyhossza" msgid "" "Connect an infill line to an internal perimeter with a short segment of an additional perimeter. If expressed as percentage (example: 15%) it is calculated over infill extrusion width. Orca Slicer tries to connect two close infill lines to a short perimeter segment. If no such perimeter segment shorter than infill_anchor_max is found, the infill line is connected to a perimeter segment at just one side and the length of the perimeter segment taken is limited to this parameter, but no longer than anchor_length_max.\n" @@ -15186,24 +15232,24 @@ msgstr "" "Az \"Alapértelmezett\" az aktív objektum/tárgy filamentjét használja." msgid "Line width of internal sparse infill. If expressed as a %, it will be computed over the nozzle diameter." -msgstr "A belső ritka kitöltés vonalszélessége. Ha százalékban van megadva, a fúvókaátmérő alapján lesz kiszámítva." +msgstr "A belső kitöltés vonalszélessége. Ha százalékban adod meg, a szeletelő a fúvókaátmérőből számítja ki." msgid "Infill/wall overlap" msgstr "Kitöltés/fal átfedés" #, no-c-format, no-boost-format msgid "This allows the infill area to be enlarged slightly to overlap with walls for better bonding. The percentage value is relative to line width of sparse infill. Set this value to ~10-15% to minimize potential over extrusion and accumulation of material resulting in rough top surfaces." -msgstr "A kitöltési terület kissé megnagyobbodik, hogy átfedésbe kerüljön a fallal a jobb kötés érdekében. A százalékos érték a ritka kitöltés vonalszélességéhez viszonyított. Állítsd ezt az értéket kb. 10-15%-ra a lehetséges túlextrudálás és az anyagfelhalmozódás minimalizálásához, amely érdes felső felületeket eredményezhet." +msgstr "A jobb kötés érdekében kissé megnöveli a kitöltési területet, hogy az átfedje a falat. A százalékos érték a kitöltés vonalszélességéhez viszonyított. Körülbelül 10-15%-os értékkel csökkenthető a túlextrudálás és az érdes felső felületet okozó anyagfelhalmozódás." msgid "Top/Bottom solid infill/wall overlap" msgstr "Felső/alsó tömör kitöltés és fal átfedése" #, no-c-format, no-boost-format msgid "Top solid infill area is enlarged slightly to overlap with wall for better bonding and to minimize the appearance of pinholes where the top infill meets the walls. A value of 25-30% is a good starting point, minimizing the appearance of pinholes. The percentage value is relative to line width of sparse infill." -msgstr "A felső tömör kitöltési terület kissé megnagyobbodik, hogy átfedésbe kerüljön a fallal a jobb kötés érdekében, és csökkentse a tűlyukszerű hibák megjelenését ott, ahol a felső kitöltés a falakkal találkozik. Jó kiindulási érték a 25-30%, amely segít minimalizálni a tűlyukak megjelenését. A százalékos érték a ritka kitöltés vonalszélességéhez viszonyított." +msgstr "A jobb kötés és a felső kitöltés falhoz csatlakozásánál megjelenő apró lyukak csökkentése érdekében kissé megnöveli a felső tömör kitöltés területét, hogy az átfedje a falat. Jó kiindulási érték a 25-30%. A százalékos érték a kitöltés vonalszélességéhez viszonyított." msgid "This is the speed for internal sparse infill." -msgstr "A belső ritkás kitöltés sebessége" +msgstr "A belső kitöltés sebessége" msgid "Inherits profile" msgstr "Örököli a profilt" @@ -15215,7 +15261,7 @@ msgid "Interface shells" msgstr "Érintkezőréteg-héjak" msgid "Force the generation of solid shells between adjacent materials/volumes. Useful for multi-extruder prints with translucent materials or manual soluble support material." -msgstr "Kikényszeríti a tömör héjak létrehozását a szomszédos anyagok/térfogatok között. Hasznos többextruderes nyomatoknál áttetsző anyagokkal vagy manuálisan oldható támaszanyag használatakor." +msgstr "Kikényszeríti a tömör héjak létrehozását a szomszédos anyagok vagy térfogatok között. Hasznos többextruderes nyomatoknál áttetsző anyagok, illetve kézzel létrehozott, oldható támaszok használatakor." msgid "Maximum width of a segmented region" msgstr "Szegmentált régió maximális szélessége" @@ -15318,7 +15364,7 @@ msgid "Ironing expansion" msgstr "Vasaló bővítés" msgid "Expand or contract the ironing area." -msgstr "A vasalási terület bővítése/szűkítése ." +msgstr "A vasalási terület bővítése vagy szűkítése." msgid "Z contouring enabled" msgstr "Z kontúrozás engedélyezve" @@ -15381,10 +15427,10 @@ msgstr "" "Ez az opció figyelmen kívül marad, ha a G-kód változat Klipperre van állítva." msgid "This G-code will be used as a code for the pause print. Users can insert pause G-code in the G-code viewer." -msgstr "Ez a G-kód lesz használva a nyomtatás szüneteltetéséhez. A felhasználók a szünet G-kódot a G-kódnézőben illeszthetik be." +msgstr "Ezt a G-kódot használja a nyomtatás szüneteltetéséhez. A szüneteltetési G-kódot a G-kódnézőben lehet beilleszteni." msgid "This G-code will be used as a custom code." -msgstr "Ezt a G-kód egyedi kódként lesz használva." +msgstr "Ezt a G-kódot egyedi kódként használja." msgid "Small area flow compensation (beta)" msgstr "Kis területű áramláskompenzáció (béta)" @@ -15423,7 +15469,7 @@ msgid "Maximum E speed" msgstr "Maximális E sebesség" msgid "Maximum acceleration X" -msgstr "Maximális sebesség X" +msgstr "Maximális gyorsulás X" msgid "Maximum acceleration Y" msgstr "Maximális gyorsulás Y" @@ -15579,8 +15625,8 @@ msgid "" "Disable turns off input shaping in the firmware." msgstr "" "Válaszd ki a rezgéskompenzáció algoritmust.\n" -"A Default a firmware alapértelmezett beállításait használja.\n" -"A letiltása kikapcsolja a rezgéskompenzációt a firmware-ben." +"Az Alapértelmezett a firmware alapértelmezett beállításait használja.\n" +"A Letiltás kikapcsolja a rezgéskompenzációt a firmware-ben." msgid "MZV" msgstr "MZV" @@ -15747,8 +15793,8 @@ msgid "" "Auxiliary fan speed will be ramped up linearly from layer \"For the first\" to maximum at layer \"Full fan speed at layer\".\n" "\"Full fan speed at layer\" will be ignored if lower than \"For the first\", in which case the fan will run at maximum allowed speed at layer \"For the first\" + 1." msgstr "" -"A segédventilátor sebessége lineárisan megemelkedik az \"Az első\" rétegtől a maximálisig a \"Teljes ventilátorsebesség\" rétegnél.\n" -"A rendszer figyelmen kívül hagyja a „teljes ventilátor fordulatszámot” ha alacsonyabb, mint „Az első”, ebben az esetben a ventilátor a maximális megengedett sebességgel fog működni „Az első” + 1 rétegben." +"A segédventilátor sebessége az „Az első” rétegtől lineárisan emelkedik, és a „Teljes ventilátor fordulatszám ennél a rétegnél” rétegnél éri el a maximumot.\n" +"Ha a „Teljes ventilátor fordulatszám ennél a rétegnél” értéke kisebb az „Az első” értékénél, a rendszer figyelmen kívül hagyja, és a ventilátor az „Az első” + 1. rétegen a megengedett maximális sebességgel működik." msgid "Special auxiliary cooling fan speed, effective only for the first x layers." msgstr "Speciális kiegészítő hűtőventilátor sebessége, csak az első x rétegeknél hatásos." @@ -15775,7 +15821,7 @@ msgid "Host Type" msgstr "Host típusa" msgid "Orca Slicer can upload G-code files to a printer host. This field must contain the kind of the host." -msgstr "A Orca Slicer képes G-kód fájlokat feltölteni a nyomtatóra. Ennek a mezőnek tartalmaznia kell a gazdagép típusát." +msgstr "Az Orca Slicer képes G-kód fájlokat feltölteni a nyomtatóra. Ennek a mezőnek a gazdagép típusát kell tartalmaznia." msgid "Nozzle volume" msgstr "Fúvóka térfogata" @@ -15811,7 +15857,7 @@ msgid "Extra loading distance" msgstr "Extra betöltési hossz" msgid "When set to zero, the distance the filament is moved from parking position during load is exactly the same as it was moved back during unload. When positive, it is loaded further, if negative, the loading move is shorter than unloading." -msgstr "Ha nullára van állítva, akkor a filamentet a betöltés során a parkolóhelyzetből pontosan ugyanannyira kerül előtolásra, mint amennyire a kiürítéskor vissza lett húzva. Ha pozitív, akkor tovább töltődik, ha negatív, akkor a betöltési mozgás rövidebb, mint a kiürítési." +msgstr "Nulla értéknél a filament betöltéskor pontosan akkora utat tesz meg a parkolóhelyzettől, amekkorát kiürítéskor visszahúzott. Pozitív értéknél tovább tölti be, negatív értéknél pedig a betöltési mozgás rövidebb a kiürítésinél." msgid "Start end points" msgstr "Kezdő- és végpontok" @@ -15916,7 +15962,7 @@ msgid "Change extrusion role G-code (process)" msgstr "Extrudálási szerepkör G-kód módosítása (folyamat)" msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code." -msgstr "Ez a G-kód akkor kerül beillesztésre, amikor az extrudálási szerep megváltozik. A gép és a filament extrudálási szerepkör G-kódja után fut." +msgstr "Az Orca Slicer az extrudálási szerep megváltozásakor illeszti be ezt a G-kódot. A gép és a filament extrudálási szerepéhez tartozó G-kód után fut le." # AI Translated msgid "Plugins Used" @@ -15949,7 +15995,7 @@ msgid "Raft contact Z distance" msgstr "Tutaj érintkezési Z-távolság" msgid "Z gap between raft and object. If Support Top Z Distance is 0, this value is ignored and the object is printed in direct contact with the raft (no gap)." -msgstr "Z rés a tutaj és a tárgy között. Ha a támasz felső Z-távolsága 0, ez az érték figyelmen kívül lesz hagyva és a tárgy közvetlenül a tutajon kerül nyomtatásra (rés nélkül)." +msgstr "Z-rés a tutaj és a tárgy között. Ha a támasz felső Z-távolsága 0, a szeletelő figyelmen kívül hagyja ezt az értéket, és a tárgyat közvetlenül a tutajra nyomtatja (rés nélkül)." msgid "Raft expansion" msgstr "Tutaj kibővítése" @@ -15967,7 +16013,7 @@ msgid "First layer expansion" msgstr "Első réteg kiterjesztése" msgid "This expands the first raft or support layer to improve bed adhesion." -msgstr "Az első tutaj- vagy támaszréteg kiterjesztése a tárgyasztalhoz való tapadás javítása érdekében." +msgstr "Az első tutaj- vagy támaszréteg kiterjesztése az asztalhoz való tapadás javítása érdekében." msgid "Raft layers" msgstr "Tutajrétegek" @@ -16019,7 +16065,7 @@ msgid "Long retraction when cut (beta)" msgstr "Hosszú visszahúzás vágáskor (béta)" msgid "Experimental feature: Retracting and cutting off the filament at a longer distance during changes to minimize purge. While this reduces flush significantly, it may also raise the risk of nozzle clogs or other printing problems." -msgstr "Kísérleti funkció: Filamentváltás közben nagyobb távolságról történő visszahúzás és vágás a kiürítés minimalizálása érdekében. Bár ez jelentősen csökkenti az öblítést, növelheti a fúvóka eltömődésének vagy más nyomtatási problémáknak a kockázatát." +msgstr "Kísérleti funkció: Filamentváltás közben nagyobb távolságról történő visszahúzás és vágás az öblítés minimalizálása érdekében. Bár ez jelentősen csökkenti az öblítést, növelheti a fúvóka eltömődésének vagy más nyomtatási problémáknak a kockázatát." msgid "Retraction distance when cut" msgstr "Visszahúzási távolság vágáskor" @@ -16183,7 +16229,7 @@ msgid "Back" msgstr "Hátul" msgid "Random" -msgstr "Véletlenszerû" +msgstr "Véletlenszerű" msgid "Staggered inner seams" msgstr "Eltolt belső varratok" @@ -16211,7 +16257,7 @@ msgid "Conditional scarf joint" msgstr "Feltételes átlapolt illesztés" msgid "Apply scarf joints only to smooth perimeters where traditional seams do not conceal the seams at sharp corners effectively." -msgstr "Átlapolt illesztést csak sima kerületeknél alkalmazzon, ahol a hagyományos varratok nem rejtik el hatékonyan a varratot az éles sarkoknál." +msgstr "Csak olyan sima kerületeken alkalmaz átlapolt illesztést, ahol nincsenek éles sarkok, amelyek hatékonyan elrejtenék a hagyományos varratot." msgid "Conditional angle threshold" msgstr "Feltételes szögküszöb" @@ -16228,7 +16274,7 @@ msgstr "Feltételes túlnyúlási küszöb" #, no-c-format, no-boost-format msgid "This option determines the overhang threshold for the application of scarf joint seams. If the unsupported portion of the perimeter is less than this threshold, scarf joint seams will be applied. The default threshold is set at 40% of the external wall's width. Due to performance considerations, the degree of overhang is estimated." -msgstr "Ez az opció meghatározza az átlapolt varratok alkalmazásának túlnyúlási küszöbét. Ha a kerület alá nem támasztott része kisebb ennél a küszöbnél, átlapolt varrat kerül alkalmazásra. Az alapértelmezett küszöb a külső fal szélességének 40%-a. Teljesítménybeli okokból a túlnyúlás mértéke becsült érték." +msgstr "Ez a beállítás határozza meg az átlapolt varratok túlnyúlási küszöbét. Ha a kerület alá nem támasztott része kisebb ennél a küszöbnél, a szeletelő átlapolt varratot alkalmaz. Az alapértelmezett küszöb a külső fal szélességének 40%-a. Teljesítménybeli okokból a túlnyúlás mértéke csak becsült érték." msgid "Scarf joint speed" msgstr "Átlapolt varrat sebessége" @@ -16237,7 +16283,7 @@ msgid "This option sets the printing speed for scarf joints. It is recommended t msgstr "Ez az opció beállítja az átlapolt varratok nyomtatási sebességét. Ajánlott az átlapolt varratokat alacsony sebességgel nyomtatni (100 mm/s alatt). Az is javasolt, hogy kapcsold be az \"Extrudálási sebesség simítását\", ha az itt megadott sebesség jelentősen eltér a külső vagy belső fal sebességétől. Ha az itt megadott sebesség nagyobb, mint a külső vagy belső fal sebessége, a nyomtató a kettő közül a lassabbat fogja használni. Ha százalékban van megadva (pl. 80%), a sebesség a megfelelő külső vagy belső fali sebesség alapján lesz kiszámítva. Az alapértelmezett érték 100%." msgid "Scarf joint flow ratio" -msgstr "Átlapolt varrat áramlási aránya" +msgstr "Átlapolt varrat anyagáramlása" msgid "This factor affects the amount of material for scarf joints." msgstr "Ez a tényező az átlapolt varratokhoz felhasznált anyag mennyiségét befolyásolja." @@ -16339,7 +16385,7 @@ msgid "" "Enabled = skirt is as tall as the highest printed object. Otherwise 'Skirt height' is used.\n" "Note: With the draft shield active, the skirt will be printed at skirt distance from the object. Therefore, if brims are active it may intersect with them. To avoid this, increase the skirt distance value.\n" msgstr "" -"A huzatvédő hasznos lehet az ABS vagy ASA nyomatok kunkorodásának és a tárgyasztalról való leválásának megelőzésére, amelyet légmozgás okozhat. Általában csak nyitott vázas, azaz burkolat nélküli nyomtatóknál van rá szükség.\n" +"A huzatvédő segíthet megelőzni, hogy a légmozgás miatt az ABS- vagy ASA-nyomatok felkunkorodjanak és leváljanak az asztalról. Általában csak nyitott vázas, azaz burkolat nélküli nyomtatóknál van rá szükség.\n" "\n" "Engedélyezve = a szoknya olyan magas lesz, mint a legmagasabb nyomtatott objektum. Ellenkező esetben a \"Szoknya magassága\" érték kerül használatra.\n" "Megjegyzés: Aktív huzatvédő mellett a szoknya az objektumtól mért szoknyatávolságban lesz nyomtatva. Ezért ha perem is aktív, metszheti azt. Ennek elkerüléséhez növeld a szoknyatávolság értékét.\n" @@ -16384,13 +16430,13 @@ msgstr "" "A hurkok végső száma nincs figyelembe véve az objektumok elrendezésekor vagy távolságának ellenőrzésekor. Ilyen esetben növeld a hurkok számát." msgid "The printing speed in exported G-code will be slowed down when the estimated layer time is shorter than this value in order to get better cooling for these layers." -msgstr "A nyomtatási sebesség az exportált G-kódban csökkentésre kerül, ha a becsült rétegidő kisebb, mint ez az érték, hogy a rétegek jobb hűtése biztosított legyen." +msgstr "Ha a becsült rétegidő kisebb ennél az értéknél, az exportált G-kód csökkenti a nyomtatási sebességet a rétegek jobb hűtése érdekében." msgid "Minimum sparse infill threshold" -msgstr "Ritkás kitöltés küszöbértéke" +msgstr "Kitöltés küszöbértéke" msgid "Sparse infill areas which are smaller than this threshold value are replaced by internal solid infill." -msgstr "Az ennél a küszöbértéknél kisebb ritka kitöltési területek belső tömör kitöltéssel helyettesítődnek." +msgstr "Az ennél a küszöbértéknél kisebb kitöltési területeket belső tömör kitöltéssel helyettesíti." # AI Translated msgid "" @@ -16420,7 +16466,7 @@ msgid "Line width of internal solid infill. If expressed as a %, it will be comp msgstr "A belső tömör kitöltés vonalszélessége. Ha százalékban van megadva, a fúvókaátmérő alapján lesz kiszámítva." msgid "This is the speed for internal solid infill, not including the top or bottom surface." -msgstr "A belső szilárd kitöltés sebessége, de az az érték nem vonatkozik a felső és alsó felületre" +msgstr "A belső tömör kitöltés sebessége; nem vonatkozik a felső és alsó felületre" msgid "This enables spiraling, which smooths out the Z moves of the outer contour and turns a solid model into a single walled print with solid bottom layers. The final generated model has no seam." msgstr "A spirál mód kisimítja a külső kontúr Z mozgásait. A tömör modellt egyfalú nyomatokká alakítja, tömör alsó rétegekkel. A végső modellen nincsenek varratok" @@ -16439,21 +16485,21 @@ msgid "Maximum distance to move points in XY to try to achieve a smooth spiral. msgstr "A pontok XY irányban történő maximális elmozdítása a sima spirál elérése érdekében. Ha százalékban van megadva, a fúvókaátmérő alapján lesz kiszámítva." msgid "Spiral starting flow ratio" -msgstr "Spirál kezdő áramlási aránya" +msgstr "Spirál kezdő anyagáramlása" #, no-c-format, no-boost-format msgid "Sets the starting flow ratio while transitioning from the last bottom layer to the spiral. Normally the spiral transition scales the flow ratio from 0% to 100% during the first loop which can in some cases lead to under extrusion at the start of the spiral." -msgstr "Beállítja a kezdő áramlási arányt az utolsó alsó rétegről a spirálra való átmenet során. Normál esetben a spirálra váltás az első hurok alatt 0%-ról 100%-ra skálázza az áramlási arányt, ami egyes esetekben alulextrudálást okozhat a spirál elején." +msgstr "Beállítja az anyagáramlás kezdőértékét az utolsó alsó rétegről a spirálra való átmenet során. Normál esetben a spirálra váltás az első hurok alatt 0%-ról 100%-ra növeli az anyagáramlást, ami egyes esetekben alulextrudálást okozhat a spirál elején." msgid "Spiral finishing flow ratio" -msgstr "Spirál befejező áramlási aránya" +msgstr "Spirál befejező anyagáramlása" #, no-c-format, no-boost-format msgid "Sets the finishing flow ratio while ending the spiral. Normally the spiral transition scales the flow ratio from 100% to 0% during the last loop which can in some cases lead to under extrusion at the end of the spiral." -msgstr "Beállítja a befejező áramlási arányt a spirál lezárásakor. Normál esetben a spirál lezárása az utolsó hurok alatt 100%-ról 0%-ra skálázza az áramlási arányt, ami egyes esetekben alulextrudálást okozhat a spirál végén." +msgstr "Beállítja az anyagáramlás befejező értékét a spirál lezárásakor. Normál esetben a spirál lezárása az utolsó hurok alatt 100%-ról 0%-ra csökkenti az anyagáramlást, ami egyes esetekben alulextrudálást okozhat a spirál végén." msgid "If smooth or traditional mode is selected, a timelapse video will be generated for each print. After each layer is printed, a snapshot is taken with the chamber camera. All of these snapshots are composed into a timelapse video when printing completes. If smooth mode is selected, the toolhead will move to the excess chute after each layer is printed and then take a snapshot. Since the melt filament may leak from the nozzle during the process of taking a snapshot, a prime tower is required for smooth mode to wipe the nozzle." -msgstr "Ha a sima vagy a hagyományos mód van kiválasztva, minden nyomtatásnál készül egy időfelvétel-videó. Az egyes rétegek kinyomtatása után a beépített kamera egy képet készít. A nyomtatás befejeződése után aztán ezeket a képeket a szoftver egy videóvá fűzi össze. Ha a sima mód van kiválasztva, a réteg nyomtatása után a nyomtatófej a kidobónyíláshoz mozog, majd a kamera egy képet készít. Mivel a kép készítése során szivároghat valamennyi olvadt filament a fúvókából, egy törlőtoronyra van szükség a fúvóka megtisztításához." +msgstr "Sima vagy hagyományos módban minden nyomtatásról Timelapse-videó készül. Az egyes rétegek után a beépített kamera fényképet készít, majd a nyomtatás végén a szoftver videóvá fűzi össze a képeket. Sima módban a szerszámfej minden réteg után a kidobónyíláshoz mozog, mielőtt a kamera elkészíti a képet. Mivel eközben olvadt filament szivároghat a fúvókából, a fúvóka megtisztításához törlőtorony szükséges." msgid "Traditional" msgstr "Hagyományos" @@ -16467,14 +16513,14 @@ msgstr "Timelapse a legtávolabbi pontban" # AI Translated msgid "When enabled, the timelapse snapshot is taken at the farthest point from camera instead of traveling to the wipe tower or excess chute. Only effective in traditional timelapse mode on non-I3 printers." -msgstr "Bekapcsolva a timelapse felvétel a kamerától legtávolabbi pontban készül, ahelyett hogy a nyomtatófej a törlőtoronyhoz vagy a hulladékcsatornához mozogna. Csak a hagyományos timelapse módban, nem I3 felépítésű nyomtatókon működik." +msgstr "Bekapcsolva a Timelapse-felvétel a kamerától legtávolabbi pontban készül, ahelyett hogy a szerszámfej a törlőtoronyhoz vagy a hulladékcsatornához mozogna. Csak hagyományos Timelapse módban és nem I3 felépítésű nyomtatókon működik." msgid "Temperature variation" msgstr "Hőmérséklet változás" #. TRN PrintSettings : "Ooze prevention" > "Temperature variation" msgid "Temperature difference to be applied when an extruder is not active. The value is not used when 'idle_temperature' in filament settings is set to non-zero value." -msgstr "Az az alkalmazandó hőmérséklet-különbség, amikor egy extruder nem aktív. Ez az érték nem kerül felhasználásra, ha a filament beállításokban az 'idle_temperature' nem nulla értékre van állítva." +msgstr "A nem aktív extrudernél alkalmazott hőmérséklet-különbség. A rendszer figyelmen kívül hagyja ezt az értéket, ha a filamentbeállításokban az 'idle_temperature' értéke nem nulla." msgid "∆℃" msgstr "∆℃" @@ -16510,16 +16556,16 @@ msgid "Use single nozzle to print multi filament." msgstr "Egyetlen fúvóka használata többféle filament nyomtatásához." msgid "Manual Filament Change" -msgstr "Manuális filamentcsere" +msgstr "Kézi filamentcsere" msgid "Enable this option to omit the custom Change filament G-code only at the beginning of the print. The tool change command (e.g., T0) will be skipped throughout the entire print. This is useful for manual multi-material printing, where we use M600/PAUSE to trigger the manual filament change action." -msgstr "Engedélyezd ezt az opciót, hogy az egyedi Filamentcsere G-kód csak a nyomtatás elején maradjon ki. A szerszámváltási parancs (pl. T0) a teljes nyomtatás során ki lesz hagyva. Ez manuális többanyagú nyomtatásnál hasznos, ahol az M600/PAUSE parancsot használjuk a manuális filamentcsere elindítására." +msgstr "Engedélyezd ezt a beállítást, ha csak a nyomtatás elején szeretnéd kihagyni az egyéni Filamentcsere G-kódot. A szerszámváltási parancsok (pl. T0) a teljes nyomtatás során kimaradnak. Ez kézi többanyagos nyomtatásnál hasznos, ahol az M600/PAUSE paranccsal indítható el a kézi filamentcsere." msgid "Wipe tower type" msgstr "Törlőtorony típusa" msgid "Choose the wipe tower implementation for multi-material prints. Type 1 is recommended for Bambu and Qidi printers with a filament cutter. Type 2 offers better compatibility with multi-tool and MMU printers and provide overall better compatibility." -msgstr "Válassza ki a törlőtorony megvalósítását a többanyagos nyomtatáshoz. Az 1. típus ajánlott a Bambu és Qidi nyomtatókhoz szálvágóval. A 2. típus jobb kompatibilitást kínál a többszerszámos és MMU nyomtatókkal, és összességében jobb kompatibilitást biztosít." +msgstr "Válaszd ki a törlőtorony megvalósítását a többanyagos nyomtatáshoz. Az 1. típus ajánlott a szálvágóval felszerelt Bambu és Qidi nyomtatókhoz. A 2. típus jobb kompatibilitást kínál a többszerszámos és MMU nyomtatókkal." msgid "Type 1" msgstr "1. típus" @@ -16528,10 +16574,10 @@ msgid "Type 2" msgstr "2. típus" msgid "Purge in prime tower" -msgstr "Kiürítés a törlőtoronyban" +msgstr "Öblítés a törlőtoronyban" msgid "Purge remaining filament into prime tower." -msgstr "A megmaradt filament kiürítése a törlőtoronyba." +msgstr "A megmaradt filament öblítése a törlőtoronyba." msgid "Enable filament ramming" msgstr "Filament tömörítés engedélyezése" @@ -16540,19 +16586,19 @@ msgid "Tool change on wipe tower" msgstr "Szerszámcsere a törlőtoronyban" msgid "Force the toolhead to travel to the wipe tower before issuing the tool change command (Tx). Only relevant for multi-extruder (multi-toolhead) printers using a Type 2 wipe tower. By default Orca skips the travel on multi-toolhead machines because the firmware handles the head swap, which can result in the Tx command being issued above the printed part. Enable this option if you want the tool change to always be issued above the wipe tower instead." -msgstr "A szerszámcsere parancs (Tx) kiadása előtt kényszerítse a szerszámfejet a törlőtoronyhoz. Csak a 2-es típusú törlőtornyot használó többextruderes (több szerszámfejes) nyomtatóknál releváns. Alapértelmezés szerint az Orca kihagyja az utazást a több szerszámfejes gépeken, mert a firmware kezeli a fejcserét, ami azt eredményezheti, hogy a Tx parancs a nyomtatott rész felett kerül kiadásra. Engedélyezd ezt az opciót, ha azt szeretnéd, hogy a szerszámcsere mindig a törlőtorony felett történjen." +msgstr "A szerszámcsere parancs (Tx) kiadása előtt a törlőtoronyhoz mozgatja a szerszámfejet. Csak a 2-es típusú törlőtornyot használó többextruderes (több szerszámfejes) nyomtatóknál van jelentősége. Az Orca alapértelmezés szerint kihagyja ezt a mozgást a több szerszámfejes gépeknél, mert a fejcserét a firmware kezeli. Emiatt azonban előfordulhat, hogy a Tx parancsot a nyomtatott tárgy felett adja ki. Kapcsold be ezt a beállítást, ha azt szeretnéd, hogy a szerszámcsere mindig a törlőtorony felett történjen." msgid "No sparse layers (beta)" msgstr "Nincsenek ritka rétegek (béta)" msgid "If enabled, the wipe tower will not be printed on layers with no tool changes. On layers with a tool change, extruder will travel downward to print the wipe tower. User is responsible for ensuring there is no collision with the print." -msgstr "Ha engedélyezve van, akkor törlőtorony nem kerül kinyomtatásra szerszámváltás nélküli rétegeken. A szerszámcserével rendelkező rétegeken az extruder az aktuális magasság alá süllyed a törlőtorony nyomtatásához. A felhasználó felelős azért, hogy ez ne okozzon ütközést a nyomtatás során." +msgstr "Ha engedélyezed, nem készül törlőtorony azokon a rétegeken, ahol nincs szerszámváltás. A szerszámváltást tartalmazó rétegeknél az extruder az aktuális magasság alá süllyed a törlőtorony nyomtatásához. Ügyelj arra, hogy ez ne okozzon ütközést a nyomtatás során." msgid "Prime all printing extruders" msgstr "Az összes nyomtató extruder előkészítése" msgid "If enabled, all printing extruders will be primed at the front edge of the print bed at the start of the print." -msgstr "Ha engedélyezve van, akkor a nyomtatás kezdetén az összes nyomtató extruder előkészítésre kerül a tárgyasztal elülső szélénél." +msgstr "Bekapcsolva a nyomtatás kezdetén minden extrudert előkészít az asztal elülső szélénél." # AI Translated msgid "Toolchange ordering" @@ -16576,7 +16622,7 @@ msgid "Slice gap closing radius" msgstr "Szeletelési hézag lezárási sugara" msgid "Cracks smaller than 2x gap closing radius are being filled during the triangle mesh slicing. The gap closing operation may reduce the final print resolution, therefore it is advisable to keep the value reasonably low." -msgstr "A háromszögháló szeletelés során a szeletelési hézag lezárási sugaránál 2x kisebb résekk feltöltésre kerülnek. A hézagok lezárása csökkentheti a nyomtatási felbontást, ezért ajánlott ezt az értéket alacsonyan tartani." +msgstr "A háromszögháló szeletelésekor kitölti a hézagzárási sugár kétszeresénél kisebb repedéseket. A hézagok lezárása csökkentheti a nyomtatási felbontást, ezért érdemes ezt az értéket viszonylag alacsonyan tartani." msgid "Slicing Mode" msgstr "Szeletelési mód" @@ -16600,7 +16646,7 @@ msgid "Z offset" msgstr "Z ofszet" msgid "This value will be added (or subtracted) from all the Z coordinates in the output G-code. It is used to compensate for bad Z endstop position: for example, if your endstop zero actually leaves the nozzle 0.3mm far from the print bed, set this to -0.3 (or fix your endstop)." -msgstr "Ez az érték hozzáadódik (vagy kivonásra kerül) az összes Z koordinátához a kimeneti G-kódban. A Z tengely végállás pozíciójának kompenzálására szolgál: például ha a végállás nullája valójában 0,3 mm-re hagyja a fúvókát a tárgyasztal felett, akkor állítsa ezt az értéke -0,3-ra (vagy javítsa meg a végállást)." +msgstr "Ez az érték a kimeneti G-kód minden Z-koordinátáját ennyivel növeli vagy csökkenti. A hibás Z-végálláshelyzet kompenzálására szolgál: például ha a végállás nullpontján a fúvóka valójában 0,3 mm-re marad az asztaltól, állítsd ezt az értéket -0,3-ra (vagy javítsd ki a végállást)." msgid "Enable support" msgstr "Támasz engedélyezése" @@ -16609,19 +16655,19 @@ msgid "This enables support generation." msgstr "Engedélyezi a támasz generálását." msgid "Normal (auto) and Tree (auto) are used to generate support automatically. If Normal (manual) or Tree (manual) is selected, only support enforcers are generated." -msgstr "A normál (auto) és a fa (auto) a támaszok automatikus generálásához van használva. Ha a normál (kézi) vagy a fa (kézi) van kiválasztva, akkor csak a kényszerített támaszok kerülnek generálásra." +msgstr "A Normál (automatikus) és a Fa (automatikus) beállítás automatikusan hozza létre a támaszokat. A Normál (kézi) és a Fa (kézi) beállítás csak a kijelölt támaszkényszerítőknél hoz létre támaszt." msgid "Normal (auto)" -msgstr "normál (auto)" +msgstr "Normál (automatikus)" msgid "Tree (auto)" -msgstr "fa (auto)" +msgstr "Fa (automatikus)" msgid "Normal (manual)" -msgstr "normál (manuális)" +msgstr "Normál (kézi)" msgid "Tree (manual)" -msgstr "fa (manuális)" +msgstr "Fa (kézi)" msgid "Support/object XY distance" msgstr "Támasz/tárgy XY távolság" @@ -16642,16 +16688,16 @@ msgid "Use this setting to rotate the support pattern on the horizontal plane." msgstr "Ezzel a beállítással elforgathatod a támasz mintázatát a vízszintes síkon." msgid "On build plate only" -msgstr "Csak a tárgyasztaltól" +msgstr "Csak az asztalról" msgid "This setting only generates supports that begin on the build plate." -msgstr "Nem generál támaszt a modell felületén, csak a tárgyasztalon" +msgstr "Nem hoz létre támaszt a modell felületén, csak az asztalon" msgid "Support critical regions only" msgstr "Csak a kritikus területek alátámasztása" msgid "Only create support for critical regions including sharp tail, cantilever, etc." -msgstr "Csak olyan kritikus területekhez generál támasztékot, mint például egy farok vagy egyéb kiálló részek." +msgstr "Csak olyan kritikus területekhez hoz létre támaszt, mint például egy farok vagy más kiálló részek." msgid "Ignore small overhangs" msgstr "Kis túlnyúlások mellőzése" @@ -16669,7 +16715,7 @@ msgid "Bottom Z distance" msgstr "Alsó Z távolság" msgid "Z gap between the object and the support bottom. If Support Top Z Distance is 0 and the bottom has interface layers, this value is ignored and the support is printed in direct contact with the object (no gap)." -msgstr "Z rés a tárgy és a támasz alja között. Ha a támasz felső Z-távolsága 0 és az alján vannak interfész rétegek, ez az érték figyelmen kívül lesz hagyva, és a támasz közvetlenül a tárgyhoz lesz nyomtatva (rés nélkül)." +msgstr "Z-rés a tárgy és a támasz alja között. Ha a támasz felső Z-távolsága 0, és alul érintkezőrétegek vannak, a szeletelő figyelmen kívül hagyja ezt az értéket, és a támaszt közvetlenül a tárgyra nyomtatja (rés nélkül)." msgid "Support/raft base" msgstr "Támasz/tutaj alap" @@ -16698,7 +16744,7 @@ msgid "This covers the top contact layer of the supports with loops. It is disab msgstr "Lefedi a támasz felső érintkező rétegét körökkel. Alapértelmezés szerint letiltva." msgid "Support/raft interface" -msgstr "Támasz/tutaj interfész" +msgstr "Támasz/tutaj érintkező felülete" # AI Translated msgid "" @@ -16828,8 +16874,8 @@ msgid "" "Support will be generated for overhangs whose slope angle is below the threshold. The smaller this value is, the steeper the overhang that can be printed without support.\n" "Note: If set to 0, normal supports use the Threshold overlap instead, while tree supports fall back to a default value of 30." msgstr "" -"Az olyan túlnyúlásoknál, amelynek dőlésszöge ez alatt az érték alatt van, támasz fog generálódni.Minél kisebb ez az érték, annál meredekebb a túlnyúlás, amely alátámasztás nélkül nyomtatható.\n" -"Megjegyzés: Ha 0-ra van állítva, a normál támaszok a Küszöbátfedést használják, míg a fa típusú támaszok az alapértelmezett 30-as értékre térnek vissza." +"Azokhoz a túlnyúlásokhoz készül támasz, amelyek dőlésszöge a küszöbérték alatt van. Minél kisebb ez az érték, annál meredekebb túlnyúlás nyomtatható támasz nélkül.\n" +"Megjegyzés: 0 értéknél a normál támaszok helyette az átfedési küszöbértéket használják, a fatámaszok pedig visszaállnak az alapértelmezett 30-as értékre." msgid "Threshold overlap" msgstr "Átfedési küszöbérték" @@ -16864,16 +16910,16 @@ msgid "Adjusts the density of the support structure used to generate the tips of msgstr "Az ágak csúcsainak létrehozásához használt támaszszerkezet sűrűségét állítja be. A nagyobb érték jobb túlnyúlásokat eredményez, viszont a támaszokat nehezebb eltávolítani, ezért ha sűrű érintkező felületre van szükség, inkább a felső támaszérintkező felületek engedélyezése javasolt a magas ágsűrűségérték helyett." msgid "Auto brim width" -msgstr "Automatikus karimaszélesség" +msgstr "Automatikus peremszélesség" msgid "Enabling this option means the width of the brim for tree support will be automatically calculated." -msgstr "Ennek az opciónak az engedélyezése azt jelenti, hogy a fa támasz karimájának szélessége automatikusan lesz kiszámítva." +msgstr "Bekapcsolva automatikusan kiszámítja a fatámasz peremének szélességét." msgid "Tree support brim width" -msgstr "Fa támasz karimaszélessége" +msgstr "Fatámasz peremszélessége" msgid "Distance from tree branch to the outermost brim line." -msgstr "A távolság a fa támasz ágától a legkülső karimavonalig." +msgstr "A fatámasz ágának és a legkülső peremvonalnak a távolsága." msgid "Tip Diameter" msgstr "Csúcsátmérő" @@ -16978,19 +17024,19 @@ msgid "Detect thin walls" msgstr "Vékony falak felismerése" msgid "This detects thin walls which can’t contain two lines and uses a single line to print. It may not print as well because it’s not a closed loop." -msgstr "Felismeri a vékony falakat, amellyeket nem lehet két vonalnyi szélességgel nyomtatni, és egyetlen vonalt használ. Lehet nem jó a nyomat minősége, mert nem zárt hurok." +msgstr "Felismeri azokat a vékony falakat, amelyekben nem fér el két vonal, és egyetlen vonallal nyomtatja ki őket. A nyomtatási minőség gyengébb lehet, mert ez a vonal nem alkot zárt hurkot." msgid "This G-code is inserted when filament is changed, including T commands to trigger tool change." -msgstr "Ez a G-kód kerül beillesztésre, amikor a filament csere történik, beleértve a szerszámváltást indító T parancsokat is." +msgstr "Az Orca Slicer filamentcserekor illeszti be ezt a G-kódot, beleértve a szerszámváltást indító T parancsokat is." msgid "This G-code is inserted when the extrusion role is changed." -msgstr "Ez a G-kód akkor kerül beillesztésre, amikor az extrudálási szerep megváltozik." +msgstr "Az Orca Slicer az extrudálási szerep megváltozásakor illeszti be ezt a G-kódot." msgid "Change extrusion role G-code (filament)" msgstr "Az extrudálási szerep G-kódjának módosítása (szál)" msgid "This G-code is inserted when the extrusion role is changed for the active filament." -msgstr "Ez a G-kód akkor kerül beillesztésre, amikor az aktív filament extrudálási szerepe megváltozik." +msgstr "Az Orca Slicer akkor illeszti be ezt a G-kódot, amikor megváltozik az aktív filament extrudálási szerepe." msgid "Line width for top surfaces. If expressed as a %, it will be computed over the nozzle diameter." msgstr "A felső felületek vonalszélessége. Ha %-ban van megadva, a rendszer a fúvóka átmérője alapján számítja ki." @@ -17061,7 +17107,7 @@ msgid "Wipe while retracting" msgstr "Törlés visszahúzás közben" msgid "This moves the nozzle along the last extrusion path when retracting to clean any leaked material on the nozzle. This can minimize blobs when printing a new part after traveling." -msgstr "Ez visszahúzáskor a fúvókát az utolsó extrudálási útvonal mentén mozgatja, hogy a fúvókából szivárgott anyagot eltávolítsa. Ez minimálisra csökkentheti a pöttyöket, amikor a nyomtatófej a mozgást követően egy egy új alkatrész nyomtatásába kezd." +msgstr "Ez visszahúzáskor a fúvókát az utolsó extrudálási útvonal mentén mozgatja, hogy eltávolítsa a kiszivárgott anyagot. Így kevesebb anyagcsomó keletkezhet, amikor a szerszámfej a mozgás után új tárgy nyomtatásába kezd." msgid "Wipe distance" msgstr "Törlési távolság" @@ -17138,7 +17184,7 @@ msgid "Wipe tower rotation angle with respect to X axis." msgstr "Törlőtorony forgatási szöge az x-tengelyhez képest." msgid "Brim width of prime tower, negative number means auto calculated width based on the height of prime tower." -msgstr "A törlőtorony karimájának szélessége. Negatív szám esetén a szélesség automatikusan, a törlőtorony magassága alapján kerül kiszámításra." +msgstr "A törlőtorony peremének szélessége. Negatív értéknél a szeletelő automatikusan, a törlőtorony magassága alapján számítja ki a szélességet." msgid "Stabilization cone apex angle" msgstr "Stabilizáló kúp csúcsszöge" @@ -17160,7 +17206,7 @@ msgid "" "\n" "For the wipe tower external perimeters the internal perimeter speed is used regardless of this setting." msgstr "" -"A maximális nyomtatási sebesség öblítéskor a törlőtoronyban, valamint a törlőtorony ritka rétegeinek nyomtatásakor. Öblítés közben, ha a ritka kitöltés sebessége vagy a filament maximális térfogati sebességéből számolt sebesség alacsonyabb, akkor a kisebbik érték lesz használva.\n" +"A maximális nyomtatási sebesség öblítéskor a törlőtoronyban, valamint a törlőtorony ritka rétegeinek nyomtatásakor. Öblítés közben, ha a kitöltés sebessége vagy a filament maximális térfogati sebességéből számolt sebesség alacsonyabb, a kisebbik értéket használja.\n" "\n" "A ritka rétegek nyomtatásakor, ha a belső kerület sebessége vagy a filament maximális térfogati sebességéből számolt sebesség alacsonyabb, akkor a kisebbik érték lesz használva.\n" "\n" @@ -17194,7 +17240,7 @@ msgid "Extra rib length" msgstr "Extra bordahossz" msgid "Positive values can increase the size of the rib wall, while negative values can reduce the size. However, the size of the rib wall can not be smaller than that determined by the cleaning volume." -msgstr "A pozitív értékek növelhetik a bordafal méretét, míg a negatív értékek csökkenthetik azt. A bordafal mérete azonban nem lehet kisebb annál, mint amit a kiürítési mennyiség meghatároz." +msgstr "A pozitív értékek növelhetik, a negatív értékek pedig csökkenthetik a bordafal méretét. A bordafal azonban nem lehet kisebb az öblítési térfogat által meghatározott méretnél." msgid "Rib width" msgstr "Bordaszélesség" @@ -17209,13 +17255,13 @@ msgid "The wall of prime tower will fillet." msgstr "A törlőtorony fala lekerekített lesz." msgid "The extruder to use when printing perimeter of the wipe tower. Set to 0 to use the one that is available (non-soluble would be preferred)." -msgstr "Az a extruder, amelyet a törlőtorony kerületének nyomtatásához kell használni. Állítsd 0-ra, ha az éppen elérhető extrudert szeretnéd használni (előnyösítve a nem oldhatót)." +msgstr "A törlőtorony kerületének nyomtatásához használt extruder. Állítsd 0-ra az éppen elérhető extruder használatához; lehetőség szerint nem oldható filamentet választ." msgid "Purging volumes - load/unload volumes" msgstr "Kiürítési mennyiségek - betöltési/kirakodási mennyiségek" msgid "This vector saves required volumes to change from/to each tool used on the wipe tower. These values are used to simplify creation of the full purging volumes below." -msgstr "Ez a vektor eltárolja a törlőtornyon használt egyes szerszámokra/szerszámokról való váltáshoz szükséges mennyiségeket. Ezek az értékek az alábbi teljes kiürítési mennyiségek létrehozásának egyszerűsítésére szolgálnak." +msgstr "Ez a vektor tárolja a törlőtornyon használt egyes szerszámokra és szerszámokról való váltáshoz szükséges térfogatokat. Ezek az értékek egyszerűsítik az alábbi teljes öblítési térfogatok létrehozását." msgid "Skip points" msgstr "Pontok kihagyása" @@ -17242,31 +17288,31 @@ msgid "Infill gap." msgstr "Kitöltési hézag." msgid "Purging after filament change will be done inside objects' infills. This may lower the amount of waste and decrease the print time. If the walls are printed with transparent filament, the mixed color infill will be visible. It will not take effect unless the prime tower is enabled." -msgstr "A filamentcsere utáni kiürítés az objektumok kitöltésén belül történik. Ez csökkentheti a hulladék mennyiségét és a nyomtatási időt. Ha a falakat átlátszó filamenttel nyomtatod, a vegyes színű kitöltés látható lesz. Ez az opció csak akkor működik, ha a törlőtorony engedélyezve van." +msgstr "A filamentcsere utáni öblítés az objektumok kitöltésén belül történik. Ez csökkentheti a hulladék mennyiségét és a nyomtatási időt. Ha a falakat átlátszó filamenttel nyomtatod, a vegyes színű kitöltés látható lesz. Ez az opció csak akkor működik, ha a törlőtorony engedélyezve van." msgid "Purging after filament change will be done inside objects' support. This may lower the amount of waste and decrease the print time. It will not take effect unless a prime tower is enabled." -msgstr "A filamentcsere utáni kiürítés az objektumok támaszain belül történik. Ez csökkentheti a hulladék mennyiségét és a nyomtatási időt. Ez az opció csak akkor működik, ha a törlőtorony engedélyezve van." +msgstr "A filamentcsere utáni öblítés az objektumok támaszain belül történik. Ez csökkentheti a hulladék mennyiségét és a nyomtatási időt. Ez az opció csak akkor működik, ha a törlőtorony engedélyezve van." msgid "This object will be used to purge the nozzle after a filament change to save filament and decrease the print time. Colors of the objects will be mixed as a result. It will not take effect unless the prime tower is enabled." -msgstr "Ez az objektum lesz használva a fúvóka kiürítésére filamentcsere után, a nyomtatási idő csökkentése és némi filament megtakarításának érdekében. Az objektum színei ennek eredményeképpen keveredni fognak. Ez az opció csak akkor működik, ha a törlőtorony engedélyezve van." +msgstr "Ezt az objektumot használja a fúvóka öblítésére filamentcsere után, így filamentet és nyomtatási időt takarít meg. Emiatt az objektum színei keverednek. Ez a beállítás csak bekapcsolt törlőtoronnyal működik." msgid "Maximal bridging distance" msgstr "Maximális áthidalási távolság" msgid "Maximal distance between supports on sparse infill sections." -msgstr "A támaszok közötti maximális távolság a ritkás kitöltésű részeken." +msgstr "A támaszok közötti maximális távolság a kitöltési területeken." msgid "Wipe tower purge lines spacing" -msgstr "A törlőtorony kiürítési vonalainak távolsága" +msgstr "A törlőtorony öblítési vonalainak távolsága" msgid "Spacing of purge lines on the wipe tower." -msgstr "A törlőtoronyon lévő kiürítési vonalak távolsága." +msgstr "A törlőtorony öblítési vonalainak távolsága." msgid "Extra flow for purging" -msgstr "Többletáramlás a kiürítéshez" +msgstr "Többletáramlás az öblítéshez" msgid "Extra flow used for the purging lines on the wipe tower. This makes the purging lines thicker or narrower than they normally would be. The spacing is adjusted automatically." -msgstr "A törlőtorony kiürítési vonalaihoz használt többletáramlás. Ez a kiürítési vonalakat a szokásosnál vastagabbá vagy vékonyabbá teszi. A távolság automatikusan igazodik." +msgstr "A törlőtorony öblítési vonalaihoz használt többletáramlás. Ettől az öblítési vonalak a szokásosnál vastagabbak vagy vékonyabbak lesznek. A távolság automatikusan igazodik." msgid "Idle temperature" msgstr "Üresjárati hőmérséklet" @@ -17347,7 +17393,7 @@ msgid "Relative extrusion is recommended when using \"label_objects\" option. So msgstr "A relatív extrudálás használata ajánlott a \"label_objects\" opcióval. Bizonyos extruderek jobban működnek, ha ez az opció nincs bejelölve (abszolút extrudálási mód). A törlőtorony csak a relatív móddal kompatibilis. A legtöbb nyomtatón ajánlott. Alapértelmezés szerint be van jelölve." msgid "The classic wall generator produces walls with constant extrusion width and for very thin areas, gap-fill is used. The Arachne engine produces walls with variable extrusion width." -msgstr "A klasszikus falgenerátor állandó szélességű falakat generál, és a nagyon vékony területeknél hézagkitöltést használ. Az Arachne engine változó szélességű falakat generál." +msgstr "A klasszikus falgenerátor állandó szélességű falakat hoz létre, és a nagyon vékony területeknél hézagkitöltést használ. Az Arachne falgenerátor változó szélességű falakat hoz létre." msgid "Arachne" msgstr "Arachne" @@ -17368,7 +17414,7 @@ msgid "Wall transitioning threshold angle" msgstr "Falátmenet szögének küszöbértéke" msgid "When to create transitions between even and odd numbers of walls. A wedge shape with an angle greater than this setting will not have transitions and no walls will be printed in the center to fill the remaining space. Reducing this setting reduces the number and length of these center walls, but may leave gaps or overextrude." -msgstr "Mikor legyen átmenetet a páros és páratlan számú falak között. Az ennél nagyobb szögű ék formánál nem lesz átmenet és nem kerül közé anyag, hogy kitöltse a fennmaradó helyet. Ennek az értéknek a csökkentése csökkenti a középső falak számát és hosszát, de hézagokat hagyhat vagy túlextrudálhat" +msgstr "Meghatározza, hogy mikor jöjjön létre átmenet a páros és páratlan számú falak között. Az ennél nagyobb szögű, ék alakú részeknél nem jön létre átmenet, és a fennmaradó hely kitöltéséhez nem nyomtat falat középre. Az érték csökkentésével csökken e középső falak száma és hossza, de hézagok vagy túlextrudálás alakulhat ki." msgid "Wall distribution count" msgstr "Falak elosztása" @@ -17419,16 +17465,16 @@ msgid "Width of the wall that will replace thin features (according to the Minim msgstr "A fal szélessége, amely lecseréli a modell vékony részeit (a Minimális méretben megadott érték szerint). Ha a minimális falszélesség vékonyabb, mint a nyomtatandó elem vastagsága, akkor a fal olyan vastag lesz, mint maga a nyomtatott elem. A fúvóka átmérőjének százalékában van kifejezve" msgid "Hotend change time" -msgstr "Hotendváltás ideje" +msgstr "Fejegységváltás ideje" msgid "Time to change hotend." -msgstr "A hotendváltás ideje." +msgstr "A fejegységváltás ideje." msgid "Hotend change" -msgstr "Hotendváltás" +msgstr "Fejegységváltás" msgid "When changing the hotend, it is recommended to extrude a certain length of filament from the original nozzle. This helps minimize nozzle oozing." -msgstr "A hotend cseréjekor ajánlott egy bizonyos hosszúságú filamentet extrudálni az eredeti fúvókából. Ez segít minimalizálni a fúvóka szivárgását." +msgstr "A fejegység cseréjekor ajánlott egy bizonyos hosszúságú filamentet extrudálni az eredeti fúvókából. Ez segít csökkenteni a fúvóka szivárgását." msgid "Extruder change" msgstr "Extruderváltás" @@ -17446,13 +17492,13 @@ msgid "To prevent oozing, the nozzle temperature will be cooled during ramming. msgstr "A szivárgás megakadályozása érdekében a fúvóka a betolás során lehűl. Megjegyzés: csak a hűtési parancs és a ventilátor bekapcsolása kerül elküldésre, a célhőmérséklet elérése nem garantált. A 0 letiltást jelent." msgid "The maximum volumetric speed for ramming before a hotend change, where -1 means using the maximum volumetric speed." -msgstr "A hotendváltás előtti betolás maximális áramlási sebessége, ahol -1 a maximális sebesség használatát jelenti." +msgstr "A fejegységváltás előtti betolás maximális anyagáramlása; a -1 a maximális sebesség használatát jelenti." msgid "length when change hotend" -msgstr "hossz hotendcsere esetén" +msgstr "hossz fejegységcsere esetén" msgid "When this retraction value is modified, it will be used as the amount of filament retracted inside the hotend before changing hotends." -msgstr "Ha ezt a visszahúzási értéket módosítod, akkor ezt az értéket használja a nyomtató a filament hotend belsejéből történő visszahúzásakor, mielőtt hotendet cserélne." +msgstr "Ha módosítod, a nyomtató ezt az értéket használja, amikor fejegységcsere előtt visszahúzza a filamentet a fejegység belsejéből." # AI Translated msgid "Support fast purge mode" @@ -17464,14 +17510,14 @@ msgstr "Támogatja-e ez a nyomtató a gyors öblítési módot optimalizált hő # AI Translated msgid "Filament change" -msgstr "Filament csere" +msgstr "Filamentcsere" # AI Translated msgid "The volume of material required to prime the extruder on the tower, excluding a hotend change." msgstr "Az extruder toronyban való előkészítéséhez szükséges anyagmennyiség, a fejegységcserét nem beleértve." msgid "The volume of material required to prime the extruder for a hotend change on the tower." -msgstr "Az extruder átöblítéséhez szükséges anyagmennyiség a hotend cseréjekor." +msgstr "Az extruder átöblítéséhez szükséges anyagmennyiség fejegységcsere esetén." msgid "Preheat temperature delta" msgstr "Előmelegítési hőmérséklet delta" @@ -17616,7 +17662,7 @@ msgid "Lift the object above the bed when it is partially below. Disabled by def msgstr "A tárgy az ágy fölé emelve, ha az részben alatta van. Alapértelmezés szerint le van tiltva." msgid "Arrange the supplied models in a plate and merge them in a single model in order to perform actions once." -msgstr "A megadott modellek elredezése és egyetlen modellé való összevonása a tárgyasztalon, hogy egyszerre lehessen végrehajtani a műveleteket." +msgstr "A megadott modellek elrendezése és egyetlen modellé egyesítése az asztalon, hogy a műveletek egyszerre legyenek végrehajthatók." msgid "Convert Unit" msgstr "Mértékegység átváltása" @@ -17688,7 +17734,7 @@ msgid "Downward machines check" msgstr "Visszafelé kompatibilis gépek ellenőrzése" msgid "If enabled, check whether current machine downward compatible with the machines in the list." -msgstr "Ha engedélyezve van, ellenőrve van, hogy az aktuális gép visszafelé kompatibilis-e a listában szereplő gépekkel." +msgstr "Bekapcsolva ellenőrzi, hogy a jelenlegi gép visszafelé kompatibilis-e a listában szereplő gépekkel." msgid "Downward machines settings" msgstr "Visszafelé kompatibilis gépbeállítások" @@ -17729,10 +17775,10 @@ msgid "Redirects debug logging to file.\n" msgstr "A hibakeresési naplózást fájlba irányítja.\n" msgid "Enable timelapse for print" -msgstr "Időfelvétel engedélyezése a nyomtatáshoz" +msgstr "Timelapse engedélyezése a nyomtatáshoz" msgid "If enabled, this slicing will be considered using timelapse." -msgstr "Ha engedélyezve van, ez a szeletelés időfelvétel használatával számol." +msgstr "Bekapcsolva a szeletelés Timelapse használatával számol." msgid "Load custom G-code" msgstr "Egyéni G-kód betöltése" @@ -18006,13 +18052,13 @@ msgid "Size of the first layer bounding box" msgstr "Az első réteg befoglaló dobozának mérete" msgid "Bottom-left corner of print bed bounding box" -msgstr "A tárgyasztal befoglaló dobozának bal alsó sarka" +msgstr "Az asztal befoglaló téglalapjának bal alsó sarka" msgid "Top-right corner of print bed bounding box" -msgstr "A tárgyasztal befoglaló dobozának jobb felső sarka" +msgstr "Az asztal befoglaló téglalapjának jobb felső sarka" msgid "Size of the print bed bounding box" -msgstr "A tárgyasztal befoglaló dobozának mérete" +msgstr "Az asztal befoglaló téglalapjának mérete" msgid "Timestamp" msgstr "Időbélyeg" @@ -18066,13 +18112,13 @@ msgid "Layer Z" msgstr "Réteg Z" msgid "Height of the current layer above the print bed, measured to the top of the layer." -msgstr "Az aktuális réteg magassága a tárgyasztal felett, a réteg tetejéig mérve." +msgstr "Az aktuális réteg magassága az asztal felett, a réteg tetejéig mérve." msgid "Maximal layer Z" msgstr "Maximális réteg Z" msgid "Height of the last layer above the print bed." -msgstr "Az utolsó réteg magassága a tárgyasztal felett." +msgstr "Az utolsó réteg magassága az asztal felett." msgid "Filament extruder ID" msgstr "Filament extruderazonosító" @@ -18134,8 +18180,8 @@ msgid "" "An object has enabled XY Size compensation which will not be used because it is also fuzzy skin painted.\n" "XY Size compensation cannot be combined with fuzzy skin painting." msgstr "" -"Egy objektumnál engedélyezve van az XY méretkompenzáció, de ez nem lesz használva, mert bolyhos felülettel is festett.\n" -"Az XY méretkompenzáció nem kombinálható a bolyhos felület festésével." +"Egy objektumnál engedélyezve van az XY-méretkompenzáció, de a barázdált felület festése miatt nem használható.\n" +"Az XY-méretkompenzáció nem kombinálható a barázdált felület festésével." msgid "Object name" msgstr "Objektum neve" @@ -18356,7 +18402,7 @@ msgstr "" "\n" "Általában nincs szükség erre a kalibrálásra. Ha egyetlen színű/anyagú nyomtatást indítasz, és a nyomtatásindító menüben be van jelölve az \"áramlásdinamika kalibrálás\" opció, a nyomtató a régi módon fog működni, vagyis a nyomtatás előtt kalibrálja a filamentet; ha többszínű/többanyagú nyomtatást indítasz, a nyomtató minden filamentváltásnál a filament alapértelmezett kompenzációs paraméterét használja, ami a legtöbb esetben jó eredményt ad.\n" "\n" -"Kérlek, vedd figyelembe, hogy vannak olyan esetek, amelyek megbízhatatlanná tehetik a kalibrálási eredményeket, például az elégtelen tapadás a tárgyasztalon. A tapadás javítható a tárgyasztal lemosásával vagy ragasztó felvitelével. Erről további információt a wikiben találsz.\n" +"Vedd figyelembe, hogy bizonyos körülmények megbízhatatlanná tehetik a kalibrálási eredményeket, például az elégtelen tapadás az asztalon. A tapadást az asztal lemosásával vagy ragasztó felvitelével javíthatod. Erről további információt a wikiben találsz.\n" "\n" "Tesztjeinkben a kalibrálási eredmények körülbelül 10 százalékos ingadozást mutattak, ezért előfordulhat, hogy az eredmény nem lesz pontosan ugyanaz minden egyes kalibrálásnál. A kiváltó ok feltárásán még dolgozunk, hogy a jövőbeni frissítésekkel javíthassunk rajta." @@ -18468,7 +18514,7 @@ msgid "Please find the best object on your plate" msgstr "Keresd meg a legjobb tárgyat a tálcán" msgid "Fill in the value above the block with smoothest top surface" -msgstr "Töltsd ki az értéket a legsimább felső felületű blokkból" +msgstr "Írd be a legsimább felső felületű blokk fölötti értéket" msgid "Skip Calibration2" msgstr "Kalibrálás 2 kihagyása" @@ -18496,7 +18542,7 @@ msgid "Title" msgstr "Cím" msgid "A test model will be printed. Please clear the build plate and place it back to the hot bed before calibration." -msgstr "Egy tesztmodell kerül kinyomtatásra. Kérlek, tisztítsd meg a tálcát, és helyezd vissza az asztalra a kalibrálás előtt." +msgstr "A rendszer egy tesztmodellt nyomtat. A kalibrálás előtt tisztítsd meg a tálcát, majd helyezd vissza a fűtött asztalra." msgid "Printing Parameters" msgstr "Nyomtatási paraméterek" @@ -18567,7 +18613,7 @@ msgid "Step value" msgstr "Lépésérték" msgid "The nozzle diameter has been synchronized from the printer Settings" -msgstr "A fúvóka átmérője a nyomtató beállításaiból került szinkronizálásra" +msgstr "A fúvóka átmérőjét a nyomtató beállításai alapján szinkronizáltuk" msgid "From Volumetric Speed" msgstr "Ettől a volumetrikus sebességtől" @@ -18591,11 +18637,11 @@ msgid "Success to get history result" msgstr "Előzmények sikeresen lekérdezve" msgid "Refreshing the previous Flow Dynamics Calibration records" -msgstr "Az előző anyagáramlás-dinamikai kalibrációs rekordok frissítése" +msgstr "A korábbi áramlásdinamika-kalibrálási eredmények frissítése" #, c-format, boost-format msgid "Note: The hotend number on the %s is tied to the holder. When the hotend is moved to a new holder, its number will update automatically." -msgstr "Megjegyzés: A hotend száma a tartóhoz van rendelve ezen: %s. Amikor a hotendet áthelyezed egy új tartóra, a száma automatikusan frissül." +msgstr "Megjegyzés: a fejegység száma ezen a helyen van a tartóhoz rendelve: %s. Amikor a fejegységet áthelyezed egy másik tartóra, a száma automatikusan frissül." msgid "Action" msgstr "Művelet" @@ -18655,6 +18701,20 @@ msgstr "" "A(z) %1% gazdagépnévhez több IP-cím is tartozik.\n" "Válaszd ki, melyik legyen használva." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "Automatikus méretezés a fúvókához" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Ez a modell 0,4 mm-es fúvókához és 0,2 mm-es rétegmagassághoz készült. \n" +"Ha a méretezési opció be van kapcsolva (ajánlott), a modell dinamikusan átméreteződik az aktuális fúvókaátmérőhöz és egy megfelelő rétegmagassághoz, így a teszt pontos és jól leolvasható lesz.\n" +"Csak akkor kapcsold ki a méretezést, ha a referenciamodellt pontosan az eredeti formájában szeretnéd kinyomtatni." + msgid "PA Calibration" msgstr "PA kalibrálás" @@ -18677,7 +18737,7 @@ msgid "Start PA: " msgstr "Kezdő PA: " msgid "End PA: " -msgstr "Befejező PA:" +msgstr "Befejező PA: " msgid "PA step: " msgstr "PA lépcső: " @@ -18705,8 +18765,8 @@ msgid "" msgstr "" "Kérlek, adj meg érvényes értékeket:\n" "Kezdő PA: >= 0.0\n" -"Befejező PA: > Start PA\n" -"PA lépcső: >= 0.001)" +"Befejező PA: > Kezdő PA\n" +"PA lépcső: >= 0.001" msgid "" "Acceleration values must be greater than speed values.\n" @@ -18791,6 +18851,14 @@ msgstr "Kezdősebesség: " msgid "End speed: " msgstr "Befejező sebesség: " +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "Automatikus igazítás a max. volumetrikus sebességhez" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Ha a végsebesség meghaladná a filament maximális volumetrikus sebességét, automatikusan csökkenti a rétegmagasságot (szabványos értékeket megtartva és a gép korlátain belül maradva), hogy elérje azt. Ha még a legkisebb rétegmagasság sem elegendő, akkor inkább a végsebességet csökkenti." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -18802,11 +18870,62 @@ msgstr "" "lépés >= 0\n" "vég > kezdő + lépés" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"A végsebesség (%.0f mm/s) meghaladja a filament maximális volumetrikus sebességét (%.1f mm³/s), ami a külső falat ennél a vonalszélességnél és rétegmagasságnál körülbelül %.0f mm/s értékre korlátozza.\n" +" Az ennél nagyobb sebességek le lesznek vágva, így a torony felső blokkjai nem a kért sebességgel nyomtatódnak.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"A végsebesség (%.0f mm/s) meghaladja a filament maximális volumetrikus sebességét (%.1f mm³/s) az alapértelmezett rétegmagasságnál (%.2f mm).\n" +"\n" +"A rétegmagasság %.2f mm értékre csökkent (ezt az értéket a nyomtató beállításai is használják), hogy a torony elérhesse a kért sebességet." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Még a nyomtató beállításai által használt legkisebb rétegmagasságnál (%.2f mm) is meghaladja a végsebesség (%.0f mm/s) a filament maximális volumetrikus sebességét (%.1f mm³/s).\n" +"\n" +"A rétegmagasság %.2f mm értékre lesz állítva, a végsebesség pedig %.0f mm/s értékre csökken.\n" +"\n" +"Folytatod?" + +# AI Translated +msgid "Continue anyway?" +msgstr "Mindenképp folytatod?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Engedélyezd az \"Automatikus igazítás\" opciót ennek automatikus javításához, vagy mindenképp folytatod?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Engedélyezd az \"Automatikus méretezés a fúvókához\" és az \"Automatikus igazítás\" opciót ennek automatikus javításához, vagy mindenképp folytatod?" + msgid "Start retraction length: " msgstr "Kezdő visszahúzás hossza: " msgid "End retraction length: " -msgstr "Befejező visszahúzási hossz:" +msgstr "Befejező visszahúzási hossz: " msgid "Input shaping Frequency test" msgstr "Rezgéskompenzáció frekvencia teszt" @@ -18821,7 +18940,7 @@ msgid "Fast Tower" msgstr "Gyors torony" msgid "Please ensure the selected type is compatible with your firmware version." -msgstr "Kérjük, győződj meg róla, hogy a kiválasztott típus kompatibilis a firmware verziójával." +msgstr "Kérlek, győződj meg róla, hogy a kiválasztott típus kompatibilis a firmware-verzióval." msgid "" "Marlin version => 2.1.2\n" @@ -18837,7 +18956,7 @@ msgid "" "RepRap firmware version => 3.4.0\n" "Check your firmware documentation for supported shaper types." msgstr "" -"RepRap firmware verzió => 3.4.0\n" +"RepRap firmware-verzió => 3.4.0\n" "Ellenőrizd a firmware dokumentációját a támogatott rezgéskompenzátor-típusokhoz." msgid "Frequency (Start / End): " @@ -19011,7 +19130,7 @@ msgid "Leveling before print" msgstr "Szintezés nyomtatás előtt" msgid "Time-lapse" -msgstr "Időzített felvétel" +msgstr "Timelapse" # AI Translated msgid "Enable IFS" @@ -19092,16 +19211,16 @@ msgid "Error uploading to print host" msgstr "Hiba a nyomtatási gazdagépre történő feltöltéskor" msgid "The selected bed type does not match the file. Please confirm before starting the print." -msgstr "A kiválasztott tárgyasztaltípus nem egyezik a fájlban megadottal. A nyomtatás indítása előtt erősítsd meg." +msgstr "A kiválasztott asztaltípus nem egyezik a fájlban megadottal. A nyomtatás indítása előtt erősítsd meg." msgid "Heated Bed Leveling" -msgstr "Fűtött tárgyasztal szintezése" +msgstr "Fűtött asztal szintezése" msgid "Textured Build Plate (Side A)" -msgstr "Texturált tárgyasztal (A oldal)" +msgstr "Texturált asztal (A oldal)" msgid "Smooth Build Plate (Side B)" -msgstr "Sima tárgyasztal (B oldal)" +msgstr "Sima asztal (B oldal)" # AI Translated #, c-format, boost-format @@ -19201,7 +19320,7 @@ msgid "Create Based on Current Filament" msgstr "Létrehozás a jelenlegi filament alapján" msgid "Copy Current Filament Preset " -msgstr "Jelenlegi filamentbeállítás másolása" +msgstr "Jelenlegi filamentbeállítás másolása " msgid "Basic Information" msgstr "Alapinformációk" @@ -19251,7 +19370,7 @@ msgid "\"Bambu\" or \"Generic\" cannot be used as a Vendor for custom filaments. msgstr "A \"Bambu\" vagy \"Generic\" nem használható gyártóként egyedi filamentek esetében." msgid "Filament type is not selected, please reselect type." -msgstr "A filament típusa nem lett kiválasztva, kérlek, válaszd ki a típust." +msgstr "Nincs kiválasztva filamenttípus. Kérlek, válassz egyet." # AI Translated msgid "Filament serial missing; please input serial." @@ -19342,20 +19461,20 @@ msgid "Printable Space" msgstr "Nyomtatási terület" msgid "Hot Bed STL" -msgstr "Tárgyasztal STL" +msgstr "Asztal STL-fájlja" msgid "Hot Bed SVG" -msgstr "Tárgyasztal SVG" +msgstr "Asztal SVG-fájlja" msgid "Max Print Height" msgstr "Maximális nyomtatási magasság" #, c-format, boost-format msgid "The file exceeds %d MB, please import again." -msgstr "A fájl mérete meghaladja a(z) %d MB-ot, kérlek ismételd meg az importálást." +msgstr "A fájl mérete meghaladja a(z) %d MB-ot. Kérlek, importáld újra." msgid "Exception in obtaining file size, please import again." -msgstr "Kivétel történt a fájlméret megállapításakor, kérlek ismételd meg az importálást." +msgstr "Nem sikerült megállapítani a fájl méretét. Kérlek, importáld újra." msgid "Preset path was not found; please reselect vendor." msgstr "Útvonal nem található. Kérlek, válaszd ki újra a gyártót." @@ -19381,7 +19500,7 @@ msgid "Process Preset Template" msgstr "Folyamatbeállítás sablon" msgid "You have not yet chosen which printer preset to create based on. Please choose the vendor and model of the printer" -msgstr "Még nem választottad ki, hogy melyik nyomtató beállításai alapján készüljön az új. Kérlek, válaszd ki a nyomtató gyártóját és modelljét" +msgstr "Még nem választottad ki, hogy melyik nyomtatóbeállítás alapján készüljön az új. Kérlek, válaszd ki a nyomtató gyártóját és modelljét" msgid "You have entered a disallowed character in the printable area section on the first page. Please use only numbers." msgstr "Tiltott karakter került be az első oldalon a nyomtatási terület részbe. Kérlek, csak számokat használj." @@ -19470,7 +19589,7 @@ msgid "Printer Created" msgstr "Nyomtató létrehozva" msgid "Please go to printer settings to edit your presets" -msgstr "Kérlek, a beállítások szerkesztéséhez lépj be a nyomtató beállításaiba." +msgstr "Kérlek, a beállítások szerkesztéséhez nyisd meg a nyomtatóbeállításokat." msgid "Filament Created" msgstr "Filament létrehozva" @@ -19481,7 +19600,7 @@ msgid "" "Please note that nozzle temperature, hot bed temperature, and maximum volumetric speed each have a significant impact on printing quality. Please set them carefully." msgstr "" "Ha szükséges, lépj be a filamentbeállításokhoz az értékek szerkesztéséhez.\n" -"Figyelem: a fúvóka hőmérséklete, a tárgyasztal hőmérséklete és a maximális volumetrikus sebesség jelentős hatással van a nyomtatási minőségre. Kérlek, körültekintően állítsd be őket." +"Figyelem: a fúvóka és az asztal hőmérséklete, valamint a maximális volumetrikus sebesség jelentős hatással van a nyomtatási minőségre. Kérlek, körültekintően állítsd be őket." msgid "" "\n" @@ -19575,12 +19694,16 @@ msgstr "Csak azok a nyomtatónevek jelennek meg, amelyekhez tartoznak felhaszná msgid "" "Only the filament names with user filament presets will be displayed, \n" "and all user filament presets in each filament name you select will be exported as a zip." -msgstr "Csak azok a nyomtatónevek jelennek meg, amelyekhez tartoznak felhasználói beállítások. A kiválasztott beállítások ZIP fájlként kerülnek exportálásra." +msgstr "" +"Csak azok a filamentnevek jelennek meg, amelyekhez tartoznak felhasználói filamentbeállítások,\n" +"és a kiválasztott filamentnevekhez tartozó összes felhasználói filamentbeállítás ZIP-fájlként lesz exportálva." msgid "" "Only printer names with changed process presets will be displayed, \n" "and all user process presets in each printer name you select will be exported as a zip." -msgstr "Csak azok a nyomtatónevek jelennek meg, amelyeknél változtak a folyamatbeállítások. A kiválasztott beállítások ZIP fájlként kerülnek exportálásra." +msgstr "" +"Csak azok a nyomtatónevek jelennek meg, amelyekhez módosított folyamatbeállítások tartoznak,\n" +"és a kiválasztott nyomtatónevekhez tartozó összes felhasználói folyamatbeállítás ZIP-fájlként lesz exportálva." msgid "Please select at least one printer or filament." msgstr "Kérlek, válassz ki legalább egy nyomtatót vagy filamentet." @@ -19605,8 +19728,8 @@ msgstr "A más beállítások által örökölt beállítások nem törölhetők msgid "The following presets inherits this preset." msgid_plural "The following preset inherits this preset." -msgstr[0] "A következő profilok öröklik ezt a profilt." -msgstr[1] "A következő profil örökli ezt a profilt." +msgstr[0] "A következő profil örökli ezt a profilt." +msgstr[1] "A következő profilok öröklik ezt a profilt." msgid "Delete Preset" msgstr "Beállítás törlése" @@ -19725,7 +19848,7 @@ msgid "Print Host upload" msgstr "Feltöltés a nyomtatóra" msgid "Select the network agent implementation for printer communication. Available agents are registered at startup." -msgstr "Válaszd ki a nyomtatókommunikációhoz használt hálózati ügynök implementációját. Az elérhető ügynökök indításkor kerülnek regisztrálásra." +msgstr "Válaszd ki a nyomtatóval való kommunikációhoz használt hálózati ügynököt. Az elérhető ügynököket indításkor regisztrálja a rendszer." # AI Translated msgid "Select a Flashforge printer" @@ -19758,7 +19881,7 @@ msgid "HTTPS CA file is optional. It is only needed if you use HTTPS with a self msgstr "A HTTPS CA-fájl nem kötelező. Csak akkor szükséges, ha a HTTPS-t saját aláírású tanúsítvánnyal használod." msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" -msgstr "Tanúsítványfájlok (*.crt, *.pem) |*.crt; *.pem|Minden fájl|* . *" +msgstr "Tanúsítványfájlok (*.crt, *.pem)|*.crt;*.pem|Minden fájl|*.*" msgid "Open CA certificate file" msgstr "CA tanúsítványfájl megnyitása" @@ -19794,12 +19917,12 @@ msgstr "K-sorozatú nyomtatók keresése a LAN-on... ez néhány másodpercet ve # AI Translated msgid "No K-series printers found. Make sure the printer is on the same network and not blocked by Wi-Fi client isolation, then click Scan again." -msgstr "Nem található K-sorozatú nyomtató. Győződj meg róla, hogy a nyomtató ugyanazon a hálózaton van, és nem blokkolja a Wi-Fi kliensizoláció, majd kattints újra a Keresés gombra." +msgstr "Nem található K-sorozatú nyomtató. Győződj meg róla, hogy a nyomtató ugyanazon a hálózaton van és nem blokkolja a Wi-Fi kliensizoláció, majd kattints újra a Keresés gombra." # AI Translated #, c-format msgid "Found %zu Creality printer(s). Select one and click Use Selected." -msgstr "%zu Creality nyomtató található. Válassz ki egyet, és kattints a Kijelölt használata gombra." +msgstr "%zu Creality nyomtató található. Válassz ki egyet, majd kattints a Kijelölt használata gombra." # AI Translated msgid "Active" @@ -19903,7 +20026,7 @@ msgstr "Kérlek, győződj meg róla, hogy az OrcaSlicer egyetlen példánya sem # AI Translated msgid "System folder cannot be deleted because some files are in use by another application. Please close any applications using these files and try again." -msgstr "A rendszermappa nem törölhető, mert néhány fájlt egy másik alkalmazás használ. Kérlek, zárd be az ezeket a fájlokat használó alkalmazásokat, és próbáld újra." +msgstr "A rendszermappa nem törölhető, mert néhány fájlt egy másik alkalmazás használ. Zárd be az ezeket a fájlokat használó alkalmazásokat, majd próbáld újra." # AI Translated msgid "Failed to delete system folder..." @@ -20138,7 +20261,7 @@ msgid "It has a small layer height. This results in almost negligible layer line msgstr "Kis rétegmagassággal rendelkezik. Ennek eredményeként a rétegvonalak szinte elhanyagolhatók, a nyomtatási minőség pedig magas. A legtöbb nyomtatási esethez megfelelő." msgid "Compared with the default profile of a 0.2 mm nozzle, it has lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in much higher print quality but a much longer print time." -msgstr "A 0.2 mm-es fúvóka alapértelmezett profiljához képest alacsonyabb sebességekkel és gyorsulással dolgozik, a ritkás kitöltés mintázata pedig Gyroid. Ez jóval magasabb nyomtatási minőséget, de sokkal hosszabb nyomtatási időt eredményez." +msgstr "A 0,2 mm-es fúvóka alapértelmezett profiljához képest alacsonyabb sebességeket és gyorsulást használ, a kitöltési mintázat pedig Gyroid. Ez jóval jobb nyomtatási minőséget, de sokkal hosszabb nyomtatási időt eredményez." msgid "Compared with the default profile of a 0.2 mm nozzle, it has a slightly bigger layer height. This results in almost negligible layer lines and slightly shorter print time." msgstr "A 0.2 mm-es fúvóka alapértelmezett profiljához képest kissé nagyobb rétegmagassággal rendelkezik. Ennek eredményeként a rétegvonalak szinte elhanyagolhatók, a nyomtatási idő pedig kissé rövidebb." @@ -20150,19 +20273,19 @@ msgid "Compared with the default profile of a 0.2 mm nozzle, it has a smaller la msgstr "A 0.2 mm-es fúvóka alapértelmezett profiljához képest kisebb rétegmagassággal rendelkezik. Ennek eredményeként a rétegvonalak szinte láthatatlanok, a nyomtatási minőség magasabb, de a nyomtatási idő hosszabb." msgid "Compared with the default profile of a 0.2 mm nozzle, it has a smaller layer lines, lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in almost invisible layer lines and much higher print quality but much longer print time." -msgstr "A 0.2 mm-es fúvóka alapértelmezett profiljához képest kisebb rétegvonalakkal, alacsonyabb sebességekkel és gyorsulással dolgozik, a ritkás kitöltés mintázata pedig Gyroid. Ez szinte láthatatlan rétegvonalakat és sokkal magasabb nyomtatási minőséget, de jóval hosszabb nyomtatási időt eredményez." +msgstr "A 0,2 mm-es fúvóka alapértelmezett profiljához képest vékonyabb rétegvonalakat, alacsonyabb sebességeket és gyorsulást használ, a kitöltési mintázat pedig Gyroid. Ez szinte láthatatlan rétegvonalakat és sokkal jobb nyomtatási minőséget, de jóval hosszabb nyomtatási időt eredményez." msgid "Compared with the default profile of a 0.2 mm nozzle, it has a smaller layer height. This results in minimal layer lines and higher print quality but longer print time." msgstr "A 0.2 mm-es fúvóka alapértelmezett profiljához képest kisebb rétegmagassággal rendelkezik. Ennek eredményeként minimálisak a rétegvonalak, a nyomtatási minőség magasabb, de a nyomtatási idő hosszabb." msgid "Compared with the default profile of a 0.2 mm nozzle, it has a smaller layer lines, lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in minimal layer lines and much higher print quality but much longer print time." -msgstr "A 0.2 mm-es fúvóka alapértelmezett profiljához képest kisebb rétegvonalakkal, alacsonyabb sebességekkel és gyorsulással dolgozik, a ritkás kitöltés mintázata pedig Gyroid. Ez minimális rétegvonalakat és sokkal magasabb nyomtatási minőséget, de jóval hosszabb nyomtatási időt eredményez." +msgstr "A 0,2 mm-es fúvóka alapértelmezett profiljához képest vékonyabb rétegvonalakat, alacsonyabb sebességeket és gyorsulást használ, a kitöltési mintázat pedig Gyroid. Ez alig látható rétegvonalakat és sokkal jobb nyomtatási minőséget, de jóval hosszabb nyomtatási időt eredményez." msgid "It has a normal layer height. This results in average layer lines and print quality. It is suitable for most printing cases." msgstr "Normál rétegmagassággal rendelkezik. Ennek eredményeként átlagos rétegvonalak és nyomtatási minőség érhető el. A legtöbb nyomtatási esethez megfelelő." msgid "Compared with the default profile of a 0.4 mm nozzle, it has more wall loops and a higher sparse infill density. This results in higher print strength but more filament consumption and longer print time." -msgstr "A 0.4 mm-es fúvóka alapértelmezett profiljához képest több falhurokkal és nagyobb ritkás kitöltési sűrűséggel rendelkezik. Ez nagyobb nyomatszilárdságot, de több filamentfelhasználást és hosszabb nyomtatási időt eredményez." +msgstr "A 0,4 mm-es fúvóka alapértelmezett profiljához képest több falhurkot és nagyobb kitöltési sűrűséget használ. Ez nagyobb nyomatszilárdságot, de több filamentfelhasználást és hosszabb nyomtatási időt eredményez." msgid "Compared with the default profile of a 0.4 mm nozzle, it has a bigger layer height. This results in more apparent layer lines and lower print quality, but slightly shorter print time." msgstr "A 0.4 mm-es fúvóka alapértelmezett profiljához képest nagyobb rétegmagassággal rendelkezik. Ennek eredményeként a rétegvonalak jobban láthatók, a nyomtatási minőség alacsonyabb, de a nyomtatási idő kissé rövidebb." @@ -20174,13 +20297,13 @@ msgid "Compared with the default profile of a 0.4 mm nozzle, it has a smaller la msgstr "A 0.4 mm-es fúvóka alapértelmezett profiljához képest kisebb rétegmagassággal rendelkezik. Ennek eredményeként a rétegvonalak kevésbé láthatók, a nyomtatási minőség magasabb, de a nyomtatási idő hosszabb." msgid "Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height, lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in less apparent layer lines and much higher print quality but much longer print time." -msgstr "A 0.4 mm-es fúvóka alapértelmezett profiljához képest kisebb rétegmagassággal, alacsonyabb sebességekkel és gyorsulással dolgozik, a ritkás kitöltés mintázata pedig Gyroid. Ez kevésbé látható rétegvonalakat és sokkal magasabb nyomtatási minőséget, de jóval hosszabb nyomtatási időt eredményez." +msgstr "A 0,4 mm-es fúvóka alapértelmezett profiljához képest kisebb rétegmagasságot, alacsonyabb sebességeket és gyorsulást használ, a kitöltési mintázat pedig Gyroid. Ez kevésbé látható rétegvonalakat és sokkal jobb nyomtatási minőséget, de jóval hosszabb nyomtatási időt eredményez." msgid "Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height. This results in almost negligible layer lines and higher print quality but longer print time." msgstr "A 0.4 mm-es fúvóka alapértelmezett profiljához képest kisebb rétegmagassággal rendelkezik. Ennek eredményeként a rétegvonalak szinte elhanyagolhatók, a nyomtatási minőség magasabb, de a nyomtatási idő hosszabb." msgid "Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height, lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in almost negligible layer lines and much higher print quality but much longer print time." -msgstr "A 0.4 mm-es fúvóka alapértelmezett profiljához képest kisebb rétegmagassággal, alacsonyabb sebességekkel és gyorsulással dolgozik, a ritkás kitöltés mintázata pedig Gyroid. Ez szinte elhanyagolható rétegvonalakat és sokkal magasabb nyomtatási minőséget, de jóval hosszabb nyomtatási időt eredményez." +msgstr "A 0,4 mm-es fúvóka alapértelmezett profiljához képest kisebb rétegmagasságot, alacsonyabb sebességeket és gyorsulást használ, a kitöltési mintázat pedig Gyroid. Ez alig látható rétegvonalakat és sokkal jobb nyomtatási minőséget, de jóval hosszabb nyomtatási időt eredményez." msgid "Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height. This results in almost negligible layer lines and longer print time." msgstr "A 0.4 mm-es fúvóka alapértelmezett profiljához képest kisebb rétegmagassággal rendelkezik. Ennek eredményeként a rétegvonalak szinte elhanyagolhatók, de a nyomtatási idő hosszabb." @@ -20189,7 +20312,7 @@ msgid "It has a big layer height. This results in apparent layer lines and ordin msgstr "Nagy rétegmagassággal rendelkezik. Ennek eredményeként jól látható rétegvonalak, átlagos nyomtatási minőség és átlagos nyomtatási idő várható." msgid "Compared with the default profile of a 0.6 mm nozzle, it has more wall loops and a higher sparse infill density. This results in higher print strength but more filament consumption and longer print time." -msgstr "A 0.6 mm-es fúvóka alapértelmezett profiljához képest több falhurokkal és nagyobb ritkás kitöltési sűrűséggel rendelkezik. Ez nagyobb nyomatszilárdságot, de több filamentfelhasználást és hosszabb nyomtatási időt eredményez." +msgstr "A 0,6 mm-es fúvóka alapértelmezett profiljához képest több falhurkot és nagyobb kitöltési sűrűséget használ. Ez nagyobb nyomatszilárdságot, de több filamentfelhasználást és hosszabb nyomtatási időt eredményez." msgid "Compared with the default profile of a 0.6 mm nozzle, it has a bigger layer height. This results in more apparent layer lines and lower print quality, but shorter print time in some cases." msgstr "A 0.6 mm-es fúvóka alapértelmezett profiljához képest nagyobb rétegmagassággal rendelkezik. Ennek eredményeként a rétegvonalak jobban láthatók, a nyomtatási minőség alacsonyabb, de bizonyos esetekben a nyomtatási idő rövidebb." @@ -20219,7 +20342,7 @@ msgid "Compared with the default profile of a 0.8 mm nozzle, it has a smaller la msgstr "A 0.8 mm-es fúvóka alapértelmezett profiljához képest kisebb rétegmagassággal rendelkezik. Ennek eredményeként a rétegvonalak kevésbé, de továbbra is jól láthatók, a nyomtatási minőség kissé magasabb, de bizonyos esetekben a nyomtatási idő hosszabb." msgid "This is neither a commonly used filament, nor one of Bambu filaments, and it varies a lot from brand to brand. So, it's highly recommended to ask its vendor for suitable profile before printing and adjust some parameters according to its performances." -msgstr "Ez sem nem egy gyakran használt filament, sem nem tartozik a Bambu filamentek közé, ráadásul márkánként jelentősen eltérhet. Ezért nyomtatás előtt erősen ajánlott a gyártótól megfelelő profilt kérni, és a paramétereket a filament viselkedése alapján finomhangolni." +msgstr "Ez a filament nem gyakran használt, és nem is Bambu-filament, ráadásul márkánként jelentősen eltérhet. Ezért nyomtatás előtt erősen ajánlott a gyártótól megfelelő profilt kérni, majd a paramétereket a filament viselkedése alapján finomhangolni." msgid "When printing this filament, there's a risk of warping and low layer adhesion strength. To get better results, please refer to this wiki: Printing Tips for High Temp / Engineering materials." msgstr "Ennek a filamentnek a nyomtatásakor fennáll a kunkorodás és az alacsony rétegtapadási szilárdság kockázata. A jobb eredmény érdekében nézd meg ezt a wikit: Nyomtatási tippek magas hőmérsékletű / műszaki anyagokhoz." @@ -20448,10 +20571,10 @@ msgid "Generates filament grouping for the left and right nozzles based on the m msgstr "A bal és jobb fúvókához olyan filamentcsoportosítást hoz létre, amely a leginkább filamenttakarékos elveket követi a hulladék minimalizálása érdekében." msgid "Generates filament grouping for the left and right nozzles based on the printer's actual filament status, reducing the need for manual filament adjustment." -msgstr "A bal és jobb fúvókához a nyomtató tényleges filamentállapota alapján hoz létre filamentcsoportosítást, csökkentve a manuális filamentbeállítás szükségességét." +msgstr "A nyomtatóban ténylegesen betöltött filamentek alapján csoportosítja a filamenteket a bal és jobb fúvókához, így kevesebb kézi beállításra van szükség." msgid "Manually assign filament to the left or right nozzle" -msgstr "Filament manuális hozzárendelése a bal vagy jobb fúvókához" +msgstr "Filament kézi hozzárendelése a bal vagy jobb fúvókához" msgid "Global settings" msgstr "Globális beállítások" @@ -20582,7 +20705,7 @@ msgstr "A feltöltés sikertelen" # AI Translated msgid "The file has been transferred, but some unknown errors occurred. Please check the device page for the file and try to start printing again." -msgstr "A fájl átvitele megtörtént, de ismeretlen hibák léptek fel. Kérlek, ellenőrizd a fájlt az eszköz oldalán, és próbáld újra elindítani a nyomtatást." +msgstr "A fájl átvitele befejeződött, de ismeretlen hiba történt. Ellenőrizd a fájlt az Eszköz oldalon, majd próbáld újra elindítani a nyomtatást." # AI Translated msgid "Failed to open file for upload." @@ -20610,23 +20733,23 @@ msgstr "A hibakód nem található" # AI Translated msgid "The printer is busy, please check the device page for the file and try to start printing again." -msgstr "A nyomtató foglalt, kérlek, ellenőrizd a fájlt az eszköz oldalán, és próbáld újra elindítani a nyomtatást." +msgstr "A nyomtató foglalt. Ellenőrizd a fájlt az Eszköz oldalon, majd próbáld újra elindítani a nyomtatást." # AI Translated msgid "The file is lost, please check and try again." -msgstr "A fájl elveszett, kérlek, ellenőrizd, és próbáld újra." +msgstr "A fájl nem található. Ellenőrizd, majd próbáld újra." # AI Translated msgid "The file is corrupted, please check and try again." -msgstr "A fájl sérült, kérlek, ellenőrizd, és próbáld újra." +msgstr "A fájl sérült. Ellenőrizd, majd próbáld újra." # AI Translated msgid "Transmission abnormality, please check and try again." -msgstr "Átviteli rendellenesség, kérlek, ellenőrizd, és próbáld újra." +msgstr "Átviteli hiba történt. Ellenőrizd, majd próbáld újra." # AI Translated msgid "The file does not match the printer, please check and try again." -msgstr "A fájl nem felel meg a nyomtatónak, kérlek, ellenőrizd, és próbáld újra." +msgstr "A fájl nem kompatibilis a nyomtatóval. Ellenőrizd, majd próbáld újra." # AI Translated msgid "Start print timeout" @@ -20650,7 +20773,7 @@ msgstr "A kapcsolat időtúllépés miatt megszakadt. Kérlek, ellenőrizd, hogy # AI Translated msgid "The Hostname/IP/URL could not be parsed, please check it and try again." -msgstr "A gépnév/IP/URL nem értelmezhető, kérlek, ellenőrizd, és próbáld újra." +msgstr "A gépnév/IP-cím/URL nem értelmezhető. Ellenőrizd, majd próbáld újra." # AI Translated msgid "File/data transfer interrupted. Please check the printer and network, then try it again." @@ -20690,27 +20813,27 @@ msgid "Add or Select" msgstr "Hozzáadás vagy kiválasztás" msgid "Warning: The brim type is not set to \"painted\", the brim ears will not take effect!" -msgstr "Figyelmeztetés: A karimatípus nincs \"festett\" értékre állítva, ezért a karimafülek nem fognak érvényesülni!" +msgstr "Figyelmeztetés: a perem típusa nincs \"festett\" értékre állítva, ezért a peremfülek nem fognak érvényesülni!" msgid "Set the brim type of this object to \"painted\"" -msgstr "Ennek az objektumnak a karimatípusát állítsd \"festett\" értékre" +msgstr "Állítsd ennek az objektumnak a peremtípusát \"festett\" értékre" msgid "invalid brim ears" msgstr "érvénytelen peremfülek" msgid "Brim Ears" -msgstr "Karimás Fülek" +msgstr "Peremfülek" msgid "Please select single object." msgstr "Válassz ki egyetlen objektumot." # AI Translated msgid "Entering Brim Ears" -msgstr "Belépés a karimás fülek módba" +msgstr "Belépés a peremfülek módba" # AI Translated msgid "Leaving Brim Ears" -msgstr "Kilépés a karimás fülek módból" +msgstr "Kilépés a peremfülek módból" msgid "Zoom Out" msgstr "Kicsinyítés" @@ -20861,7 +20984,7 @@ msgid "Number of triangular facets" msgstr "Háromszögfelületek száma" msgid "Calculating, please wait..." -msgstr "Számítás folyamatban, kérlek várj..." +msgstr "Számítás folyamatban, kérlek, várj..." # AI Translated msgid "Save these settings as default" @@ -21082,7 +21205,7 @@ msgstr "Filament az AMS kimenetében" # AI Translated msgid " The high drying temperature may cause AMS blockage, please unload first." -msgstr " A magas szárítási hőmérséklet eltömítheti az AMS-t, kérlek, előbb töltsd ki a filamentet." +msgstr " A magas szárítási hőmérséklet eltömítheti az AMS-t, ezért kérlek, előbb vedd ki a filamentet." # AI Translated msgid "Initiating AMS drying" @@ -21110,7 +21233,7 @@ msgstr " Kérlek, csatlakoztasd a tápellátást, majd használd a szárítási # AI Translated msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding." -msgstr " A magas szárítási hőmérséklet eltömítheti az AMS-t. Kérlek, a folytatás előtt töltsd ki kézzel a filamentet." +msgstr " A magas szárítási hőmérséklet eltömítheti az AMS-t. Kérlek, a folytatás előtt kézzel vedd ki a filamentet." # AI Translated msgid "System is busy" @@ -21169,19 +21292,19 @@ msgid "Starting: Checking air vent" msgstr "Indítás: levegőkifúvás ellenőrzése" msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used." -msgstr "Előfordulhat, hogy a filament nem kompatibilis az aktuális gépbeállításokkal. Általános filamentbeállítások lesznek használva." +msgstr "Előfordulhat, hogy a filament nem kompatibilis a jelenlegi gépbeállításokkal. Általános filamentbeállításokat használ." msgid "The filament model is unknown. Still using the previous filament preset." msgstr "A filament modellje ismeretlen. A korábbi filamentbeállítás marad használatban." msgid "The filament model is unknown. Generic filament presets will be used." -msgstr "A filament modellje ismeretlen. Általános filamentbeállítások lesznek használva." +msgstr "A filament modellje ismeretlen. Általános filamentbeállításokat használ." msgid "The filament may not be compatible with the current machine settings. A random filament preset will be used." -msgstr "Előfordulhat, hogy a filament nem kompatibilis az aktuális gépbeállításokkal. Egy véletlenszerű filamentbeállítás lesz használva." +msgstr "Előfordulhat, hogy a filament nem kompatibilis a jelenlegi gépbeállításokkal. Egy véletlenszerű filamentbeállítást használ." msgid "The filament model is unknown. A random filament preset will be used." -msgstr "A filament modellje ismeretlen. Egy véletlenszerű filamentbeállítás lesz használva." +msgstr "A filament modellje ismeretlen. Egy véletlenszerű filamentbeállítást használ." #: resources/data/hints.ini: [hint:Precise wall] msgid "" @@ -21284,8 +21407,8 @@ msgid "" "Timelapse\n" "Did you know that you can generate a timelapse video during each print?" msgstr "" -"Időfelvétel\n" -"Tudtad, hogy minden nyomtatáshoz időfelvétel-videót készíthetsz?" +"Timelapse\n" +"Tudtad, hogy minden nyomtatásról Timelapse-videót készíthetsz?" #: resources/data/hints.ini: [hint:Auto-Arrange] msgid "" @@ -21300,8 +21423,8 @@ msgid "" "Auto-Orient\n" "Did you know that you can rotate objects to an optimal orientation for printing with a simple click?" msgstr "" -"Automatikus orientáció\n" -"Tudtad, hogy az objektumokat egy kattintással elforgathatod a nyomtatáshoz optimális orientációba?" +"Automatikus tájolás\n" +"Tudtad, hogy az objektumokat egyetlen kattintással a nyomtatáshoz optimális helyzetbe forgathatod?" #: resources/data/hints.ini: [hint:Lay on Face] msgid "" @@ -21309,8 +21432,7 @@ msgid "" "Did you know that you can quickly orient a model so that one of its faces sits on the print bed? Select the \"Place on face\" function or press the F key." msgstr "" "Felületre fektetés\n" -"Tudtad, hogy a modellt egyszerűen elforgathatod úgy, hogy az egyik oldala az asztalra kerüljön? Válaszd a \"Felületre fektetés\" opciót, vagy csak nyomd meg az F gombot.\n" -" " +"Tudtad, hogy a modellt egyszerűen elforgathatod úgy, hogy az egyik oldala az asztalra kerüljön? Válaszd a \"Felületre fektetés\" opciót, vagy csak nyomd meg az F gombot." #: resources/data/hints.ini: [hint:Object List] msgid "" @@ -21483,7 +21605,10 @@ msgid "" "Did you know that when printing materials that are prone to warping such as ABS, appropriately increasing the heatbed temperature can reduce the probability of warping?" msgstr "" "Kunkorodás elkerülése\n" -"Tudtad, hogy a kunkorodásra hajlamos anyagok (például ABS) nyomtatásakor a tárgyasztal hőmérsékletének növelése csökkentheti a kunkorodás valószínűségét?" +"Tudtad, hogy a kunkorodásra hajlamos anyagok (például ABS) nyomtatásakor az asztal hőmérsékletének növelése csökkentheti a kunkorodás valószínűségét?" + +#~ msgid "Print order within a single layer." +#~ msgstr "Nyomtatási sorrend egyetlen rétegen belül." #~ msgid "Bottom" #~ msgstr "Alul" @@ -21568,9 +21693,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Continue to sync filaments" #~ msgstr "Filamentek szinkronizálásának folytatása" diff --git a/localization/i18n/it/OrcaSlicer_it.po b/localization/i18n/it/OrcaSlicer_it.po index 44a3221846..3c43178102 100644 --- a/localization/i18n/it/OrcaSlicer_it.po +++ b/localization/i18n/it/OrcaSlicer_it.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -3850,6 +3850,10 @@ msgstr "Disposizione..." msgid "Arranging" msgstr "Disposizione" +# AI Translated +msgid "Arranging " +msgstr "Disposizione " + msgid "Arranging canceled." msgstr "Disposizione annullata." @@ -8240,21 +8244,21 @@ msgstr "La directory per la sostituzione non è stata selezionata" msgid "Replaced with 3D files from directory:\n" msgstr "Sostituito con file 3D dalla directory:\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ Saltato %1%: stesso file.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ Saltato %s: stesso file.\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ Saltato %1%: il file non esiste.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ Saltato %s: il file non esiste.\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ Saltato %1%: sostituzione fallita.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ Saltato %s: sostituzione fallita.\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ Sostituito %1%.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ Sostituito %s.\n" msgid "Replaced volumes" msgstr "Volumi sostituiti" @@ -9229,6 +9233,21 @@ msgstr "Attenua gli strati inferiori" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "Quando si scorre il cursore degli strati nell'anteprima elaborata, gli strati al di sotto di quello corrente vengono visualizzati scuriti, in modo che solo lo strato in visualizzazione sia mostrato alla massima luminosità." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Luminosità degli strati attenuati" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"Quanto luminosi appaiono gli strati attenuati quando \"Attenua gli strati inferiori\" è attivo.\n" +"99% è appena scurito, 0% li rende neri. Limitato al 99% perché 100% equivarrebbe a disattivare l'opzione." + msgid "Login region" msgstr "Regione di accesso" @@ -13326,12 +13345,37 @@ msgstr "Per oggetto" msgid "Intra-layer order" msgstr "Ordine intra-strato" -msgid "Print order within a single layer." -msgstr "Ordine di stampa all'interno di un singolo strato." +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Ordine in cui le istanze degli oggetti vengono percorse all'interno di un singolo strato; determina quanti spostamenti servono per passare dall'una all'altra.\n" +"\n" +"Predefinito: concatenamento con il vicino più prossimo, affinato con 2-opt e rimozione degli incroci. Una buona scelta generale.\n" +"Come elenco di oggetti: le istanze vengono stampate nello stesso ordine dell'elenco degli oggetti, senza alcuna ottimizzazione del percorso. Da usare quando serve un ordine prevedibile e controllato manualmente.\n" +"Il migliore di tutti (percorso più breve): tutte le strategie vengono valutate e viene usata la più breve. L'ordine delle istanze degli oggetti viene deciso una sola volta per l'intera stampa, mentre l'ordine delle singole isole viene deciso strato per strato, quindi strati diversi possono usare strategie diverse. Slicing leggermente più lento.\n" +"Serpentina: percorso a serpentina, riga per riga, affinato con 2-opt. Adatto a griglie regolari di molti pezzi piccoli.\n" +"\n" +"Con più filamenti o strumenti nello stesso strato, ridurre i cambi strumento ha la priorità: gli oggetti vengono prima raggruppati per filamento e questa impostazione ordina solo le istanze all'interno di ciascun gruppo di filamento, quindi la sequenza complessiva potrebbe non sembrare il percorso più breve sul piatto." msgid "As object list" msgstr "Come elenco di oggetti" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "Il migliore di tutti (percorso più breve)" + +# AI Translated +msgid "Snake" +msgstr "Serpentina" + msgid "Slow printing down for better layer cooling" msgstr "Rallenta stampa per miglior raffreddamento degli strati" @@ -18679,6 +18723,20 @@ msgstr "" "Esistono diversi indirizzi IP che risolvono il nome host %1%.\n" "Selezionare quello da utilizzare." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "Scala automaticamente in base all'ugello" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Questo modello è progettato per un ugello da 0,4 mm con un'altezza strato di 0,2 mm. \n" +"Quando l'opzione di ridimensionamento è attiva (consigliata), il modello viene ridimensionato dinamicamente in base al diametro dell'ugello attuale e a un'altezza strato adeguata, rendendo il test preciso e facile da leggere.\n" +"Disattiva il ridimensionamento solo se desideri stampare il modello di riferimento esattamente com'è." + msgid "PA Calibration" msgstr "Calibrazione AP" @@ -18815,6 +18873,14 @@ msgstr "Velocità iniziale: " msgid "End speed: " msgstr "Velocità finale: " +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "Adatta automaticamente alla velocità volumetrica massima" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Se la velocità finale superasse la velocità volumetrica massima del filamento, l'altezza strato viene ridotta automaticamente (mantenendo valori standard e restando entro i limiti della macchina) per raggiungerla. Se anche l'altezza strato minima non è sufficiente, viene ridotta invece la velocità finale." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -18826,6 +18892,57 @@ msgstr "" "incremento >= 0\n" "fine > inizio + incremento" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"La velocità finale (%.0f mm/s) supera la velocità volumetrica massima del filamento (%.1f mm³/s), il che limita la parete esterna a circa %.0f mm/s con questa larghezza linea e questa altezza strato.\n" +" Le velocità superiori verranno limitate, quindi i blocchi superiori della torre non verranno stampati alla velocità richiesta.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"La velocità finale (%.0f mm/s) supera la velocità volumetrica massima del filamento (%.1f mm³/s) con l'altezza strato predefinita (%.2f mm).\n" +"\n" +"L'altezza strato è stata ridotta a %.2f mm (un valore usato dai profili di questa stampante) affinché la torre possa raggiungere la velocità richiesta." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Anche con l'altezza strato più piccola usata dai profili di questa stampante (%.2f mm), la velocità finale (%.0f mm/s) supera la velocità volumetrica massima del filamento (%.1f mm³/s).\n" +"\n" +"L'altezza strato verrà impostata su %.2f mm e la velocità finale ridotta a %.0f mm/s.\n" +"\n" +"Continuare?" + +# AI Translated +msgid "Continue anyway?" +msgstr "Continuare comunque?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Attivare \"Adatta automaticamente\" per correggere automaticamente il problema oppure continuare comunque?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Attivare \"Scala automaticamente in base all'ugello\" e \"Adatta automaticamente\" per correggere automaticamente il problema oppure continuare comunque?" + msgid "Start retraction length: " msgstr "Lunghezza di retrazione iniziale: " @@ -21514,6 +21631,9 @@ msgstr "" "Evita le deformazioni\n" "Sapevi che quando si stampano materiali soggetti a deformazioni come l'ABS, aumentare in modo appropriato la temperatura del piano riscaldato può ridurre la probabilità di deformazione?" +#~ msgid "Print order within a single layer." +#~ msgstr "Ordine di stampa all'interno di un singolo strato." + #~ msgid "Bottom" #~ msgstr "Inferiore" @@ -21600,9 +21720,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Continue to sync filaments" #~ msgstr "Continua la sincronizzazione dei filamenti" diff --git a/localization/i18n/ja/OrcaSlicer_ja.po b/localization/i18n/ja/OrcaSlicer_ja.po index 8ee2ec34c0..0d9f044060 100644 --- a/localization/i18n/ja/OrcaSlicer_ja.po +++ b/localization/i18n/ja/OrcaSlicer_ja.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -3860,6 +3860,10 @@ msgstr "レイアウト中" msgid "Arranging" msgstr "レイアウト中" +# AI Translated +msgid "Arranging " +msgstr "レイアウト中 " + msgid "Arranging canceled." msgstr "レイアウトを取り消しました" @@ -8258,21 +8262,21 @@ msgstr "置換用のディレクトリが選択されていません" msgid "Replaced with 3D files from directory:\n" msgstr "ディレクトリの3Dファイルで置換しました:\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ スキップ %1%: 同一ファイル。\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ スキップ %s: 同一ファイル。\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ スキップ %1%: ファイルが存在しません。\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ スキップ %s: ファイルが存在しません。\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ スキップ %1%: 置換に失敗しました。\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ スキップ %s: 置換に失敗しました。\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ 置換しました %1%。\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ 置換しました %s。\n" msgid "Replaced volumes" msgstr "置換されたボリューム" @@ -9249,6 +9253,21 @@ msgstr "下の積層を暗くする" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "スライスプレビューで積層スライダーを操作する際、現在の層より下の積層を暗く描画し、表示中の積層のみを明るく表示します。" +# AI Translated +msgid "Dimmed layer brightness" +msgstr "暗くした積層の明るさ" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"「下の積層を暗くする」を有効にしたときに、暗くした積層をどの程度の明るさで表示するかを指定します。\n" +"99%ではほとんど暗くならず、0%では真っ黒になります。100%はオプションを無効にした場合と同じになるため、上限は99%です。" + msgid "Login region" msgstr "地域" @@ -13416,12 +13435,37 @@ msgstr "オブジェクト順" msgid "Intra-layer order" msgstr "レイヤー内の順序" -msgid "Print order within a single layer." -msgstr "単一レイヤー内の印刷順序。" +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"1つの積層内でオブジェクトインスタンスを巡回する順序です。インスタンス間の移動距離に影響します。\n" +"\n" +"デフォルト:最近傍法でつなぎ、2-optと交差の除去で改善します。一般的な用途に適した選択です。\n" +"オブジェクトリスト順:パスの最適化を行わず、オブジェクトリストと同じ順序でインスタンスを造形します。手動で管理できる予測しやすい順序が必要な場合に使用します。\n" +"すべてを比較(最短経路):すべての方式を評価し、最も短いものを使用します。オブジェクトインスタンスの順序は造形全体で1回だけ決定され、個々のアイランドの順序は積層ごとに決定されるため、積層によって異なる方式が使われる場合があります。スライスがやや遅くなります。\n" +"蛇行:行ごとに折り返しながら蛇行して巡回し、2-optで改善します。小さなパーツが規則的に並んだ配置に適しています。\n" +"\n" +"同じ積層内で複数のフィラメントやツールを使用する場合は、ツール交換の削減が優先されます。オブジェクトはまずフィラメントごとにグループ化され、この設定は各フィラメントグループ内のインスタンスの順序のみを決めるため、全体の順序はプレート全体での最短経路には見えないことがあります。" msgid "As object list" msgstr "オブジェクトリスト順" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "すべてを比較(最短経路)" + +# AI Translated +msgid "Snake" +msgstr "蛇行" + msgid "Slow printing down for better layer cooling" msgstr "冷却の為減速" @@ -19167,6 +19211,20 @@ msgstr "" "ホスト名%1%には、いくつかのIPアドレスがあります。\n" "使用するIPアドレスを1つ選んでください。" +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "ノズルに合わせて自動スケール" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"このモデルは、0.4 mmノズルと0.2 mmの積層ピッチを基準に設計されています。 \n" +"スケールオプションを有効にすると(推奨)、現在のノズル径と適切な積層ピッチに合わせてサイズが動的に調整され、テストの精度と読み取りやすさが向上します。\n" +"参照モデルをそのままの状態で造形したい場合のみ、スケールを無効にしてください。" + msgid "PA Calibration" msgstr "PAキャリブレーション" @@ -19306,6 +19364,14 @@ msgstr "開始速度: " msgid "End speed: " msgstr "終了速度: " +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "最大体積速度に合わせて自動調整" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "終了速度がフィラメントの最大体積速度を超える場合、その速度に到達できるよう積層ピッチを自動的に下げます(標準的な値を使用し、プリンタの制限内に収めます)。最小の積層ピッチでも足りない場合は、代わりに終了速度を下げます。" + # AI Translated msgid "" "Please input valid values:\n" @@ -19318,6 +19384,57 @@ msgstr "" "ステップ >= 0\n" "終了 > 開始 + ステップ" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"終了速度(%.0f mm/s)がフィラメントの最大体積速度(%.1f mm³/s)を超えています。この押出線幅と積層ピッチでは、外壁は約 %.0f mm/s に制限されます。\n" +" これを超える速度は制限されるため、タワーの上部ブロックは指定した速度で造形されません。\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"終了速度(%.0f mm/s)がフィラメントの最大体積速度(%.1f mm³/s)を超えています(デフォルトの積層ピッチ %.2f mm の場合)。\n" +"\n" +"タワーが指定した速度に到達できるよう、積層ピッチを %.2f mm(このプリンタのプロファイルで使用されている値)に下げました。" + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"このプリンタのプロファイルで使用されている最小の積層ピッチ(%.2f mm)でも、終了速度(%.0f mm/s)がフィラメントの最大体積速度(%.1f mm³/s)を超えています。\n" +"\n" +"積層ピッチを %.2f mm に設定し、終了速度を %.0f mm/s に下げます。\n" +"\n" +"続行しますか?" + +# AI Translated +msgid "Continue anyway?" +msgstr "このまま続行しますか?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "「自動調整」を有効にすると自動的に修正されます。このまま続行しますか?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "「ノズルに合わせて自動スケール」と「自動調整」を有効にすると自動的に修正されます。このまま続行しますか?" + msgid "Start retraction length: " msgstr "開始リトラクション長さ: " @@ -22077,6 +22194,9 @@ msgstr "" "反りを避ける\n" "ABSのような反りやすい素材を印刷する場合、ヒートベッドの温度を適切に上げることで、反りが発生する確率を下げることができることをご存知ですか?" +#~ msgid "Print order within a single layer." +#~ msgstr "単一レイヤー内の印刷順序。" + #~ msgid "Bottom" #~ msgstr "底面" @@ -22157,9 +22277,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Continue to sync filaments" #~ msgstr "フィラメントの同期を続行" diff --git a/localization/i18n/ko/OrcaSlicer_ko.po b/localization/i18n/ko/OrcaSlicer_ko.po index de6c3df39c..5a6ac0438b 100644 --- a/localization/i18n/ko/OrcaSlicer_ko.po +++ b/localization/i18n/ko/OrcaSlicer_ko.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: 2025-06-02 17:12+0900\n" "Last-Translator: crwusiz \n" "Language-Team: \n" @@ -3864,6 +3864,10 @@ msgstr "정렬 중..." msgid "Arranging" msgstr "정렬 중" +# AI Translated +msgid "Arranging " +msgstr "정렬 중 " + msgid "Arranging canceled." msgstr "정렬 취소됨." @@ -8284,24 +8288,24 @@ msgid "Replaced with 3D files from directory:\n" msgstr "다음 디렉터리의 3D 파일로 교체했습니다:\n" # AI Translated -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ 건너뜀 %1%: 동일한 파일입니다.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ 건너뜀 %s: 동일한 파일입니다.\n" # AI Translated -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ 건너뜀 %1%: 파일이 존재하지 않습니다.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ 건너뜀 %s: 파일이 존재하지 않습니다.\n" # AI Translated -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ 건너뜀 %1%: 교체하지 못했습니다.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ 건너뜀 %s: 교체하지 못했습니다.\n" # AI Translated -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ %1%을(를) 교체했습니다.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ %s을(를) 교체했습니다.\n" # AI Translated msgid "Replaced volumes" @@ -9324,6 +9328,21 @@ msgstr "아래 레이어 어둡게 표시" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "슬라이스된 미리보기에서 레이어 슬라이더를 움직일 때 현재 레이어보다 아래에 있는 레이어를 어둡게 렌더링하여, 보고 있는 레이어만 완전한 밝기로 표시합니다." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "어둡게 표시된 레이어의 밝기" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"\"아래 레이어 어둡게 표시\"를 활성화했을 때 어둡게 표시되는 레이어의 밝기입니다.\n" +"99%는 거의 어두워지지 않고, 0%는 완전히 검게 표시됩니다. 100%는 이 옵션을 비활성화한 것과 같으므로 최대 99%로 제한됩니다." + msgid "Login region" msgstr "로그인 지역" @@ -13539,12 +13558,37 @@ msgstr "객체별" msgid "Intra-layer order" msgstr "레이어 내 순서" -msgid "Print order within a single layer." -msgstr "단일 레이어 내의 출력 순서" +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"단일 레이어 내에서 객체 인스턴스를 방문하는 순서로, 인스턴스 사이를 오가는 이동량을 결정합니다.\n" +"\n" +"기본값: 최근접 이웃 방식으로 경로를 연결하고 2-opt와 교차 제거로 개선합니다. 일반적으로 무난한 선택입니다.\n" +"객체 목록으로: 경로 최적화 없이 객체 목록과 동일한 순서로 인스턴스를 출력합니다. 예측 가능하고 수동으로 제어되는 순서가 필요할 때 사용하십시오.\n" +"전체 비교(최단 경로): 모든 전략을 평가하여 가장 짧은 것을 사용합니다. 객체 인스턴스 순서는 출력 전체에 대해 한 번만 결정되고 개별 아일랜드의 순서는 레이어마다 결정되므로, 레이어에 따라 서로 다른 전략이 사용될 수 있습니다. 슬라이싱이 약간 느려집니다.\n" +"사행형: 행 단위로 앞뒤를 오가며 사행하듯 순회하고 2-opt로 개선합니다. 작은 부품이 규칙적인 격자로 배치된 경우에 적합합니다.\n" +"\n" +"같은 레이어에서 여러 필라멘트나 툴을 사용하는 경우에는 툴 교체 최소화가 우선합니다. 객체를 먼저 필라멘트별로 그룹화하며 이 설정은 각 필라멘트 그룹 내의 인스턴스 순서만 결정하므로, 전체 순서가 플레이트 전체의 최단 경로처럼 보이지 않을 수 있습니다." msgid "As object list" msgstr "객체 목록으로" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "전체 비교(최단 경로)" + +# AI Translated +msgid "Snake" +msgstr "사행형" + msgid "Slow printing down for better layer cooling" msgstr "레이어 냉각 향상을 위한 감속" @@ -14248,7 +14292,7 @@ msgstr "플러시 체적 속도" # AI Translated msgid "Volumetric speed when flushing filament. 0 indicates the max volumetric speed." -msgstr "필라멘트를 플러시할 때의 체적 속도입니다. 0은 최대 체적 속도를 의미합니다." +msgstr "필라멘트를 플러시할 때의 압출 속도입니다. 0은 최대 압출 속도를 의미합니다." msgid "This setting is the volume of filament that can be melted and extruded per second. Printing speed is limited by max volumetric speed, in case of too high and unreasonable speed setting. This value cannot be zero." msgstr "이 설정은 초당 얼마나 많은 양의 필라멘트를 녹이고 압출할 수 있는지를 나타냅니다. 너무 높고 부적절한 속도 설정의 경우 출력 속도는 최대 압출 속도에 의해 제한됩니다. 0이 될 수 없습니다" @@ -18715,7 +18759,7 @@ msgstr "" "이제 다양한 필라멘트에 대한 자동 교정 기능이 추가되었습니다. 완전히 자동으로 수행되며 결과는 나중에 사용할 수 있도록 프린터에 저장됩니다. 다음과 같은 제한된 경우에만 교정을 수행하면 됩니다:\n" "1. 다른 브랜드/모델의 새 필라멘트를 사용하거나 필라멘트가 눅눅해진 경우\n" "2. 노즐이 마모되었거나 새 노즐로 교체한 경우\n" -"3. 필라멘트 설정에서 최대 체적 속도나 출력 온도를 변경한 경우." +"3. 필라멘트 설정에서 최대 압출 속도나 출력 온도를 변경한 경우." msgid "About this calibration" msgstr "교정 정보" @@ -19033,6 +19077,20 @@ msgstr "" "호스트 이름 %1%으로 확인되는 IP 주소가 여러 개 있습니다.\n" "사용 할 IP를 선택해 주세요." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "노즐에 맞춰 자동 크기 조정" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"이 모델은 0.4 mm 노즐과 0.2 mm 레이어 높이를 기준으로 설계되었습니다. \n" +"크기 조정 옵션을 활성화하면(권장) 현재 노즐 직경과 적절한 레이어 높이에 맞춰 크기가 동적으로 조정되어 테스트가 정확하고 읽기 쉬워집니다.\n" +"참조 모델을 있는 그대로 출력하려는 경우에만 크기 조정을 끄십시오." + msgid "PA Calibration" msgstr "PA 교정" @@ -19171,6 +19229,14 @@ msgstr "시작 속도: " msgid "End speed: " msgstr "종료 속도: " +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "최대 압출 속도에 맞춰 자동 조정" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "종료 속도가 필라멘트의 최대 압출 속도를 초과하는 경우, 해당 속도에 도달할 수 있도록 레이어 높이를 자동으로 낮춥니다(표준 값을 유지하고 장비의 한계 내에서 조정). 최소 레이어 높이로도 부족하면 대신 종료 속도를 낮춥니다." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -19182,6 +19248,57 @@ msgstr "" "단계 >= 0\n" "끝 > 시작 + 단계)" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"종료 속도(%.0f mm/s)가 필라멘트의 최대 압출 속도(%.1f mm³/s)를 초과합니다. 현재 선 너비와 레이어 높이에서는 외벽이 약 %.0f mm/s로 제한됩니다.\n" +" 이보다 빠른 속도는 제한되므로 타워의 상단 블록은 요청한 속도로 출력되지 않습니다.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"종료 속도(%.0f mm/s)가 필라멘트의 최대 압출 속도(%.1f mm³/s)를 초과합니다(기본 레이어 높이 %.2f mm 기준).\n" +"\n" +"타워가 요청한 속도에 도달할 수 있도록 레이어 높이를 %.2f mm(이 프린터의 프로파일에서 사용하는 값)로 낮췄습니다." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"이 프린터의 프로파일에서 사용하는 가장 작은 레이어 높이(%.2f mm)에서도 종료 속도(%.0f mm/s)가 필라멘트의 최대 압출 속도(%.1f mm³/s)를 초과합니다.\n" +"\n" +"레이어 높이를 %.2f mm로 설정하고 종료 속도를 %.0f mm/s로 낮춥니다.\n" +"\n" +"계속하시겠습니까?" + +# AI Translated +msgid "Continue anyway?" +msgstr "그래도 계속하시겠습니까?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "\"자동 조정\"을 활성화하면 자동으로 해결됩니다. 그래도 계속하시겠습니까?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "\"노즐에 맞춰 자동 크기 조정\"과 \"자동 조정\"을 활성화하면 자동으로 해결됩니다. 그래도 계속하시겠습니까?" + msgid "Start retraction length: " msgstr "후퇴 시작 길이: " @@ -21289,7 +21406,7 @@ msgstr "채워넣기 전혀 없음" # AI Translated msgid "Volumetric speed" -msgstr "체적 속도" +msgstr "압출 속도" msgid "Step file import parameters" msgstr "스텝 파일 가져오기 매개변수" @@ -21940,6 +22057,9 @@ msgstr "" "뒤틀림 방지\n" "ABS와 같이 뒤틀림이 발생하기 쉬운 소재를 출력할 때, 히트베드 온도를 적절하게 높이면 뒤틀림 가능성을 줄일 수 있다는 사실을 알고 계셨나요?" +#~ msgid "Print order within a single layer." +#~ msgstr "단일 레이어 내의 출력 순서" + #~ msgid "Bottom" #~ msgstr "아래" @@ -22008,9 +22128,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Continue to sync filaments" #~ msgstr "필라멘트 동기화 계속하기" diff --git a/localization/i18n/lt/OrcaSlicer_lt.po b/localization/i18n/lt/OrcaSlicer_lt.po index 986a9dc0d7..9a6b7ae590 100644 --- a/localization/i18n/lt/OrcaSlicer_lt.po +++ b/localization/i18n/lt/OrcaSlicer_lt.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: 2026-07-02 14:13+0300\n" "Last-Translator: Gintaras Kučinskas \n" "Language-Team: \n" @@ -3840,6 +3840,10 @@ msgstr "Išdėstoma..." msgid "Arranging" msgstr "Išdėstymas" +# AI Translated +msgid "Arranging " +msgstr "Išdėstoma " + msgid "Arranging canceled." msgstr "Išdėstymas atšauktas." @@ -8235,21 +8239,21 @@ msgstr "" "Pakeista 3D failais iš katalogo:\n" "\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ Praleistas %1%: tas pats failas.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ Praleistas %s: tas pats failas.\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ Praleistas %1%: failas neegzistuoja.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ Praleistas %s: failas neegzistuoja.\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ Praleistas %1%: nepavyko pakeisti.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ Praleistas %s: nepavyko pakeisti.\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ Pakeistas %1%.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ Pakeistas %s.\n" msgid "Replaced volumes" msgstr "Pakeisti tūriai" @@ -9186,6 +9190,21 @@ msgstr "Pritemdyti apatinius sluoksnius" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "Slenkant sluoksnių slankiklį pjaustytoje peržiūroje, atvaizduoti žemiau esančius sluoksnius pritemdytus, kad visu ryškumu būtų rodomas tik peržiūrimas sluoksnis." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Pritemdytų sluoksnių ryškumas" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"Kaip ryškiai atvaizduojami pritemdyti sluoksniai, kai įjungta parinktis „Pritemdyti apatinius sluoksnius“.\n" +"99 % – pritemdymas vos pastebimas, 0 % – sluoksniai atvaizduojami juodai. Riba yra 99 %, nes 100 % prilygtų parinkties išjungimui." + msgid "Login region" msgstr "Prisijungimo regionas" @@ -13222,12 +13241,37 @@ msgstr "Objektas po objekto" msgid "Intra-layer order" msgstr "Eiliškumas sluoksnio viduje" -msgid "Print order within a single layer." -msgstr "Elementų spausdinimo eiliškumas vieno sluoksnio ribose." +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Tvarka, kuria objektų kopijos aplankomos viename sluoksnyje; ji lemia, kiek tuščiosios eigos sugaištama pereinant tarp jų.\n" +"\n" +"Numatytasis: grandinės sudarymas artimiausio kaimyno metodu, patobulintas 2-opt algoritmu ir sankirtų šalinimu. Geras bendras pasirinkimas.\n" +"Kaip objektų sąrašas: kopijos spausdinamos tokia pačia tvarka kaip objektų sąraše, be jokio kelio optimizavimo. Naudokite, kai reikia nuspėjamos, rankiniu būdu valdomos tvarkos.\n" +"Geriausias iš visų (trumpiausias kelias): įvertinamos visos strategijos ir naudojama trumpiausia. Objektų kopijų tvarka nustatoma vieną kartą visam spausdinimui, o atskirų salelių tvarka – kiekvienam sluoksniui atskirai, todėl skirtinguose sluoksniuose gali būti naudojamos skirtingos strategijos. Sluoksniuojama šiek tiek lėčiau.\n" +"Gyvatėle: vingiuotas ėjimas eilutė po eilutės, patobulintas 2-opt algoritmu. Gerai tinka taisyklingiems daugelio mažų detalių tinkleliams.\n" +"\n" +"Kai tame pačiame sluoksnyje naudojamos kelios gijos ar keli įrankiai, pirmenybė teikiama įrankio keitimų mažinimui: objektai pirmiausia grupuojami pagal giją, o ši nuostata rikiuoja tik kopijas kiekvienoje grupėje, todėl bendra seka gali neatrodyti kaip trumpiausias kelias per plokštę." msgid "As object list" msgstr "Kaip objektų sąrašas" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "Geriausias iš visų (trumpiausias kelias)" + +# AI Translated +msgid "Snake" +msgstr "Gyvatėle" + msgid "Slow printing down for better layer cooling" msgstr "Sulėtinti spausdinimą geresniam sluoksnių aušinimui" @@ -18537,6 +18581,20 @@ msgstr "" "Yra keli IP adresai, susieti su mazgo pavadinimu %1%.\n" "Pasirinkite tą, kurį norite naudoti." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "Automatinis mastelis pagal purkštuką" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Šis modelis suprojektuotas 0,4 mm purkštukui ir 0,2 mm sluoksnio aukščiui. \n" +"Kai mastelio keitimo parinktis įjungta (rekomenduojama), modelio dydis dinamiškai pritaikomas prie jūsų dabartinio purkštuko skersmens ir tinkamo sluoksnio aukščio, todėl testas yra ir tikslus, ir lengvai įskaitomas.\n" +"Mastelio keitimą išjunkite tik tuo atveju, jei norite spausdinti etaloninį modelį tiksliai tokį, koks jis yra." + msgid "PA Calibration" msgstr "PA kalibravimas (Pressure Advance)" @@ -18673,6 +18731,14 @@ msgstr "Pradinis greitis: " msgid "End speed: " msgstr "Galinis greitis: " +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "Automatiškai pritaikyti prie maksimalaus tūrinio greičio" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Jei galutinis greitis viršytų maksimalų gijos tūrinį greitį, automatiškai sumažinti sluoksnio aukštį (išlaikant standartines reikšmes ir neperžengiant įrenginio apribojimų), kad jį pasiektų. Jei net mažiausio sluoksnio aukščio nepakanka, vietoj to sumažinamas galutinis greitis." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -18684,6 +18750,57 @@ msgstr "" "žingsnis >= 0\n" "galinis > pradinis + žingsnis" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"Galutinis greitis (%.0f mm/s) viršija maksimalų gijos tūrinį greitį (%.1f mm³/s), kuris esant tokiam linijos pločiui ir sluoksnio aukščiui riboja išorinę sienelę iki maždaug %.0f mm/s.\n" +" Didesni greičiai bus apriboti, todėl viršutiniai bokšto blokai nebus spausdinami pageidaujamu greičiu.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"Galutinis greitis (%.0f mm/s) viršija maksimalų gijos tūrinį greitį (%.1f mm³/s) esant numatytajam sluoksnio aukščiui (%.2f mm).\n" +"\n" +"Sluoksnio aukštis sumažintas iki %.2f mm (reikšmė, naudojama šio spausdintuvo profiliuose), kad bokštas galėtų pasiekti pageidaujamą greitį." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Net ir esant mažiausiam sluoksnio aukščiui, naudojamam šio spausdintuvo profiliuose (%.2f mm), galutinis greitis (%.0f mm/s) viršija maksimalų gijos tūrinį greitį (%.1f mm³/s).\n" +"\n" +"Sluoksnio aukštis bus nustatytas į %.2f mm, o galutinis greitis sumažintas iki %.0f mm/s.\n" +"\n" +"Tęsti?" + +# AI Translated +msgid "Continue anyway?" +msgstr "Vis tiek tęsti?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Įjungti „Automatiškai pritaikyti“, kad tai būtų ištaisyta automatiškai, ar vis tiek tęsti?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Įjungti „Automatinis mastelis pagal purkštuką“ ir „Automatiškai pritaikyti“, kad tai būtų ištaisyta automatiškai, ar vis tiek tęsti?" + msgid "Start retraction length: " msgstr "Pradinis įtraukimo ilgis: " @@ -21219,6 +21336,9 @@ msgstr "" "Venkite deformacijų (warping)\n" "Ar žinojote, kad spausdinant medžiagas, kurios yra linkusios trauktis ir riestis (pvz., ABS), tinkamas kaitinamojo pagrindo temperatūros padidinimas gali sumažinti deformacijų (warping) tikimybę?" +#~ msgid "Print order within a single layer." +#~ msgstr "Elementų spausdinimo eiliškumas vieno sluoksnio ribose." + #~ msgid "Bottom" #~ msgstr "Apačia" @@ -21306,9 +21426,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Renders cast shadows on the plate in realistic view." #~ msgstr "Realistiniame vaizde atvaizduoja krentančius šešėlius ant spausdinimo pagrindo." diff --git a/localization/i18n/nl/OrcaSlicer_nl.po b/localization/i18n/nl/OrcaSlicer_nl.po index 7ee63c8a30..1ae53b2888 100644 --- a/localization/i18n/nl/OrcaSlicer_nl.po +++ b/localization/i18n/nl/OrcaSlicer_nl.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -4172,6 +4172,10 @@ msgstr "Rangschikken..." msgid "Arranging" msgstr "Rangschikken" +# AI Translated +msgid "Arranging " +msgstr "Rangschikken " + msgid "Arranging canceled." msgstr "Rangschikken geannuleerd." @@ -8995,24 +8999,24 @@ msgid "Replaced with 3D files from directory:\n" msgstr "Vervangen door 3D-bestanden uit de map:\n" # AI Translated -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ Overgeslagen %1%: hetzelfde bestand.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ Overgeslagen %s: hetzelfde bestand.\n" # AI Translated -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ Overgeslagen %1%: bestand bestaat niet.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ Overgeslagen %s: bestand bestaat niet.\n" # AI Translated -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ Overgeslagen %1%: vervangen is mislukt.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ Overgeslagen %s: vervangen is mislukt.\n" # AI Translated -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ Vervangen %1%.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ Vervangen %s.\n" # AI Translated msgid "Replaced volumes" @@ -10076,6 +10080,21 @@ msgstr "Onderliggende lagen dimmen" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "Bij het verschuiven van de laagschuifregelaar in de slicevoorvertoning worden de lagen onder de huidige laag verduisterd weergegeven, zodat alleen de bekeken laag op volle helderheid wordt getoond." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Helderheid van gedimde lagen" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"Hoe helder de gedimde lagen worden weergegeven wanneer \"Onderliggende lagen dimmen\" is ingeschakeld.\n" +"99% is nauwelijks donkerder, 0% maakt ze zwart. Beperkt tot 99%, omdat 100% hetzelfde zou zijn als de optie uitschakelen." + msgid "Login region" msgstr "Inlogregio" @@ -14544,13 +14563,37 @@ msgid "Intra-layer order" msgstr "Volgorde binnen een laag" # AI Translated -msgid "Print order within a single layer." -msgstr "Printvolgorde binnen één laag." +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"De volgorde waarin objectinstanties binnen één laag worden bezocht, wat bepaalt hoeveel verplaatsing er nodig is om ertussen te bewegen.\n" +"\n" +"Standaard: aaneenschakeling via de dichtstbijzijnde buur, verfijnd met 2-opt en het verwijderen van kruisingen. Een goede algemene keuze.\n" +"Zoals de objectlijst: instanties worden afgedrukt in dezelfde volgorde als de objectlijst, zonder enige padoptimalisatie. Gebruik dit wanneer je een voorspelbare, handmatig bepaalde volgorde nodig hebt.\n" +"Beste van allemaal (kortste pad): elke strategie wordt beoordeeld en de kortste wordt gebruikt. De volgorde van de objectinstanties wordt eenmalig voor de hele print bepaald, terwijl de volgorde van de afzonderlijke eilanden per laag wordt bepaald, waardoor verschillende lagen uiteindelijk verschillende strategieën kunnen gebruiken. Het slicen duurt iets langer.\n" +"Slingerend: slingerend traject, rij voor rij, verfijnd met 2-opt. Zeer geschikt voor regelmatige rasters van veel kleine onderdelen.\n" +"\n" +"Bij meerdere filamenten of gereedschappen in dezelfde laag heeft het beperken van het aantal gereedschapswissels voorrang: objecten worden eerst per filament gegroepeerd en deze instelling bepaalt alleen de volgorde van de instanties binnen elke filamentgroep, waardoor de totale volgorde er niet uitziet als het kortste pad over het printbed." # AI Translated msgid "As object list" msgstr "Zoals de objectlijst" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "Beste van allemaal (kortste pad)" + +# AI Translated +msgid "Snake" +msgstr "Slingerend" + msgid "Slow printing down for better layer cooling" msgstr "Printsnelheid omlaag brengen zodat de laag beter kan koelen" @@ -20593,6 +20636,20 @@ msgstr "" "Er zijn meerdere IP-adressen die verwijzen naar hostname %1%.\n" "Selecteer er een die gebruikt moet worden." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "Automatisch schalen naar mondstuk" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Dit model is ontworpen voor een mondstuk van 0,4 mm met een laaghoogte van 0,2 mm. \n" +"Wanneer de schaaloptie is ingeschakeld (aanbevolen), wordt het model dynamisch aangepast aan je huidige mondstukdiameter en een passende laaghoogte, waardoor de test zowel nauwkeurig als goed afleesbaar is.\n" +"Schakel het schalen alleen uit als je het referentiemodel precies zo wilt printen als het is." + msgid "PA Calibration" msgstr "PA-kalibratie" @@ -20736,6 +20793,14 @@ msgstr "Startsnelheid:" msgid "End speed: " msgstr "Eindsnelheid:" +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "Automatisch aanpassen aan max. volumetrische snelheid" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Als de eindsnelheid de maximale volumetrische snelheid van het filament zou overschrijden, wordt de laaghoogte automatisch verlaagd (met behoud van standaardwaarden en binnen de limieten van de machine) om die snelheid te halen. Als zelfs de minimale laaghoogte niet volstaat, wordt in plaats daarvan de eindsnelheid verlaagd." + # AI Translated msgid "" "Please input valid values:\n" @@ -20748,6 +20813,57 @@ msgstr "" "stap >= 0\n" "einde > start + stap" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"De eindsnelheid (%.0f mm/s) overschrijdt de maximale volumetrische snelheid van het filament (%.1f mm³/s), waardoor de buitenste wand bij deze lijndikte en laaghoogte beperkt wordt tot ongeveer %.0f mm/s.\n" +" Hogere snelheden worden begrensd, waardoor de bovenste blokken van de toren niet op de gevraagde snelheid worden geprint.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"De eindsnelheid (%.0f mm/s) overschrijdt de maximale volumetrische snelheid van het filament (%.1f mm³/s) bij de standaard laaghoogte (%.2f mm).\n" +"\n" +"De laaghoogte is verlaagd naar %.2f mm (een waarde die door de profielen van deze printer wordt gebruikt), zodat de toren de gevraagde snelheid kan halen." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Zelfs bij de kleinste laaghoogte die door de profielen van deze printer wordt gebruikt (%.2f mm) overschrijdt de eindsnelheid (%.0f mm/s) de maximale volumetrische snelheid van het filament (%.1f mm³/s).\n" +"\n" +"De laaghoogte wordt ingesteld op %.2f mm en de eindsnelheid verlaagd naar %.0f mm/s.\n" +"\n" +"Doorgaan?" + +# AI Translated +msgid "Continue anyway?" +msgstr "Toch doorgaan?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "\"Automatisch aanpassen\" inschakelen om dit automatisch op te lossen, of toch doorgaan?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "\"Automatisch schalen naar mondstuk\" en \"Automatisch aanpassen\" inschakelen om dit automatisch op te lossen, of toch doorgaan?" + msgid "Start retraction length: " msgstr "Begin terugtreklengte:" @@ -23665,6 +23781,10 @@ msgstr "" "Kromtrekken voorkomen\n" "Wist je dat bij het printen van materialen die gevoelig zijn voor kromtrekken, zoals ABS, een juiste verhoging van de temperatuur van het warmtebed de kans op kromtrekken kan verkleinen?" +# AI Translated +#~ msgid "Print order within a single layer." +#~ msgstr "Printvolgorde binnen één laag." + #~ msgid "Bottom" #~ msgstr "Onderkant" @@ -23707,9 +23827,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgctxt "Sync_Nozzle_AMS" #~ msgid "Cancel" #~ msgstr "Annuleren" diff --git a/localization/i18n/pl/OrcaSlicer_pl.po b/localization/i18n/pl/OrcaSlicer_pl.po index ab64679801..a0701dca09 100644 --- a/localization/i18n/pl/OrcaSlicer_pl.po +++ b/localization/i18n/pl/OrcaSlicer_pl.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: OrcaSlicer 2.3.0-rc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: \n" "Last-Translator: Krzysztof Morga <>\n" "Language-Team: \n" @@ -3926,6 +3926,10 @@ msgstr "Układanie..." msgid "Arranging" msgstr "Układanie" +# AI Translated +msgid "Arranging " +msgstr "Rozmieszczanie " + msgid "Arranging canceled." msgstr "Układanie anulowane." @@ -8440,24 +8444,24 @@ msgid "Replaced with 3D files from directory:\n" msgstr "Zastąpiono plikami 3D z katalogu:\n" # AI Translated -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ Pominięto %1%: ten sam plik.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ Pominięto %s: ten sam plik.\n" # AI Translated -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ Pominięto %1%: plik nie istnieje.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ Pominięto %s: plik nie istnieje.\n" # AI Translated -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ Pominięto %1%: nie udało się zastąpić.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ Pominięto %s: nie udało się zastąpić.\n" # AI Translated -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ Zastąpiono %1%.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ Zastąpiono %s.\n" # AI Translated msgid "Replaced volumes" @@ -9479,6 +9483,21 @@ msgstr "Przyciemnij niższe warstwy" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "Podczas przewijania suwaka warstw w podglądzie po cięciu renderuj warstwy poniżej bieżącej w przyciemnieniu, tak aby tylko oglądana warstwa była w pełnej jasności." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Jasność przyciemnionych warstw" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"Jak jasno renderowane są przyciemnione warstwy, gdy włączona jest opcja „Przyciemnij niższe warstwy”.\n" +"99% oznacza ledwo zauważalne przyciemnienie, 0% renderuje je na czarno. Wartość jest ograniczona do 99%, ponieważ 100% oznaczałoby to samo co wyłączenie opcji." + msgid "Login region" msgstr "Region logowania" @@ -13709,12 +13728,37 @@ msgstr "Wg obiektu" msgid "Intra-layer order" msgstr "Kolejność warstw" -msgid "Print order within a single layer." -msgstr "Kolejność druku obiektów w obrębie jednej warstwy. Domyślnie lub według listy obiektów" +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Kolejność, w jakiej instancje obiektów są odwiedzane w obrębie jednej warstwy; decyduje o tym, ile przemieszczeń zajmuje przechodzenie między nimi.\n" +"\n" +"Domyślny: łączenie metodą najbliższego sąsiada, dopracowane algorytmem 2-opt i usuwaniem przecięć. Dobry wybór ogólny.\n" +"Wg listy obiektów: instancje są drukowane w tej samej kolejności co na liście obiektów, bez optymalizacji ścieżki. Użyj, gdy potrzebujesz przewidywalnej, ręcznie ustalonej kolejności.\n" +"Najlepsza ze wszystkich (najkrótsza ścieżka): oceniane są wszystkie strategie i wybierana jest najkrótsza. Kolejność instancji obiektów ustalana jest raz dla całego wydruku, natomiast kolejność poszczególnych wysp jest ustalana dla każdej warstwy, więc różne warstwy mogą ostatecznie korzystać z różnych strategii. Cięcie trwa nieco dłużej.\n" +"Wężykiem: serpentynowe przechodzenie rząd po rzędzie, dopracowane algorytmem 2-opt. Dobrze sprawdza się przy regularnych siatkach wielu małych elementów.\n" +"\n" +"Gdy w tej samej warstwie używanych jest wiele filamentów lub narzędzi, priorytetem jest minimalizacja zmian narzędzia: obiekty są najpierw grupowane według filamentu, a to ustawienie porządkuje jedynie instancje w obrębie każdej grupy, więc ogólna sekwencja może nie wyglądać jak najkrótsza ścieżka po płycie." msgid "As object list" msgstr "Wg listy obiektów" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "Najlepsza ze wszystkich (najkrótsza ścieżka)" + +# AI Translated +msgid "Snake" +msgstr "Wężykiem" + msgid "Slow printing down for better layer cooling" msgstr "Zwolnienie druku dla lepszego chłodzenia warstw" @@ -19211,6 +19255,20 @@ msgstr "" "Jest kilka adresów IP przypisanych do nazwy hosta %1%.\n" "Proszę wybrać jeden, który ma być używany." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "Automatyczne skalowanie do dyszy" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Ten model zaprojektowano dla dyszy 0,4 mm i wysokości warstwy 0,2 mm. \n" +"Gdy opcja skalowania jest włączona (zalecane), model dynamicznie dopasowuje rozmiar do średnicy Twojej obecnej dyszy i odpowiedniej wysokości warstwy, dzięki czemu test jest dokładny i łatwy do odczytania.\n" +"Wyłącz skalowanie tylko wtedy, gdy chcesz wydrukować model referencyjny dokładnie w oryginalnej postaci." + msgid "PA Calibration" msgstr "Kalibracja PA" @@ -19349,6 +19407,14 @@ msgstr "Rozpocznij z prędkością: " msgid "End speed: " msgstr "Zakończ z prędkością: " +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "Automatyczne dopasowanie do maksymalnej prędkości przepływu" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Jeśli prędkość końcowa przekroczyłaby maksymalną prędkość przepływu filamentu, automatycznie obniż wysokość warstwy (zachowując standardowe wartości i pozostając w limitach maszyny), aby ją osiągnąć. Jeśli nawet minimalna wysokość warstwy nie wystarczy, obniżona zostanie prędkość końcowa." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -19360,6 +19426,57 @@ msgstr "" "krok >= 0\n" "koniec > start + krok)" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"Prędkość końcowa (%.0f mm/s) przekracza maksymalną prędkość przepływu filamentu (%.1f mm³/s), która przy tej szerokości linii i wysokości warstwy ogranicza zewnętrzną ścianę do około %.0f mm/s.\n" +" Wyższe prędkości zostaną ograniczone, więc górne bloki wieży nie zostaną wydrukowane z żądaną prędkością.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"Prędkość końcowa (%.0f mm/s) przekracza maksymalną prędkość przepływu filamentu (%.1f mm³/s) przy domyślnej wysokości warstwy (%.2f mm).\n" +"\n" +"Wysokość warstwy została zmniejszona do %.2f mm (wartość stosowana w profilach tej drukarki), aby wieża mogła osiągnąć żądaną prędkość." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Nawet przy najmniejszej wysokości warstwy stosowanej w profilach tej drukarki (%.2f mm) prędkość końcowa (%.0f mm/s) przekracza maksymalną prędkość przepływu filamentu (%.1f mm³/s).\n" +"\n" +"Wysokość warstwy zostanie ustawiona na %.2f mm, a prędkość końcowa obniżona do %.0f mm/s.\n" +"\n" +"Kontynuować?" + +# AI Translated +msgid "Continue anyway?" +msgstr "Kontynuować mimo to?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Włączyć „Automatyczne dopasowanie”, aby naprawić to automatycznie, czy kontynuować mimo to?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Włączyć „Automatyczne skalowanie do dyszy” i „Automatyczne dopasowanie”, aby naprawić to automatycznie, czy kontynuować mimo to?" + msgid "Start retraction length: " msgstr "Długość retrakcji na początku: " @@ -22117,6 +22234,9 @@ msgstr "" "Unikaj odkształceń\n" "Czy wiesz, że podczas drukowania filamentami podatnymi na odkształcenia, takimi jak ABS, odpowiednie zwiększenie temperatury podgrzewanej płyty może zmniejszyć prawdopodobieństwo odkształceń?" +#~ msgid "Print order within a single layer." +#~ msgstr "Kolejność druku obiektów w obrębie jednej warstwy. Domyślnie lub według listy obiektów" + #~ msgid "Bottom" #~ msgstr "Dół" @@ -22191,9 +22311,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Continue to sync filaments" #~ msgstr "Kontynuuj aby zsynchronizować filamenty" diff --git a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po index cfe7549122..0d777ec32e 100644 --- a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po +++ b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: 2026-07-26 11:14-0300\n" "Last-Translator: Alexandre Folle de Menezes\n" "Language-Team: Portuguese, Brazilian\n" @@ -3700,6 +3700,10 @@ msgstr "Organizando…" msgid "Arranging" msgstr "Organizando" +# AI Translated +msgid "Arranging " +msgstr "Organizando " + msgid "Arranging canceled." msgstr "Organização cancelada." @@ -8022,21 +8026,21 @@ msgstr "Diretório para substituição não foi selecionado" msgid "Replaced with 3D files from directory:\n" msgstr "Substituído por arquivos 3D do diretório:\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ %1% Ignorados: mesmo arquivo.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ %s Ignorados: mesmo arquivo.\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ %1% Ignorados: arquivo não existe.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ %s Ignorados: arquivo não existe.\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ %1% Ignorados: falha ao substituir.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ %s Ignorados: falha ao substituir.\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ %1% Substituídos.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ %s Substituídos.\n" msgid "Replaced volumes" msgstr "Volumes substiruídos" @@ -8975,6 +8979,22 @@ msgstr "Escurecer camadas inferiores" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "Ao mover o controle deslizante de camadas na pré-visualização fatiada, renderiza as camadas abaixo da atual escurecidas, de modo que apenas a camada visualizada seja exibida com brilho total." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Brilho das camadas escurecidas" + +# AI Translated +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"Com que brilho as camadas escurecidas são exibidas quando \"Escurecer camadas inferiores\" está ativado.\n" +"99% quase não escurece, 0% as deixa pretas. Limitado a 99% porque 100% seria o mesmo que desativar a opção." + msgid "Login region" msgstr "Região de login" @@ -12983,12 +13003,37 @@ msgstr "Por objeto" msgid "Intra-layer order" msgstr "Ordem intra-camada" -msgid "Print order within a single layer." -msgstr "Ordem de impressão dentro de uma única camada." +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Ordem em que as instâncias dos objetos são visitadas dentro de uma mesma camada, o que determina quanto deslocamento é gasto no trajeto entre elas.\n" +"\n" +"Padrão: encadeamento por vizinho mais próximo, refinado com 2-opt e remoção de cruzamentos. Uma boa escolha geral.\n" +"Como lista de objetos: as instâncias são impressas na mesma ordem da lista de objetos, sem nenhuma otimização de trajeto. Use quando precisar de uma ordem previsível e controlada manualmente.\n" +"Melhor de todas (caminho mais curto): todas as estratégias são avaliadas e a mais curta é usada. A ordem das instâncias dos objetos é definida uma única vez para toda a impressão, enquanto a ordem das ilhas individuais é definida por camada, de modo que camadas diferentes podem acabar usando estratégias diferentes. O fatiamento fica um pouco mais lento.\n" +"Serpentina: percurso em serpentina, linha por linha, refinado com 2-opt. Adequado a grades regulares de muitas peças pequenas.\n" +"\n" +"Com vários filamentos ou ferramentas na mesma camada, minimizar as trocas de ferramenta tem prioridade: os objetos são agrupados primeiro por filamento e esta configuração ordena apenas as instâncias dentro de cada grupo de filamento, portanto a sequência geral pode não parecer o caminho mais curto pela placa." msgid "As object list" msgstr "Como lista de objetos" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "Melhor de todas (caminho mais curto)" + +# AI Translated +msgid "Snake" +msgstr "Serpentina" + msgid "Slow printing down for better layer cooling" msgstr "Diminuir a velocidade de impressão para melhor resfriamento de camada" @@ -17085,15 +17130,12 @@ msgstr "Quando este valor de retração for modificado, ele será usado como a q msgid "Support fast purge mode" msgstr "Suporte ao modo de purga rápida" -# AI Translated msgid "Whether this printer supports fast purge mode with optimized temperature and multiplier." msgstr "Se esta impressora suporta o modo de purga rápida com temperatura e multiplicador otimizados." -# AI Translated msgid "Filament change" msgstr "Troca de filamento" -# AI Translated msgid "The volume of material required to prime the extruder on the tower, excluding a hotend change." msgstr "O volume de material necessário para preparar a extrusora na torre, excluindo uma troca de hotend." @@ -18278,6 +18320,18 @@ msgstr "" "Há vários endereços IP resolvendo para o nome do host %1%.\n" "Por favor, selecione um que deve ser usado." +msgid "Auto-scale for nozzle" +msgstr "Escala automática para o bico" + +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Este modelo foi projetado para um bico de 0,4 mm com altura de camada de 0,2 mm. \n" +"Quando a opção de escala está ativada (recomendado), ele é redimensionado dinamicamente para corresponder ao diâmetro do bico atual e a uma altura de camada apropriada, tornando o teste preciso e fácil de ler.\n" +"Desative a escala apenas se quiser imprimir o modelo de referência exatamente como está." + msgid "PA Calibration" msgstr "Calibração de PA" @@ -18414,6 +18468,12 @@ msgstr "Velocidade Inicial: " msgid "End speed: " msgstr "Velocidade Final: " +msgid "Auto-adjust to max volumetric speed" +msgstr "Ajuste automático à velocidade volumétrica máxima" + +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Se a velocidade final ultrapassar a velocidade volumétrica máxima do filamento, reduz automaticamente a altura de camada (mantendo valores padrão e respeitando os limites da máquina) para alcançá-la. Se nem mesmo a altura de camada mínima for suficiente, reduz a velocidade final." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -18425,6 +18485,51 @@ msgstr "" "passo >= 0\n" "fim > início + passo" +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"A velocidade final (%.0f mm/s) excede a velocidade volumétrica máxima do filamento (%.1f mm³/s), o que limita a parede externa a cerca de %.0f mm/s com esta largura de linha e altura de camada.\n" +" Velocidades acima disso serão limitadas, portanto os blocos superiores da torre não serão impressos na velocidade solicitada.\n" +"\n" +"%s" + +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"A velocidade final (%.0f mm/s) ultrapassa a velocidade volumétrica máxima do filamento (%.1f mm³/s) na altura de camada padrão (%.2f mm).\n" +"\n" +"A altura de camada foi reduzida para %.2f mm (um valor usado pelos perfis desta impressora) para que a torre possa atingir a velocidade solicitada." + +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Mesmo na menor altura de camada usada pelos perfis desta impressora (%.2f mm), a velocidade final (%.0f mm/s) ultrapassa a velocidade volumétrica máxima do filamento (%.1f mm³/s).\n" +"\n" +"A altura de camada será definida como %.2f mm e a velocidade final reduzida para %.0f mm/s.\n" +"\n" +"Continuar?" + +msgid "Continue anyway?" +msgstr "Continuar mesmo assim?" + +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Ativar \"Ajuste automático\" para corrigir isso automaticamente ou continuar mesmo assim?" + +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Ativar \"Escala automática para o bico\" e \"Ajuste automático\" para corrigir isso automaticamente ou continuar mesmo assim?" + msgid "Start retraction length: " msgstr "Distância de Retração Inicial: " @@ -19526,9 +19631,8 @@ msgstr "Não foi possível decifrar a resposta do servidor." msgid "Error saving session to file" msgstr "Erro salvando sessão para arquivo" -# AI Translated msgid "Error session check" -msgstr "Verificação de sessão de erro" +msgstr "Erro na verificação de sessão" msgid "Error during file upload" msgstr "Erro durante a subida do arquivo" @@ -19961,9 +20065,8 @@ msgstr "Impressão Falhou" msgid "Removed" msgstr "Removido" -# AI Translated msgid "Enable smart filament assign: Assign one filament to multiple nozzles to maximize savings" -msgstr "Ativar atribuição inteligente de filamento: atribui um filamento a vários bicos para maximizar a economia" +msgstr "Ativar atribuição inteligente de filamento: Atribui um filamento a vários bicos para maximizar a economia" msgid "Fila Saving" msgstr "Econo Filamento" @@ -20001,7 +20104,6 @@ msgstr "Tutorial em vídeo" msgid "(Sync with printer)" msgstr "(Sinc. com impressora)" -# AI Translated #, c-format, boost-format msgid "Error: %s extruder has no available %s nozzle, current group result is invalid." msgstr "Erro: a extrusora %s não tem nenhum bico %s disponível, o resultado do grupo atual é inválido." @@ -20012,17 +20114,14 @@ msgstr "Vamos fatiar de acordo com este método de agrupamento:" msgid "Tip: You can drag the filaments to reassign them to different nozzles." msgstr "Dica: Você pode arrastar os filamentos para reatribuí-los a diferentes bicos." -# AI Translated msgid "Please adjust your grouping or click " msgstr "Por favor, ajuste seu agrupamento ou clique em " -# AI Translated msgid " to set nozzle count" msgstr " para definir o número de bicos" -# AI Translated msgid "Set the physical nozzle count..." -msgstr "Definir o número físico de bicos..." +msgstr "Definir o número de bicos físicos…" msgid "The filament grouping method for current plate is determined by the dropdown option at the slicing plate button." msgstr "O método de agrupamento de filamentos para a placa atual é determinado pela opção no botão de fatiamento da placa." @@ -20362,99 +20461,75 @@ msgstr "Numero de facetas triangulares" msgid "Calculating, please wait..." msgstr "Calculando, por favor aguarde…" -# AI Translated msgid "Save these settings as default" msgstr "Salvar estas configurações como padrão" -# AI Translated msgid "If enabled, the values above are stored as the defaults used for future STEP imports (and shown in Preferences)." msgstr "Se ativado, os valores acima são armazenados como os padrões usados para futuras importações STEP (e mostrados nas Preferências)." -# AI Translated msgid "PresetBundle" msgstr "PresetBundle" -# AI Translated msgid "Bundle folder does not exist." msgstr "A pasta do pacote não existe." -# AI Translated msgid "Failed to open folder." msgstr "Falha ao abrir a pasta." -# AI Translated msgid "Delete selected bundle from folder and all presets loaded from it?" msgstr "Excluir o pacote selecionado da pasta e todas as predefinições carregadas a partir dele?" -# AI Translated msgid "Delete Bundle" -msgstr "Excluir pacote" +msgstr "Excluir Pacote" -# AI Translated msgid "Failed to remove bundle." msgstr "Falha ao remover o pacote." -# AI Translated msgid "Remove Bundle" msgstr "Remover pacote" -# AI Translated msgid "Unsubscribe bundle?" msgstr "Cancelar a inscrição do pacote?" -# AI Translated msgid "UnsubscribeBundle" msgstr "UnsubscribeBundle" -# AI Translated msgid "Failed to unsubscribe bundle." msgstr "Falha ao cancelar a inscrição do pacote." -# AI Translated msgid "Unsubscribe Bundle" -msgstr "Cancelar inscrição do pacote" +msgstr "Cancelar inscrição do Pacote" -# AI Translated msgid "ExportPresetBundle" msgstr "ExportPresetBundle" -# AI Translated msgid "Save preset bundle" msgstr "Salvar pacote de predefinições" -# AI Translated msgid "Performing desktop integration failed - boost::filesystem::canonical did not return appimage path." msgstr "Falha ao realizar a integração com a área de trabalho - boost::filesystem::canonical não retornou o caminho do appimage." -# AI Translated msgid "Performing desktop integration failed - Could not find executable." msgstr "Falha ao realizar a integração com a área de trabalho - não foi possível encontrar o executável." -# AI Translated msgid "Performing desktop integration failed because the application directory was not found." msgstr "Falha ao realizar a integração com a área de trabalho porque o diretório do aplicativo não foi encontrado." -# AI Translated msgid "Performing desktop integration failed - could not create Gcodeviewer desktop file. OrcaSlicer desktop file was probably created successfully." msgstr "Falha ao realizar a integração com a área de trabalho - não foi possível criar o arquivo desktop do Gcodeviewer. O arquivo desktop do OrcaSlicer provavelmente foi criado com sucesso." -# AI Translated msgid "Performing downloader desktop integration failed - boost::filesystem::canonical did not return appimage path." msgstr "Falha ao realizar a integração do downloader com a área de trabalho - boost::filesystem::canonical não retornou o caminho do appimage." -# AI Translated msgid "Performing downloader desktop integration failed - Could not find executable." msgstr "Falha ao realizar a integração do downloader com a área de trabalho - não foi possível encontrar o executável." -# AI Translated msgid "Performing downloader desktop integration failed because the application directory was not found." msgstr "Falha ao realizar a integração do downloader com a área de trabalho porque o diretório do aplicativo não foi encontrado." -# AI Translated msgid "Desktop Integration" -msgstr "Integração com a área de trabalho" +msgstr "Integração com a Área de Trabalho" -# AI Translated msgid "" "Desktop Integration sets this binary to be searchable by the system.\n" "\n" @@ -20478,40 +20553,33 @@ msgstr "Arquivar pré-visualização" msgid "Open File" msgstr "Abrir Arquivo" -# AI Translated msgid "AMS Dryness Control" -msgstr "Controle de secura do AMS" +msgstr "Controle de Secura do AMS" -# AI Translated msgid "Filament Drying Settings" -msgstr "Configurações de secagem de filamento" +msgstr "Configurações de Secagem de Filamento" msgid "Stopping" msgstr "Parando" -# AI Translated msgid "Unable to dry temporarily due to ..." -msgstr "Não é possível secar temporariamente devido a ..." +msgstr "Não é possível secar temporariamente devido a…" msgid "Drying Error" msgstr "Erro de Secagem" -# AI Translated msgid "Please check the Assistant for troubleshooting" msgstr "Por favor, verifique o Assistente para solução de problemas" -# AI Translated msgid "Please remove and store the filament (as shown)." msgstr "Por favor, remova e guarde o filamento (como mostrado)." -# AI Translated msgid "The AMS can rotate the filament which is properly stored, providing better drying results." msgstr "O AMS pode girar o filamento que está corretamente armazenado, proporcionando melhores resultados de secagem." msgid "Rotate spool when drying" msgstr "Girar o carretel durante a secagem" -# AI Translated msgctxt "amsdrying" msgid "Back" msgstr "Voltar" @@ -20531,11 +20599,9 @@ msgstr " temperatura mínima de secagem é " msgid "This filament may not be completely dried." msgstr "Este filamento pode não estar completamente seco." -# AI Translated msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature." msgstr "Este AMS está imprimindo no momento. Para garantir a qualidade da impressão, a temperatura de secagem não pode exceder a temperatura de secagem recomendada." -# AI Translated msgid "The temperature shall not exceed the filament's heat distortion temperature" msgstr "A temperatura não deve exceder a temperatura de distorção térmica do filamento" @@ -20548,22 +20614,18 @@ msgstr "O valor máximo de tempo não pode ser superior a 24." msgid "Insufficient power" msgstr "Potência insuficiente" -# AI Translated msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting." msgstr " Muitos AMS secando simultaneamente. Por favor, conecte à energia ou pare outros processos de secagem antes de iniciar." msgid "AMS is busy" msgstr "O AMS está ocupado" -# AI Translated msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait." msgstr " O AMS está calibrando | lendo RFID | carregando/descarregando material, por favor aguarde." -# AI Translated msgid "Filament in AMS outlet" msgstr "Filamento na saída do AMS" -# AI Translated msgid " The high drying temperature may cause AMS blockage, please unload first." msgstr " A alta temperatura de secagem pode causar bloqueio do AMS, por favor descarregue primeiro." @@ -20576,18 +20638,15 @@ msgstr "Não suportado no modo 2D" msgid "Task in progress" msgstr "Tarefa em progresso" -# AI Translated msgid " The AMS might be in use during Task." msgstr " O AMS pode estar em uso durante a Tarefa." msgid " Firmware update in progress, please wait..." -msgstr " Atualização de firmware em progresso, por favor aguarde..." +msgstr " Atualização de firmware em progresso, por favor aguarde…" -# AI Translated msgid " Please plug in the power and then use the drying function." -msgstr " Por favor, conecte à energia e depois use a função de secagem." +msgstr " Por favor, conecte à energia e então use a função de secagem." -# AI Translated msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding." msgstr " A alta temperatura de secagem pode causar bloqueio do AMS. Por favor, descarregue o filamento manualmente antes de prosseguir." @@ -20595,7 +20654,7 @@ msgid "System is busy" msgstr "O sistema está ocupado" msgid " Initiating other drying processes, please wait a few seconds..." -msgstr " Iniciando outros processos de secagem, por favor aguarde alguns segundos..." +msgstr " Iniciando outros processos de secagem, por favor aguarde alguns segundos…" msgid "For better drying results, remove the filament and allow it to rotate." msgstr "Para obter melhores resultados de secagem, remova o filamento e permita que ele gire." @@ -20948,6 +21007,9 @@ msgstr "" "Evitar empenamento\n" "Você sabia que ao imprimir materiais propensos ao empenamento como ABS, aumentar adequadamente a temperatura da mesa aquecida pode reduzir a probabilidade de empenamento?" +#~ msgid "Print order within a single layer." +#~ msgstr "Ordem de impressão dentro de uma única camada." + #~ msgid "Bottom" #~ msgstr "Inferior" @@ -20957,17 +21019,6 @@ msgstr "" #~ msgid "Rear" #~ msgstr "Traseira" -# AI Translated -#, boost-format -#~ msgid "" -#~ "Objects(%1%) have duplicated connectors. Some connectors may be missing in slicing result.\n" -#~ "Please report to PrusaSlicer team in which scenario this issue happened.\n" -#~ "Thank you." -#~ msgstr "" -#~ "Os objetos(%1%) têm conectores duplicados. Alguns conectores podem estar faltando no resultado do fatiamento.\n" -#~ "Por favor, informe à equipe do PrusaSlicer em qual cenário esse problema ocorreu.\n" -#~ "Obrigado." - #~ msgid "Skip for Now" #~ msgstr "Pular por Enquanto" diff --git a/localization/i18n/ru/OrcaSlicer_ru.po b/localization/i18n/ru/OrcaSlicer_ru.po index fa629fd222..c2fbcb54be 100644 --- a/localization/i18n/ru/OrcaSlicer_ru.po +++ b/localization/i18n/ru/OrcaSlicer_ru.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: OrcaSlicer V2.5.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: 2026-02-25 13:38+0300\n" "Last-Translator: Felix14_v2\n" "Language-Team: Felix14_v2 (ДС/ТГ: @felix14_v2, почта: aleks111001@list.ru), Andylg \n" @@ -27,15 +27,12 @@ msgstr "Основной экструдер" msgid "main extruder" msgstr "основной экструдер" -# AI Translated msgid "Auxiliary Extruder" msgstr "Вспомогательный экструдер" -# AI Translated msgid "Auxiliary extruder" msgstr "Вспомогательный экструдер" -# AI Translated msgid "auxiliary extruder" msgstr "вспомогательный экструдер" @@ -57,27 +54,21 @@ msgstr "Правый экструдер" msgid "right extruder" msgstr "правый экструдер" -# AI Translated msgid "Main Nozzle" msgstr "Основное сопло" -# AI Translated msgid "Main nozzle" msgstr "Основное сопло" -# AI Translated msgid "main nozzle" msgstr "основное сопло" -# AI Translated msgid "Auxiliary Nozzle" msgstr "Вспомогательное сопло" -# AI Translated msgid "Auxiliary nozzle" msgstr "Вспомогательное сопло" -# AI Translated msgid "auxiliary nozzle" msgstr "вспомогательное сопло" @@ -99,67 +90,51 @@ msgstr "Правый экструдер" msgid "right nozzle" msgstr "правого сопла" -# AI Translated msgid "Main Hotend" msgstr "Основной хотэнд" -# AI Translated msgid "Main hotend" msgstr "Основной хотэнд" -# AI Translated msgid "main hotend" msgstr "основной хотэнд" -# AI Translated msgid "Auxiliary Hotend" msgstr "Вспомогательный хотэнд" -# AI Translated msgid "Auxiliary hotend" msgstr "Вспомогательный хотэнд" -# AI Translated msgid "auxiliary hotend" msgstr "вспомогательный хотэнд" -# AI Translated msgid "Left Hotend" msgstr "Левый хотэнд" -# AI Translated msgid "Left hotend" msgstr "Левый хотэнд" -# AI Translated msgid "left hotend" msgstr "левый хотэнд" -# AI Translated msgid "Right Hotend" msgstr "Правый хотэнд" -# AI Translated msgid "Right hotend" msgstr "Правый хотэнд" -# AI Translated msgid "right hotend" msgstr "правый хотэнд" -# AI Translated msgid "main" msgstr "основной" -# AI Translated msgid "auxiliary" msgstr "вспомогательный" -# AI Translated msgid "Main" msgstr "Основной" -# AI Translated msgid "Auxiliary" msgstr "Вспомогательный" @@ -279,7 +254,7 @@ msgstr "Высокий расход" msgid "Standard" msgstr "Обычный" -# AI Translated +# На бамбувики просто "хотэнд ТПУ". Очевидно, машинный перевод. Оставляю оригинальное. msgid "TPU High Flow" msgstr "TPU High Flow" @@ -295,7 +270,6 @@ msgstr "Нержавеющая сталь" msgid "Tungsten Carbide" msgstr "Карбид вольфрама" -# AI Translated msgid "The toolhead and hotend rack may move. Please keep your hands away from the chamber." msgstr "Печатающая голова и стойка хотэндов могут смещаться. Держите руки подальше от камеры." @@ -350,15 +324,12 @@ msgstr "Версия:" msgid "Latest version" msgstr "Последняя версия" -# AI Translated msgid "Row A" msgstr "Ряд A" -# AI Translated msgid "Row B" -msgstr "Ряд B" +msgstr "Ряд Б" -# AI Translated msgid "Toolhead" msgstr "Печатающая голова" @@ -368,9 +339,8 @@ msgstr "Пусто" msgid "Error" msgstr "Ошибка" -# AI Translated msgid "Induction Hotend Rack" -msgstr "Индукционная стойка хотэндов" +msgstr "Стойка индукционных хотэндов" msgid "Hotends Info" msgstr "Информация о хотэндах" @@ -384,30 +354,25 @@ msgstr "Чтение " msgid "Please wait" msgstr "Подождите" -# AI Translated msgid "Reading" msgstr "Чтение" -# AI Translated msgid "Running..." msgstr "Выполнение..." -# AI Translated +# Ряд msgid "Raised" -msgstr "Поднято" +msgstr "Поднят" -# AI Translated msgid "The hotend is in an abnormal state and currently unavailable. Please go to 'Device -> Upgrade' to upgrade firmware." -msgstr "Хотэнд находится в нештатном состоянии и сейчас недоступен. Перейдите в «Устройство -> Обновление», чтобы обновить прошивку." +msgstr "Хотэнд находится в нештатном состоянии и сейчас недоступен. Перейдите в «Принтер» → «Обновление», чтобы обновить прошивку." -# AI Translated msgid "Abnormal Hotend" msgstr "Нештатное состояние хотэнда" msgid "Cancel" msgstr "Отмена" -# AI Translated msgid "Jump to the upgrade page" msgstr "Перейти на страницу обновления" @@ -417,9 +382,8 @@ msgstr "Обновить" msgid "Refreshing" msgstr "Обновление" -# AI Translated msgid "Hotend status abnormal, unavailable at present. Please upgrade the firmware and try again." -msgstr "Состояние хотэнда нештатное, сейчас недоступно. Обновите прошивку и повторите попытку." +msgstr "Хотэнд находится в нештатном состоянии и сейчас недоступен. Обновите прошивку и попробуйте ещё раз." msgid "SN" msgstr "Серийный номер" @@ -431,19 +395,16 @@ msgstr "Версия" msgid "Used Time: %s" msgstr "Время использования: %s" -# AI Translated +# Полагаю, речь об этом https://wiki.bambulab.com/ru/software/bambu-studio/filament-track-switch-dynamic-mapping msgid "Dynamic nozzles are allocated on the current plate. Picking hotend is not supported." msgstr "На текущем столе назначены динамические сопла. Выбор хотэнда не поддерживается." -# AI Translated msgid "Hotend Rack" msgstr "Стойка хотэндов" -# AI Translated msgid "ToolHead" msgstr "Печатающая голова" -# AI Translated msgid "Nozzle information needs to be read" msgstr "Необходимо считать информацию о сопле" @@ -948,7 +909,6 @@ msgstr "Снять выбор" msgid "Select all connectors" msgstr "Выбрать все соединения" -# AI Translated msgctxt "Cut tool" msgid "Cut" msgstr "Разрезать" @@ -1885,14 +1845,14 @@ msgid "" "Select 2 faces on objects and \n" " make objects assemble together." msgstr "" -"Выберите две грани на моделях и\n" -"соберите объекты вместе." +"Выберите две грани на моделях и соберите\n" +"объекты вместе." msgid "" "Select 2 points or circles on objects and \n" " specify distance between them." msgstr "" -"Выберите 2 точки или окружности на моделях \n" +"Выберите 2 точки или окружности на моделях\n" "и укажите расстояние между ними." msgid "Face" @@ -1954,7 +1914,6 @@ msgstr "Запуск режима измерения" msgid "Leaving Measure gizmo" msgstr "Выход из режима измерения" -# AI Translated msgctxt "Assembly tool" msgid "Assemble" msgstr "Собрать" @@ -1968,8 +1927,9 @@ msgstr "Выберите минимум две модели." msgid "(Moving)" msgstr "(подвижная)" +# Пробел в конце, чтобы не срезалась часть msgid "Point and point assembly" -msgstr "Сборка по точкам" +msgstr "Сборка по точкам " # Зачем здесь "внимание"? Это просто руководство к действию msgid "Warning: please select two different meshes." @@ -1992,8 +1952,9 @@ msgstr "" "для получения возможности поднимать их\n" "над столом." +# Пробел в конце, чтобы не срезалась часть msgid "Face and face assembly" -msgstr "Сборка по граням" +msgstr "Сборка по граням " msgid "Entering Assembly gizmo" msgstr "Запуск режима сборки" @@ -2133,7 +2094,7 @@ msgstr "" "\n" "Для автоматического переноса существующих профилей войдите в Orca Cloud. Посетите нашу Вики, чтобы узнать подробнее о ручном переносе, хранении и синхронизации профилей.\n" "\n" -"Можно спокойно игнорировать это сообщение, если вы ранее не использовали Bambu Cloud для синхронизации." +"Можно спокойно игнорировать это сообщение, если вы ранее не использовали Bambu Cloud для синхронизации. " msgid "Profile syncing change" msgstr "Изменения в синхронизации профилей" @@ -2214,7 +2175,6 @@ msgstr "Загрузка плагинов" msgid "Plugin %s is no longer available." msgstr "Плагин «%s» больше недоступен." -# AI Translated #, c-format, boost-format msgid "Plugin %s access is unauthorized." msgstr "Доступ к плагину %s не авторизован." @@ -3661,10 +3621,9 @@ msgid "Left(Aux)" msgstr "Левый (вспом.)" # FAN_HEAT_BREAK_0_IDX - охлаждение термобарьера в первом хотэнде -# AI Translated msgctxt "Hotend Heat Breaker Fan" msgid "Hotend" -msgstr "Хотэнд" +msgstr "1 термобарьер" msgid "Parts" msgstr "Основной" @@ -3713,29 +3672,23 @@ msgstr "Подтверждение экструзии" msgid "Check filament location" msgstr "Проверка расположения прутка" -# AI Translated msgid "Switch" msgstr "Переключить" -# AI Translated msgid "hotend" msgstr "хотэнд" -# AI Translated msgid "Wait for AMS cooling" msgstr "Дождитесь охлаждения AMS" -# AI Translated msgid "Switch current filament at Filament Track Switch" msgstr "Переключить текущий материал на Filament Track Switch" -# AI Translated msgid "Pull back current filament at Filament Track Switch" msgstr "Втянуть текущий материал на Filament Track Switch" -# AI Translated msgid "Switch track at Filament Track Switch" -msgstr "Переключить дорожку на Filament Track Switch" +msgstr "Переключить подачу на Filament Track Switch" msgid "The maximum temperature cannot exceed " msgstr "Температура не должна превышать " @@ -3743,45 +3696,37 @@ msgstr "Температура не должна превышать " msgid "The minmum temperature should not be less than " msgstr "Температура не должна быть ниже " -# AI Translated msgid "Type to filter..." -msgstr "Введите текст для фильтрации..." +msgstr "Поиск..." # в Сохранение толщины вертикальной оболочки. # было Везде, но из-за условия совместимости изменено.... как тогда быть? msgid "All" msgstr "Все" -# AI Translated msgid "No selected items..." -msgstr "Нет выбранных элементов..." +msgstr "Ничего не выбрано..." -# AI Translated msgid "All items selected..." -msgstr "Выбраны все элементы..." +msgstr "Выбраны все..." -# AI Translated msgid "No matching items..." -msgstr "Нет подходящих элементов..." +msgstr "Ничего не найдено..." msgid "Deselect All" msgstr "Снять выбор со всего" -# AI Translated msgid "Select visible" msgstr "Выбрать видимые" -# AI Translated msgid "Deselect visible" msgstr "Снять выбор с видимых" -# AI Translated msgid "Filter selected" -msgstr "Отфильтровать выбранные" +msgstr "Фильтровать выбранные" -# AI Translated msgid "Filter nonSelected" -msgstr "Отфильтровать невыбранные" +msgstr "Фильтровать невыбранные" msgid "Simple settings" msgstr "Простые настройки" @@ -3799,18 +3744,15 @@ msgstr "Режим разработчика" msgid "Launch troubleshoot center" msgstr "Запустить экран отладки" -# AI Translated msgid "Set nozzle count" msgstr "Задать количество сопел" -# AI Translated msgid "Please set nozzle count" -msgstr "Задайте количество сопел" +msgstr "Укажите количество сопел" msgid "Error: Can not set both nozzle count to zero." msgstr "Ошибка: оба значения не могут быть нулевыми." -# AI Translated #, c-format, boost-format msgid "Error: Nozzle count can not exceed %d." msgstr "Ошибка: количество сопел не может превышать %d." @@ -3821,45 +3763,36 @@ msgstr "Подтвердить" msgid "Extruder" msgstr "Экструдер" -# AI Translated msgid "Nozzle Selection" msgstr "Выбор сопла" -# AI Translated msgid "Available Nozzles" msgstr "Доступные сопла" msgid "Nozzle Info" msgstr "Информация о сопле" -# AI Translated msgid "Sync Nozzle status" msgstr "Синхронизировать состояние сопла" -# AI Translated msgid "Caution: Mixing nozzle diameters in one print is not supported. If the selected size is only on one extruder, single-extruder printing will be enforced." -msgstr "Внимание: смешивание диаметров сопел в одной печати не поддерживается. Если выбранный размер есть только на одном экструдере, будет принудительно применена печать одним экструдером." +msgstr "Внимание: смешивание диаметров сопел в одной печати не поддерживается. Печать будет производиться одним соплом, если выбранный диаметр есть только на одном экструдере." -# AI Translated #, c-format, boost-format msgid "Refresh %d/%d..." -msgstr "Обновление %d/%d..." +msgstr "Обновить %d/%d..." -# AI Translated msgid "Unknown nozzle detected. Refresh to update info (unrefreshed nozzles will be excluded during slicing). Verify nozzle diameter & flow rate against displayed values." -msgstr "Обнаружено неизвестное сопло. Обновите, чтобы получить сведения (необновлённые сопла будут исключены при нарезке). Сверьте диаметр сопла и расход с отображаемыми значениями." +msgstr "Обнаружено неизвестное сопло. Обновите для получения сведений (неизвестные сопла будут исключены при нарезке). Сверьте диаметр сопла и расход с отображаемыми значениями." -# AI Translated msgid "Unknown nozzle detected. Refresh to update (unrefreshed nozzles will be skipped in slicing)." -msgstr "Обнаружено неизвестное сопло. Обновите для получения сведений (необновлённые сопла будут пропущены при нарезке)." +msgstr "Обнаружено неизвестное сопло. Обновите для получения сведений (неизвестные сопла будут пропущены при нарезке)." -# AI Translated msgid "Please confirm whether the required nozzle diameter and flow rate match the currently displayed values." msgstr "Убедитесь, что требуемый диаметр сопла и расход соответствуют отображаемым значениям." -# AI Translated msgid "Your printer has different nozzles installed. Please select a nozzle for this print." -msgstr "На вашем принтере установлены разные сопла. Выберите сопло для этой печати." +msgstr "В принтере установлены разные сопла. Выберите сопло для этой печати." msgid "Ignore" msgstr "Игнорировать" @@ -3888,11 +3821,14 @@ msgstr "Расстановка..." msgid "Arranging" msgstr "Расстановка" +msgid "Arranging " +msgstr "Расстановка: " + msgid "Arranging canceled." msgstr "Расстановка отменена." msgid "Arranging complete, but some items were not able to be arranged. Reduce spacing and try again." -msgstr "Расстановка завершена, но не всё удалось уместить на столе. Уменьшите отступ расстановки и повторите попытку." +msgstr "Расстановка завершена, но не всё удалось уместить на столе. Уменьшите отступ и повторите попытку." msgid "Arranging done." msgstr "Расстановка выполнена." @@ -4342,8 +4278,8 @@ msgid "" "Lower half area: The filament from original project will be used when unmapped.\n" "And you can click it to modify" msgstr "" -"Верхняя половина: Исходный\n" -"Нижняя половина: При отсутствии назначения будет использоваться филамент из исходного проекта.\n" +"Сверху: оригинальный материал\n" +"Снизу: материал исходного проекта (если не назначен).\n" "Нажмите для изменения" msgid "" @@ -4353,7 +4289,7 @@ msgid "" msgstr "" "Сверху: оригинальный материал\n" "Снизу: материал из AMS\n" -"Нажмите, чтобы изменить" +"Нажмите для изменения" msgid "" "Upper half area: Original\n" @@ -4367,45 +4303,41 @@ msgid "AMS Slots" msgstr "Слоты AMS" msgid "Please select from the following filaments" -msgstr "Пожалуйста, выберите из следующих филаментов" +msgstr "Выберите из следующих материалов" -# AI Translated #, c-format, boost-format msgid "Select filament that installed to the %s" msgstr "Выберите материал, установленный в %s" msgid "Left AMS" -msgstr "Левый AMS" +msgstr "Левая AMS" +# Оверюзиниг: внешние мосты/внешняя катушка msgid "External" msgstr "Внешние" msgid "Reset current filament mapping" -msgstr "Сбросить текущее назначение филамента" +msgstr "Сбросить переназначенные материалы" msgid "Right AMS" -msgstr "Правый AMS" +msgstr "Правая AMS" #, c-format, boost-format msgid "Printing with the current nozzle may produce an extra %0.2f g of waste." msgstr "Печать текущим соплом может привести к дополнительным затратам %0.2f г материала." -# AI Translated #, c-format, boost-format msgid "Tips: the filament type(%s) does not match with the filament type(%s) in the slicing file. If you want to use this slot, you can install %s instead of %s and change slot information on the 'Device' page." -msgstr "Совет: тип материала (%s) не совпадает с типом материала (%s) в файле нарезки. Если вы хотите использовать этот слот, установите %s вместо %s и измените информацию о слоте на странице «Устройство»." +msgstr "Совет: тип материала (%s) не совпадает с типом материала (%s) в файле нарезки. Если вы хотите использовать этот слот, установите %s вместо %s и измените информацию о слоте на странице «Принтер»." -# AI Translated #, c-format, boost-format msgid "Cannot select: the filament type(%s) does not match with the filament type(%s) in the slicing file. If you want to use this slot, you can install %s instead of %s and change slot information on the 'Device' page." -msgstr "Невозможно выбрать: тип материала (%s) не совпадает с типом материала (%s) в файле нарезки. Если вы хотите использовать этот слот, установите %s вместо %s и измените информацию о слоте на странице «Устройство»." +msgstr "Невозможно выбрать: тип материала (%s) не совпадает с типом материала (%s) в файле нарезки. Если вы хотите использовать этот слот, установите %s вместо %s и измените информацию о слоте на странице «Принтер»." -# AI Translated #, c-format, boost-format msgid "Cannot select: the slot is empty or undefined. If you want to use this slot, you can install %s and change slot information on the 'Device' page." -msgstr "Невозможно выбрать: слот пуст или не определён. Если вы хотите использовать этот слот, установите %s и измените информацию о слоте на странице «Устройство»." +msgstr "Невозможно выбрать: слот пуст или не определён. Если вы хотите использовать этот слот, установите %s и измените информацию о слоте на странице «Принтер»." -# AI Translated msgid "Cannot select: No filament loaded in current slot." msgstr "Невозможно выбрать: в текущий слот не загружен материал." @@ -4447,12 +4379,10 @@ msgstr "Использовать для печати материал с вне msgid "Print with filament in AMS" msgstr "Печать материалом из AMS" -# AI Translated msgctxt "Nozzle position" msgid "Left" msgstr "Левое" -# AI Translated msgctxt "Nozzle position" msgid "Right" msgstr "Правое" @@ -4522,7 +4452,7 @@ msgid "Update remaining capacity" msgstr "Обновлять оставшуюся ёмкость катушки" msgid "AMS will attempt to estimate the remaining capacity of the Bambu Lab filaments." -msgstr "AMS попытается оценить оставшееся количество филаментов Bambu Lab." +msgstr "AMS будет пытаться оценивать оставшееся количество материалов Bambu Lab." msgid "AMS filament backup" msgstr "Резервирование материала AMS" @@ -4804,9 +4734,9 @@ msgid "" "\n" "The first layer height will be reset to 0.2." msgstr "" -"Нулевая высота начального слоя недопустима.\n" +"Нулевая высота первого слоя недопустима.\n" "\n" -"Высота первого слоя будет сброшена до 0.2." +"Значение будет сброшено до 0,2." # Оба первых предложения легко объединяются в одно. msgid "" @@ -5046,9 +4976,9 @@ msgstr "Измерение точности движений" msgid "Enhancing motion precision" msgstr "Улучшение точности движений" -# ??? Измерение точности позиционирования +# Относится к motion accuracy points – точкам фактического положения головы на сетке с эталонными координатами msgid "Measure motion accuracy" -msgstr "Измерение точности перемещения" +msgstr "Измерение точности позиционирования" msgid "Nozzle offset calibration" msgstr "Калибровка смещения сопла" @@ -5057,30 +4987,30 @@ msgid "High temperature auto bed leveling" msgstr "Измерение кривизны разогретого стола" msgid "Auto Check: Quick Release Lever" -msgstr "Автопроверка: быстросъёмный рычаг" +msgstr "Проверка: быстросъёмный модуль" msgid "Auto Check: Door and Upper Cover" -msgstr "Автопроверка: дверца и верхняя крышка" +msgstr "Проверка: дверца и верхняя крышка" msgid "Laser Calibration" msgstr "Калибровка лазера" msgid "Auto Check: Platform" -msgstr "Автопроверка: платформа" +msgstr "Проверка: стол" -# ??? Подтверждение положения камеры msgid "Confirming BirdsEye Camera location" -msgstr "Подтверждение расположения камеры BirdsEye" +msgstr "Подтверждение положения камеры" # ??? Калибровка ракурса камеры msgid "Calibrating BirdsEye Camera" msgstr "Калибровка камеры BirdsEye" +# Нет здесь никакого выравнивания, у бамбуков даже крутилок нет. Это просто снятие карты высот. msgid "Auto bed leveling -phase 1" -msgstr "Автоматическое выравнивание стола — фаза 1" +msgstr "Измерение кривизны стола — фаза 1" msgid "Auto bed leveling -phase 2" -msgstr "Автоматическое выравнивание стола — фаза 2" +msgstr "Измерение кривизны стола — фаза 2" msgid "Heating chamber" msgstr "Нагрев камеры" @@ -5092,19 +5022,22 @@ msgid "Printing calibration lines" msgstr "Печать калибровочных линий" msgid "Auto Check: Material" -msgstr "Автопроверка: материал" +msgstr "Проверка: материал" +# https://wiki.bambulab.com/ru/h2/troubleshooting/hmscode/0C00_0300_0002_0014#:~:text=калибровку%20камеры%20реального%20времени,-: msgid "Live View Camera Calibration" -msgstr "Калибровка камеры Live View" +msgstr "Калибровка камеры реального времени" msgid "Waiting for heatbed to reach target temperature" msgstr "Ожидание нагрева стола" +# у H2D система определяет, где лежит обрезок листа. Но может также относиться и к 3D-гравировке, где определяется расстояние до поверхности. msgid "Auto Check: Material Position" -msgstr "Автопроверка: положение материала" +msgstr "Проверка: положение заготовки" +# https://wiki.bambulab.com/ru/h2/troubleshooting/hmscode/0500_0400_0002_0037 msgid "Cutting Module Offset Calibration" -msgstr "Калибровка смещения режущего модуля" +msgstr "Калибровка смещения модуля резки" msgid "Measuring Surface" msgstr "Измерение поверхности" @@ -5137,7 +5070,7 @@ msgid "Timelapse is not supported while the storage is readonly." msgstr "Запись таймлапсов невозможна на защищённый от записи накопитель." msgid "To ensure your safety, certain processing tasks (such as laser) can only be resumed on printer." -msgstr "В целях безопасности некоторые задачи обработки (например, лазерная) могут быть возобновлены только на принтере." +msgstr "В целях безопасности некоторые виды обработки (например, лазерная) можно возобновить только вручную на принтере." #, c-format, boost-format msgid "The chamber temperature is too high, which may cause the filament to soften. Please wait until the chamber temperature drops below %d℃. You may open the front door or enable fans to cool down." @@ -5174,7 +5107,6 @@ msgstr "Не удалось сгенерировать калибровочны msgid "Calibration error" msgstr "Ошибка калибровки" -# AI Translated msgid "Network unavailable" msgstr "Сеть недоступна" @@ -5190,9 +5122,9 @@ msgstr "Продолжить (проблема решена)" msgid "Stop Printing" msgstr "Остановить печать" -# ??? Перейти к помощнику, Помощник по проверке +# "Ассистент" плохо ложится в "обратитесь к ассистенту", когда речь о руководстве. msgid "Check Assistant" -msgstr "Ассистент проверки" +msgstr "Помощник проверки" msgid "Filament Extruded, Continue" msgstr "Пруток выдавлен, продолжить" @@ -5213,9 +5145,9 @@ msgstr "Просмотр трансляции" msgid "No Reminder Next Time" msgstr "Больше не спрашивать" -# AI Translated +# Перепроверить msgid "Recheck" -msgstr "Проверить снова" +msgstr "Перепроверить" msgid "Ignore. Don't Remind Next Time" msgstr "Игнорировать и больше не спрашивать" @@ -5227,7 +5159,7 @@ msgid "Problem Solved and Resume" msgstr "Проблема решена, продолжить" msgid "Got it, Turn off the Fire Alarm." -msgstr "Понятно, выключить пожарную сигнализацию." +msgstr "Ясно, выключить пожарную сигнализацию." msgid "Retry (problem solved)" msgstr "Повторить (проблема решена)" @@ -5238,15 +5170,12 @@ msgstr "Остановить сушку" msgid "Proceed" msgstr "Продолжить" -# AI Translated msgid "Abort" msgstr "Прервать" -# AI Translated msgid "Disable Purification for This Print" msgstr "Отключить очистку воздуха для этой печати" -# AI Translated msgid "Don't Remind Me" msgstr "Не напоминать" @@ -5259,7 +5188,6 @@ msgstr "Продолжить" msgid "Unknown error." msgstr "Неизвестная ошибка." -# AI Translated msgid "Loading ..." msgstr "Загрузка ..." @@ -5340,8 +5268,9 @@ msgstr "слой(-я)" msgid "Range" msgstr "Диапазон" +# Подставляется в "По умолчанию" в подсказке к параметрам. Не уверен, нужно ли здесь "строка", может просто "пусто"? msgid "Empty string" -msgstr "Пустая строка" +msgstr "пустая строка" msgid "Value is out of range." msgstr "Введённое значение вне диапазона." @@ -5727,7 +5656,7 @@ msgid "Fan speed (%)" msgstr "Скорость вентилятора (%)" msgid "Temperature (℃)" -msgstr "Температура (°C)" +msgstr "Температура (℃)" msgid "Volumetric flow rate (mm³/s)" msgstr "Объёмный расход (мм³/с)" @@ -5811,9 +5740,8 @@ msgid "Adaptive" msgstr "Адаптировать" msgid "Quality / Speed" -msgstr "Качество/Скорость" +msgstr "Качество/скорость" -# AI Translated msgctxt "Mesh action" msgid "Smooth" msgstr "Сгладить" @@ -5915,7 +5843,6 @@ msgstr "Избегать зону калибровки экструзии" msgid "Align to Y axis" msgstr "Выравнивать по оси Y" -# AI Translated msgctxt "Camera View" msgid "Front" msgstr "Спереди" @@ -5924,13 +5851,11 @@ msgctxt "Camera View" msgid "Back" msgstr "Сзади" -# AI Translated #. TRN To be shown in the main menu View->Top msgctxt "Camera View" msgid "Top" msgstr "Сверху" -# AI Translated #. TRN To be shown in the main menu View->Bottom msgctxt "Camera View" msgid "Bottom" @@ -6003,7 +5928,7 @@ msgstr "Назад" # 2026). Похоже, это внутреннее название кнопки с панелью управления визуалом # пространства моделей. msgid "Canvas Toolbar" -msgstr "Панель инструментов холста" +msgstr "Панель инструментов рабочей области" # Тут баг с переносом строк, каждое слово переносится. Чем короче – тем лучше. msgid "Fit camera to scene or selected object." @@ -6134,7 +6059,7 @@ msgid "PLA and PETG filaments detected in the mixture. Adjust parameters accordi msgstr "Обнаружено совместное использование PLA и PETG. Для повышения качества рекомендуется настроить печать в соответствии с" msgid "The prime tower extends beyond the plate boundary." -msgstr "Башня очистки выходит за пределы области печати." +msgstr "Черновая башня выходит за пределы области печати." # После строки подставляется кнопка настройки msgid "Partial flushing volume set to 0. Multi-color printing may cause color mixing in models. Please readjust flushing settings." @@ -6227,15 +6152,16 @@ msgid "" "You can find it in \"Settings > Network > Access code\"\n" "on the printer, as shown in the figure:" msgstr "" -"Вы можете найти его на принтере в разделе \n" -"Настройки > Сеть > Код подключения, как показано на рисунке:" +"Его можно найти на принтере в разделе\n" +"«Настройки» > «Сеть» > «Код подключения», как показано на рисунке:" msgid "" "You can find it in \"Setting > Setting > LAN only > Access Code\"\n" "on the printer, as shown in the figure:" msgstr "" -"Вы можете найти его в «Настройки > Настройки > Только LAN > Код доступа»\n" -"на принтере, как показано на рисунке:" +"Его можно найти на принтере в разделе\n" +"«Настройки» > «Настройки» > «Только LAN» > «Код доступа»,\n" +"как показано на рисунке:" msgid "Invalid input" msgstr "Неверный ввод" @@ -6279,7 +6205,7 @@ msgid "No" msgstr "Нет" msgid "will be closed before creating a new model. Do you want to continue?" -msgstr "будет закрыт перед созданием новой модели. Продолжить?" +msgstr "будет закрыт перед созданием нового проекта. Продолжить?" # Возможно, имеет смысл убрать тут "стол". Подавляющее большинство проектов – # это размещение моделей и их печать на одном столе, поэтому намёк на работу с @@ -6368,7 +6294,6 @@ msgstr "Вид снизу" msgid "Front View" msgstr "Вид спереди" -# AI Translated msgctxt "Camera View" msgid "Rear" msgstr "Сзади" @@ -6585,7 +6510,6 @@ msgstr "Отображение контура вокруг выбранных м msgid "Preferences" msgstr "Настройки" -# AI Translated msgctxt "Menu" msgid "Edit" msgstr "Правка" @@ -7005,7 +6929,7 @@ msgstr "" "Если накопитель не определяется, попробуйте отформатировать его." msgid "The firmware version of the printer is too low. Please update the firmware and try again." -msgstr "Версия прошивки принтера слишком старая. Пожалуйста, обновите прошивку и попробуйте снова." +msgstr "Слишком старая версия прошивки принтера. Пожалуйста, обновите прошивку и попробуйте снова." msgid "The file already exists, do you want to replace it?" msgstr "Файл уже существует, заменить?" @@ -7213,7 +7137,6 @@ msgstr "Настройки печати" msgid "Safety Options" msgstr "Настройки защиты" -# AI Translated msgid "Hotends" msgstr "Хотэнды" @@ -7250,11 +7173,9 @@ msgstr "Во время паузы смена материала поддерж msgid "Current extruder is busy changing filament." msgstr "В экструдере производится смена материала." -# AI Translated msgid "\"Load\" or \"Unload\" is not supported for external spool while using Filament Track Switch." msgstr "«Загрузка» и «Выгрузка» не поддерживаются для внешней катушки при использовании Filament Track Switch." -# AI Translated msgid "The Filament Track Switch has not been setup. Please setup on printer." msgstr "Filament Track Switch не настроен. Выполните настройку на принтере." @@ -7264,10 +7185,9 @@ msgstr "Слот уже занят." msgid "The selected slot is empty." msgstr "Выбранный слот пуст." -# Так и не нашёл, что это за 2D-режим такой. Выводится в пояснении к -# отключённой функции. +# Так и не нашёл, что это за 2D-режим такой. Выводится в пояснении к отключённой кнопке калибровки. Вероятно, блокировка калибровок печати у H2D при работе с лазерной (и не только) резкой msgid "Printer 2D mode does not support 3D calibration" -msgstr "2D-режим принтера не поддерживает 3D-калибровку" +msgstr "3D-калиброка недоступна в 2D-режиме" msgid "Downloading..." msgstr "Загрузка..." @@ -7294,7 +7214,7 @@ msgid "Chamber temperature cannot be changed in cooling mode while printing." msgstr "Температуру камеры нельзя изменить при печати в режиме «Охлаждение»." msgid "If the chamber temperature exceeds 40℃, the system will automatically switch to heating mode. Please confirm whether to switch." -msgstr "Если температура камеры превысит 40℃, система автоматически переключится в режим нагрева. Подтвердите переключение." +msgstr "Если температура камеры превышает 40℃, система автоматически переключится в режим нагрева. Подтвердите переключение." msgid "Please select an AMS slot before calibration" msgstr "Пожалуйста, выберите слот AMS перед калибровкой" @@ -7436,6 +7356,7 @@ msgctxt "Firmware" msgid "Update" msgstr "Обновление" +# https://wiki.bambulab.com/ru/hms/home msgid "Assistant(HMS)" msgstr "Помощник (HMS)" @@ -7649,7 +7570,7 @@ msgid "Serious warning:" msgstr "Серьёзное предупреждение:" msgid " (Repair)" -msgstr " (Восстановить)" +msgstr "(Восстановить)" msgid " Click here to install it." msgstr " Нажмите здесь, чтобы установить." @@ -7697,33 +7618,27 @@ msgctxt "Layers" msgid "Bottom" msgstr "Снизу" -# AI Translated msgid "Plugin Selection" -msgstr "Выбор плагина" +msgstr "Выбор плагинов" -# AI Translated msgid "" "No plugins capabilities available for this type.\n" "Enable or install some to use." msgstr "" -"Для этого типа нет доступных возможностей плагинов.\n" +"Плагины с требуемым функционалом отсутствуют для этого типа.\n" "Включите или установите их для использования." -# AI Translated msgid "There is stringing-prone filament in the current print job. Enabling nozzle clumping detection now may degrade print quality. Are you sure you want to enable it?" -msgstr "В текущем задании печати есть материал, склонный к образованию волос. Включение обнаружения налипания на сопло сейчас может ухудшить качество печати. Вы уверены, что хотите включить его?" +msgstr "В текущем проекте есть материал, склонный к образованию паутины. Работа проверки налипаний на сопле сейчас может ухудшить качество печати. Вы действительно хотите включить её?" -# AI Translated msgid "Enable Nozzle Clumping Detection" msgstr "Включить обнаружение налипания на сопло" -# AI Translated msgid "When enabled, the printer will automatically capture photos of printed parts and upload them to the cloud. Would you like to enable this option?" -msgstr "Когда включено, принтер будет автоматически делать фотографии печатаемых деталей и загружать их в облако. Хотите включить эту опцию?" +msgstr "Принтер будет автоматически делать фотографии печатаемых деталей и загружать их в облако. Включить эту настройку?" -# AI Translated msgid "Confirm Enable Print Status Snapshot" -msgstr "Подтвердите включение снимков состояния печати" +msgstr "Подтверждение активации снимков состояния печати" msgid "Enable detection of build plate position" msgstr "Определение положения покрытия" @@ -7737,28 +7652,23 @@ msgstr "Обнаружение покрытия стола" msgid "Identifies the type and position of the build plate on the heatbed. Pausing printing if a mismatch is detected." msgstr "Определение типа и положения покрытия стола. В случае обнаружения смещения печать приостанавливается." -# AI Translated msgid "Purifies the chamber air as the print finishes, based on the selected mode." msgstr "Очищает воздух в камере по завершении печати в соответствии с выбранным режимом." -# AI Translated msgid "Purifies the chamber air through internal circulation as each print finishes." msgstr "Очищает воздух в камере за счёт внутренней циркуляции по завершении каждой печати." -# AI Translated msgid "Automatically match the corresponding switch strategy for leak-prone filaments (disable blob detection) and regular filaments (enable blob detection)." -msgstr "Автоматически подбирает соответствующую стратегию переключения для склонных к вытеканию материалов (отключает обнаружение налипаний) и обычных материалов (включает обнаружение налипаний)." +msgstr "Автоматически подбирает соответствующую стратегию для склонных к подтёкам материалов (отключает обнаружение налипаний) и обычных материалов (включает обнаружение налипаний)." -# AI Translated msgid "Detect whether the nozzle is wrapped by filament or other foreign matter." -msgstr "Определяет, обмотано ли сопло материалом или иными посторонними частицами." +msgstr "Определяет налипший на сопло пластик или иные объекты." -# AI Translated msgid "After disabling, nozzle wrapping cannot be detected, which may lead to print failure or nozzle damage." -msgstr "После отключения обмотку сопла нельзя будет обнаружить, что может привести к сбою печати или повреждению сопла." +msgstr "После отключения налипший пластик на сопле нельзя будет обнаружить, что может привести к сбою печати или повреждению сопла." msgid "AI Detections" -msgstr "ИИ-обнаружение" +msgstr "ИИ-мониторинг" msgid "Printer will send assistant message or pause printing if any of the following problem is detected." msgstr "Принтер отправит сообщение помощника или приостановит печать, если обнаружит одну из следующих проблем." @@ -7770,27 +7680,27 @@ msgstr "Контроль печати с помощью ИИ" msgid "Pausing Sensitivity:" msgstr "Чувствительность:" +# Печать воздухом/в воздухе – другой частный случай при перехлёсте прутка или заторе msgid "Spaghetti Detection" -msgstr "Обнаружение «спагетти»" +msgstr "Обнаружение слетевших моделей" msgid "Detect spaghetti failures (scattered lose filament)." -msgstr "Обнаружение дефектов типа «спагетти» (разбросанная нить)." +msgstr "Обнаружение «спагетти» при печати в воздухе." msgid "Purge Chute Pile-Up Detection" -msgstr "Обнаружение скопления в лотке очистки" +msgstr "Обнаружение заполнения лотка прочистки" msgid "Monitor if the waste is piled up in the purge chute." -msgstr "Контроль скопления отходов в лотке очистки." +msgstr "Контроль скопления отходов в лотке прочистки." -# ???протечки, засорения msgid "Nozzle Clumping Detection" msgstr "Обнаружение пластика на сопле" msgid "Check if the nozzle is clumping by filaments or other foreign objects." -msgstr "Определение налипшего на сопле пластика или иных объектов." +msgstr "Определение налипшего на сопло пластика или иных объектов." msgid "Detects air printing caused by nozzle clogging or filament grinding." -msgstr "Определение холостой печати из-за затора или перетирания прутка." +msgstr "Определение холостой печати из-за затора или перехлёста/перетирания прутка." msgid "First Layer Inspection" msgstr "Проверка первого слоя" @@ -7801,9 +7711,8 @@ msgstr "Автовосстановление после смещения сло msgid "Store Sent Files on External Storage" msgstr "Сохранять файлы печати на внешнем накопителе" -# AI Translated msgid "Save the printing files sent from the slicer and other apps on External Storage" -msgstr "Сохранять файлы печати, отправленные из слайсера и других приложений, на внешнем накопителе" +msgstr "Сохранять на внешнем накопителе файлы печати, отправленные из слайсера и других приложений" msgid "Allow Prompt Sound" msgstr "Разрешить звуковые уведомления" @@ -7814,41 +7723,32 @@ msgstr "Обнаружение запутывания прутка" msgid "Check if the nozzle is clumping by filament or other foreign objects." msgstr "Обнаружение скапливания на сопле материала в результате засорения/протечки сопла или других причин." -# AI Translated msgid "Purify Air at Print End" msgstr "Очищать воздух по завершении печати" -# AI Translated msgid "Internal Circulation" msgstr "Внутренняя циркуляция" -# AI Translated msgid "Alignment Detection" msgstr "Обнаружение смещения" -# AI Translated msgid "Pauses printing when build plate misalignment is detected." msgstr "Приостанавливает печать при обнаружении смещения стола." -# AI Translated msgid "Foreign Object Detection" msgstr "Обнаружение посторонних предметов" -# AI Translated msgid "Checks for any objects on the build plate at the start of a print to avoid collisions." msgstr "Проверяет наличие любых предметов на столе в начале печати во избежание столкновений." -# AI Translated msgid "Printed Part Displacement Detection" msgstr "Обнаружение смещения печатаемой детали" -# AI Translated msgid "Monitors the printed part during printing and alerts immediately if it shifts or collapses." -msgstr "Отслеживает печатаемую деталь во время печати и немедленно предупреждает, если она сместилась или обрушилась." +msgstr "Отслеживает положение детали во время печати и немедленно предупреждает, если она сместилась или обрушилась." -# AI Translated msgid "Checks if the nozzle is clumping by filament or other foreign objects." -msgstr "Проверяет, не залипло ли сопло материалом или иными посторонними предметами." +msgstr "Проверяет присутствие пластика или инородных объектов на сопле." msgid "On" msgstr "Вкл" @@ -7862,13 +7762,11 @@ msgstr "Уведомление" msgid "Pause printing" msgstr "Пауза печати" -# AI Translated msgid "Print Status Snapshot" msgstr "Снимок состояния печати" -# AI Translated msgid "Automatically capture and upload print photos, showing defects during printing and the final result for remote viewing." -msgstr "Автоматически делает и загружает фотографии печати, показывая дефекты во время печати и итоговый результат для удалённого просмотра." +msgstr "Автоматически снимает и загружает в облако фотографии печати, показывая дефекты во время печати и итоговый результат для удалённого просмотра." msgctxt "Nozzle Type" msgid "Type" @@ -7883,7 +7781,7 @@ msgid "Flow" msgstr "Расход" msgid "Please change the nozzle settings on the printer." -msgstr "Пожалуйста, измените настройки сопла на принтере." +msgstr "Измените настройки сопла на принтере." msgid "Brass" msgstr "Латунь" @@ -7891,7 +7789,6 @@ msgstr "Латунь" msgid "High flow" msgstr "Высокий расход" -# AI Translated msgid "TPU High flow" msgstr "TPU High flow" @@ -7914,9 +7811,8 @@ msgstr "Общие" msgid "Objects" msgstr "Модели" -# AI Translated msgid "Cycle settings visibility" -msgstr "Переключать видимость настроек" +msgstr "Переключить видимость настроек" msgid "Compare presets" msgstr "Сравнить профили" @@ -8029,11 +7925,9 @@ msgstr "Переключение диаметра" msgid "Configuration incompatible" msgstr "Несовместимый профиль" -# AI Translated msgid "Filament switcher detected. All AMS filaments are now available for both extruders. The slicer will auto-assign for optimal printing." -msgstr "Обнаружен переключатель материалов. Все материалы AMS теперь доступны для обоих экструдеров. Слайсер автоматически распределит их для оптимальной печати." +msgstr "Обнаружен переключатель материалов. Все материалы из AMS теперь доступны для обоих экструдеров. Слайсер автоматически распределит их для оптимальной печати." -# AI Translated msgid "A filament switcher is detected but not calibrated and thus currently unavailable. Please calibrate it on the printer and synchronize before use." msgstr "Обнаружен переключатель материалов, но он не откалиброван и потому сейчас недоступен. Откалибруйте его на принтере и синхронизируйте перед использованием." @@ -8048,12 +7942,13 @@ msgid "" "The currently selected machine preset is inconsistent with the connected printer type.\n" "Are you sure to continue syncing?" msgstr "" -"Текущий выбранный профиль принтера не соответствует типу подключённого принтера.\n" +"Выбранный профиль принтера не соответствует типу подключённого принтера.\n" "Продолжить синхронизацию?" msgid "There are unset nozzle types. Please set the nozzle types of all extruders before synchronizing." msgstr "Типы сопел не заданы. Перед синхронизацией необходимо указать типы всех установленных сопел." +# О сопле/соплах? msgid "Sync extruder infomation" msgstr "Синхронизировать информацию об экструдере" @@ -8067,12 +7962,11 @@ msgid "Click to edit preset" msgstr "Изменить профиль" msgid "Nozzle" -msgstr "Экструдер" +msgstr "Сопло" msgid "Project Filaments" msgstr "Материалы проекта" -# AI Translated msgid "Purge mode" msgstr "Режим прочистки" @@ -8097,9 +7991,10 @@ msgstr "Поиск стола, модели или части..." msgid "Pellets" msgstr "Гранулы" +# Порядок слов сильно зависит от контекста; не могу воспроизвести в интерфейсе. По идее, выводится при bool Sidebar::is_new_project_in_gcode3mf(), но что-либо менять в нарезанном .gcode.3mf вообще нельзя #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." -msgstr "После завершения операции проект %s будет закрыт и создан новый проект." +msgstr "После завершения операции и закрытия текущего проекта %s будет создан новый проект." msgid "There are no compatible filaments, and sync is not performed." msgstr "Синхронизация не выполнена ввиду отсутствия совместимых материалов." @@ -8116,7 +8011,7 @@ msgid "Only filament color information has been synchronized from printer." msgstr "Синхронизирована только информация о цвете материала." msgid "Filament type and color information have been synchronized, but slot information is not included." -msgstr "Информация о типе и цвете филамента синхронизирована, но информация о слотах не включена." +msgstr "Синхронизирована информация о типе и цвете материала, но не о слотах." #, boost-format msgid "Do you want to save changes to \"%1%\"?" @@ -8351,22 +8246,18 @@ msgstr "" "Это действие приведёт к удалению информации о разрезе.\n" "Целостность модели после этого не гарантируется." -# AI Translated msgid "Delete Object" msgstr "Удалить модель" -# AI Translated msgid "Delete All Objects" msgstr "Удалить все модели" -# AI Translated msgid "Reset Project" msgstr "Сбросить проект" msgid "The selected object couldn't be split." msgstr "Невозможно разделить выбранную модель." -# AI Translated msgid "Split to Objects" msgstr "Разделить на модели" @@ -8395,9 +8286,8 @@ msgstr "Выбор нового файла" msgid "File for the replacement wasn't selected" msgstr "Файл для замены не выбран" -# AI Translated msgid "Replace with 3D file" -msgstr "Заменить 3D-файлом" +msgstr "Замена файла модели" # В заголовке окна выбора папки и ошибки "папка не найдена" msgid "Select folder to replace from" @@ -8409,21 +8299,21 @@ msgstr "Расположение для замены не указано" msgid "Replaced with 3D files from directory:\n" msgstr "Заменено файлами из расположения:\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ Пропущен %1%: идентичный файл.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ Пропущен %s: идентичный файл.\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ Пропущен %1%: файл не существует.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ Пропущен %s: файл не существует.\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ Пропущен %1%: не удалось заменить.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ Пропущен %s: не удалось заменить.\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ Заменён %1%.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ Заменён %s.\n" msgid "Replaced volumes" msgstr "Модели заменены" @@ -8446,7 +8336,6 @@ msgstr "Не удалось перезагрузить:" msgid "Error during reload" msgstr "Ошибка во время перезагрузки" -# AI Translated msgid "Reload all" msgstr "Перезагрузить всё" @@ -8493,9 +8382,9 @@ msgid "" "After syncing, software can optimize printing time and filament usage when slicing.\n" "Would you like to sync now?" msgstr "" -"Информация о типе сопла и количестве AMS не синхронизирована с подключённого принтера.\n" -"После синхронизации программа сможет оптимизировать время печати и расход филамента при нарезке.\n" -"Хотите синхронизировать сейчас?" +"Синхронизация информации о типе сопла и количестве AMS подключённого принтера не выполнена.\n" +"После синхронизации программа сможет оптимизировать время печати и расход материала при нарезке.\n" +"Выполнить синхронизацию?" msgid "Sync now" msgstr "Синхронизировать" @@ -8545,10 +8434,10 @@ msgid "INFO:" msgstr "Информация:" msgid "No accelerations provided for calibration. Use default acceleration value " -msgstr "Не заданы ускорения для калибровки. Использовать значение ускорения по умолчанию " +msgstr "Не заданы ускорения для калибровки. Используется значение по умолчанию: " msgid "No speeds provided for calibration. Use default optimal speed " -msgstr "Не заданы скорости для калибровки. Использовать оптимальную скорость по умолчанию " +msgstr "Не заданы скорости для калибровки. Используется значение по умолчанию: " msgid "Import SLA archive" msgstr "Импорт SLA архива" @@ -8660,17 +8549,15 @@ msgstr "Причина: «%1%» не имеет пересечений с дру msgid "Unable to perform boolean operation on model meshes. Only positive parts will be exported." msgstr "Невозможно выполнить булеву операцию над сетками модели. Будут экспортированы только положительные части." -# AI Translated msgid "Flashforge host is not available." msgstr "Хост Flashforge недоступен." # Авторизация принтера Flashforge не удалась. -# AI Translated msgid "Unable to log in to the Flashforge printer." -msgstr "Не удалось войти в принтер Flashforge." +msgstr "Не удалось авторизоваться в панели управления Flashforge." msgid "Is the printer ready? Is the print sheet in place, empty and clean?" -msgstr "Готов ли Принтер? Печатная пластина на месте, пустая и чистая?" +msgstr "Готов ли принтер? Проверьте установку и состояние покрытия стола." msgid "Upload and Print" msgstr "Загрузить и напечатать" @@ -8725,47 +8612,36 @@ msgstr "«Принтер»" msgid "Synchronize AMS Filament Information" msgstr "Синхронизировать материалы в AMS" -# AI Translated msgid "OrcaCloud plugins required by the current preset are not installed:" -msgstr "Плагины OrcaCloud, необходимые для текущего профиля, не установлены:" +msgstr "Для текущего профиля требуется установка плагинов OrcaCloud:" -# AI Translated msgid "Install Plugins" msgstr "Установить плагины" -# AI Translated msgid "Local plugins required by the current preset are missing:" -msgstr "Отсутствуют локальные плагины, необходимые для текущего профиля:" +msgstr "Для текущего профиля требуются локальные плагины:" -# AI Translated msgid "Find on OrcaCloud" msgstr "Найти в OrcaCloud" -# AI Translated msgid "Plugins required by the current preset are not activated:" -msgstr "Плагины, необходимые для текущего профиля, не активированы:" +msgstr "Для текущего профиля требуются неактивные плагины:" -# AI Translated msgid "Activate Now" -msgstr "Активировать сейчас" +msgstr "Активировать" -# AI Translated msgid "The installed plugin does not provide the required capability — it may be outdated:" -msgstr "Установленный плагин не предоставляет требуемую возможность — возможно, он устарел:" +msgstr "В установленном плагине отсутствует нужный функционал (устаревшая версия?):" -# AI Translated msgid "Preparing to install plugins..." msgstr "Подготовка к установке плагинов..." -# AI Translated msgid "Installing plugins" msgstr "Установка плагинов" -# AI Translated msgid "Cancelling — finishing the current plugin..." msgstr "Отмена — завершение текущего плагина..." -# AI Translated #, boost-format msgid "Installing %1%..." msgstr "Установка %1%..." @@ -8809,9 +8685,8 @@ msgstr "Объём: %1% мм³\n" msgid "Triangles: %1%\n" msgstr "Треугольников: %1%\n" -# AI Translated msgid "Use \"Fix Model\" to repair the mesh." -msgstr "Используйте «Исправить модель» для восстановления сетки." +msgstr "Используйте «Восстановить» для исправления сетки. " #, c-format, boost-format msgid "Plate %d: %s is not suggested for use printing filament %s (%s). If you still want to do this print job, please set this filament's bed temperature to a number that is not zero." @@ -9163,7 +9038,7 @@ msgstr "Если включено, вы сможете управлять нес # Запрашивать выбор режима группировки? msgid "Pop up to select filament grouping mode" -msgstr "Всплывающее окно для выбора режима группировки филаментов" +msgstr "Всплывающее окно для выбора режима группировки материалов" msgid "Behaviour" msgstr "Автоматизация" @@ -9286,15 +9161,14 @@ msgstr "Графика" msgid "Smooth normals" msgstr "Сглаживание бликов" -# AI Translated msgid "" "Applies smooth normals to the model.\n" "\n" "Requires manual scene reload to take effect (right-click on 3D view → \"Reload All\")." msgstr "" -"Применяет сглаженные нормали к модели.\n" +"Применять сглаживание нормалей моделей.\n" "\n" -"Для вступления в силу требуется ручная перезагрузка сцены (правый клик в 3D-виде → «Перезагрузить всё»)." +"Для применения изменений требуется ручная перезагрузка сцены (контекстное меню стола → «Перезагрузить всё»)." msgid "Phong shading" msgstr "Затенение по Фонгу" @@ -9311,9 +9185,9 @@ msgstr "Применять фоновое затенение в простран msgid "Shadows" msgstr "Тени" -# AI Translated +# Опять переусложнили техническим нюансом. Изначально тени рисовались только на столе, потом это исправили и решили отметить здесь. msgid "Renders cast shadows on the plate, other objects, and each object onto itself in realistic view." -msgstr "Отображает отбрасываемые тени на столе, других моделях и на самой модели в режиме продвинутой графики." +msgstr "Отрисовывать тени в режиме продвинутой графики." msgid "Anti-aliasing" msgstr "Сглаживание" @@ -9375,17 +9249,28 @@ msgstr "Отображать частоту кадров" msgid "Displays current viewport FPS in the top-right corner." msgstr "Выводить частоту кадров рабочего пространства в правом верхнем углу." -# AI Translated msgid "G-code Preview" -msgstr "Предпросмотр G-code" +msgstr "Просмотр нарезки" -# AI Translated msgid "Dim lower layers" -msgstr "Затемнять нижние слои" +msgstr "Затемнять предыдущие слои" -# AI Translated msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." -msgstr "При перемещении ползунка слоёв в предпросмотре нарезки слои ниже текущего отображаются затемнёнными, так что на полной яркости показан только просматриваемый слой." +msgstr "Затемнять слои, находящиеся ниже текущего. Просматриваемый слой отображается на полной яркости." + +msgid "Dimmed layer brightness" +msgstr "Яркость затемнённых слоёв" + +msgid "%" +msgstr "%" + +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"Процент яркости предыдущих слоёв при включении их затемнения.\n" +"99% — почти полная яркость.\n" +"0% — полное затенение." msgid "Login region" msgstr "Регион входа" @@ -9620,7 +9505,6 @@ msgstr "Несовместимые профили" msgid "My Printer" msgstr "Мой принтер" -# AI Translated msgid "AMS filaments" msgstr "Материалы AMS" @@ -9631,7 +9515,7 @@ msgid "AMS filament" msgstr "Материал AMS" msgid "Right filaments" -msgstr "Филаменты правого экструдера" +msgstr "Материалы правого экструдера" msgid "Click to select filament color" msgstr "Изменить цвет" @@ -9642,7 +9526,6 @@ msgstr "Добавить/удалить профиль" msgid "Edit preset" msgstr "Изменить профиль" -# AI Translated msgid "Change extruder color" msgstr "Изменить цвет экструдера" @@ -9686,10 +9569,9 @@ msgstr "Несовместимы" msgid "The selected preset is null!" msgstr "Выбранный профиль пуст!" -# AI Translated msgctxt "Layer range" msgid "End" -msgstr "до конца" +msgstr "конца" msgid "Customize" msgstr "Настроить" @@ -9799,10 +9681,12 @@ msgstr "Профиль «%1%» уже существует." #, boost-format msgid "Preset \"%1%\" already exists and is incompatible with the current printer." -msgstr "Профиль «%1%» уже существует и несовместим с текущим принтером." +msgstr "" +"Профиль «%1%» уже существует и\n" +"несовместим с текущим принтером." msgid "Please note that saving will overwrite the current preset." -msgstr "Обратите внимание, что при сохранении произойдёт перезапись текущего профиля." +msgstr "Обратите внимание: при сохранении произойдёт\nперезапись текущего профиля." msgid "The name cannot be the same as a preset alias name." msgstr "Имя не должно совпадать с именем предустановленного профиля." @@ -9864,8 +9748,9 @@ msgstr "Отправка задания на печать" msgid "Not satisfied with the grouping of filaments? Regroup and slice ->" msgstr "Не нравится текущая группировка материалов? Нажмите сюда, чтобы изменить и нарезать заново." +# Подсказка msgid "Manually change external spool during printing for multi-color printing" -msgstr "Ручная смена внешней катушки во время печати для многоцветной печати" +msgstr "Смена внешней катушки вручную во время многоцветной печати" msgid "Multi-color with external" msgstr "Многоцветная печать с внешней катушкой" @@ -9873,23 +9758,23 @@ msgstr "Многоцветная печать с внешней катушкой msgid "Your filament grouping method in the sliced file is not optimal." msgstr "Группировка материалов в файле печати не оптимальна." -# AI Translated msgid "To ensure print quality, the drying temperature will be lowered during printing." -msgstr "Для обеспечения качества печати температура сушки будет снижена во время печати." +msgstr "Температура сушки будет снижена на время печати во избежание проблем с качеством." -# AI Translated msgid "Select timelapse storage location" msgstr "Выберите место хранения таймлапсов" +# Ничего тут не выравнивается, банбуки чисто карту снимают msgid "Auto Bed Leveling" -msgstr "Автоматическое выравнивание стола" +msgstr "Измерение кривизны стола" +# "Пропуск" – это пояснение логики работы режима или призыв к действию? msgid "" "This checks the flatness of heatbed. Leveling makes extruded height uniform.\n" "*Automatic mode: Run a leveling check(about 10 seconds). Skip if surface is fine." msgstr "" -"Проверка ровности нагревательного стола. Выравнивание обеспечивает равномерную высоту экструзии.\n" -"*Автоматический режим: выполнить проверку (около 10 секунд). Пропустить, если поверхность в порядке." +"Снятие карты высот стола. Позволяет обеспечить равномерность высоты слоя.\n" +"*Автоматический режим: выполнить проверку (около 10 секунд). Пропуск, если поверхность в порядке." msgid "Flow Dynamics Calibration" msgstr "Калибровка динамики потока" @@ -9898,24 +9783,22 @@ msgid "" "This process determines the dynamic flow values to improve overall print quality.\n" "*Automatic mode: Skip if the filament was calibrated recently." msgstr "" -"Этот процесс определяет значения динамического потока для улучшения общего качества печати.\n" -"*Автоматический режим: пропустить, если филамент был откалиброван недавно." +"Анализ инертности системы подачи материала для улучшения общего качества печати.\n" +"*Автоматический режим: пропуск, если материал был недавно откалиброван." msgid "Nozzle Offset Calibration" -msgstr "Калибровка смещения сопла" +msgstr "Калибровка смещения сопел" msgid "" "Calibrate nozzle offsets to enhance print quality.\n" "*Automatic mode: Check for calibration before printing. Skip if unnecessary." msgstr "" -"Калибровка смещений сопел для улучшения качества печати.\n" -"*Автоматический режим: проверять калибровку перед печатью. Пропустить, если не требуется." +"Калибровка смещения сопел для улучшения качества печати.\n" +"*Автоматический режим: выполнять калибровку перед печатью по необходимости." -# AI Translated msgid "Shared PA Profile" msgstr "Общий профиль PA" -# AI Translated msgid "Nozzles and filaments of the same type share the same PA profile." msgstr "Сопла и материалы одного типа используют общий профиль PA." @@ -9931,50 +9814,40 @@ msgstr "Описание ошибки" msgid "Extra info" msgstr "Доп. информация" -# AI Translated msgid "The Filament Track Switch installed on the printer does not match the slicing file. Please re-slice to avoid print quality issues." -msgstr "Filament Track Switch, установленный на принтере, не соответствует файлу нарезки. Выполните повторную нарезку во избежание проблем с качеством печати." +msgstr "Filament Track Switch в принтере не соответствует файлу нарезки. Выполните повторную нарезку во избежание проблем с качеством печати." -# AI Translated msgid "This print requires a Filament Track Switch. Please install it first." -msgstr "Для этой печати требуется Filament Track Switch. Сначала установите его." +msgstr "Для печати этого файла требуется Filament Track Switch. Сначала установите его." -# AI Translated msgid "The Filament Track Switch has not been setup. Please setup it first." msgstr "Filament Track Switch не настроен. Сначала выполните его настройку." -# AI Translated #, c-format, boost-format msgid "Failed to send nozzle auto-mapping request to printer { code: %d }. Please try to refresh the printer information. If it still does not recover, you can try to rebind the printer and check the network connection." -msgstr "Не удалось отправить запрос на авто-сопоставление сопел принтеру { code: %d }. Попробуйте обновить информацию о принтере. Если это не помогает, попробуйте перепривязать принтер и проверить сетевое соединение." +msgstr "Не удалось отправить принтеру запрос на сопоставление сопел { код: %d }. Попробуйте обновить информацию о принтере. Если это не помогает, попробуйте проверить соединение и перепривязать принтер." -# AI Translated msgid "The printer is calculating nozzle mapping." -msgstr "Принтер вычисляет сопоставление сопел." +msgstr "Принтер выполняет сопоставление сопел." -# AI Translated msgid "Please wait a moment..." msgstr "Пожалуйста, подождите..." -# AI Translated #, c-format, boost-format msgid "Failed to receive nozzle auto-mapping table from printer { msg: %s }. Please refresh the printer information." -msgstr "Не удалось получить таблицу авто-сопоставления сопел от принтера { msg: %s }. Обновите информацию о принтере." +msgstr "Не удалось получить от принтера таблицу сопоставления сопел { ответ: %s }. Обновите информацию о принтере." -# AI Translated #, c-format, boost-format msgid "The printer failed to build the nozzle auto-mapping table { code: %d }. Please refresh nozzle information." -msgstr "Принтеру не удалось построить таблицу авто-сопоставления сопел { code: %d }. Обновите информацию о соплах." +msgstr "Принтеру не удалось составить таблицу сопоставления сопел { код: %d }. Обновите информацию о соплах." -# AI Translated #, c-format, boost-format msgid "The current nozzle mapping may produce an extra %0.2f g of waste." -msgstr "Текущее сопоставление сопел может привести к дополнительным %0.2f г отходов." +msgstr "Текущее сопоставление сопел может привести к дополнительным затратам %0.2fг материала." -# AI Translated #, c-format, boost-format msgid "Recommended filament arrangement saves %s->" -msgstr "Рекомендуемое расположение материалов экономит %s->" +msgstr "Рекомендуемое расположение материалов экономит %s→" #, c-format, boost-format msgid "Filament %s does not match the filament in AMS slot %s. Please update the printer firmware to support AMS slot assignment." @@ -9993,18 +9866,17 @@ msgstr "При включении режима вазы принтеры с ки msgid "The current printer does not support timelapse in Traditional Mode when printing By-Object." msgstr "Принтер не поддерживает таймлапс в режиме по умолчанию при печати моделей по очереди." -# AI Translated msgid "I have checked the installed nozzle and want to print anyway." -msgstr "Я проверил установленное сопло и всё равно хочу печатать." +msgstr "Установленное сопло проверено, продолжить в любом случае." msgid "Errors" msgstr "Ошибок" msgid "More than one filament types have been mapped to the same external spool, which may cause printing issues. The printer won't pause during printing." -msgstr "Несколько типов филамента назначены на одну внешнюю катушку, что может вызвать проблемы при печати. Принтер не будет приостанавливаться во время печати." +msgstr "На одну внешнюю катушку назначено несколько типов материала, что может вызвать проблемы при печати. Принтер не будет приостанавливаться во время печати." msgid "The filament type setting of external spool is different from the filament in the slicing file." -msgstr "Тип филамента на внешней катушке отличается от филамента в файле нарезки." +msgstr "Тип материала на внешней катушке отличается от материала в файле нарезки." msgid "The printer type selected when generating G-code is not consistent with the currently selected printer. It is recommended that you use the same printer type for slicing." msgstr "Выбранный профиль принтера в настройках слайсера не совпадает с фактическим принтером. Для нарезки рекомендуется использовать тот же профиль принтера." @@ -10022,48 +9894,40 @@ msgid "Please click the confirm button if you still want to proceed with printin msgstr "Нажмите кнопку подтверждения, если всё ещё хотите продолжить печать." msgid "This checks the flatness of heatbed. Leveling makes extruded height uniform." -msgstr "Проверка ровности нагревательного стола. Выравнивание обеспечивает равномерную высоту экструзии." +msgstr "Проверка кривизны стола. Обеспечивает равномерную высоту слоя." msgid "This process determines the dynamic flow values to improve overall print quality." -msgstr "Этот процесс определяет значения динамического потока для улучшения общего качества печати." +msgstr "Определение коэффициента динамического потока для улучшения общего качества печати." msgid "Internal" msgstr "Внутренние" -# AI Translated +# Подставляется storage_name #, c-format, boost-format msgid "%s space less than 20MB. Timelapse may not save properly. You can turn it off or" -msgstr "%s: свободного места меньше 20 МБ. Таймлапс может сохраниться некорректно. Вы можете отключить его или" +msgstr "%s: свободного места меньше 20 МБ. Таймлапс может сохраниться некорректно. Рекомендуется отключить его или " -# AI Translated msgid "Clean up files" -msgstr "Очистить файлы" +msgstr "очистить файлы" -# AI Translated msgid "Low internal storage. This timelapse will overwrite the oldest video files." msgstr "Мало внутренней памяти. Этот таймлапс перезапишет самые старые видеофайлы." -# AI Translated msgid "Low external storage. This timelapse will overwrite the oldest video files." msgstr "Мало внешней памяти. Этот таймлапс перезапишет самые старые видеофайлы." -# AI Translated msgid "Insufficient external storage for time-lapse photography. Connect to computer to delete files, or use a larger memory card." msgstr "Недостаточно внешней памяти для съёмки таймлапса. Подключитесь к компьютеру для удаления файлов или используйте карту памяти большего объёма." -# AI Translated msgid "Storage Space Not Enough" msgstr "Недостаточно места в хранилище" -# AI Translated msgid "Confirm & Print" -msgstr "Подтвердить и печатать" +msgstr "Подтвердить и продолжить" -# AI Translated msgid "Cancel Timelapse & Print" -msgstr "Отменить таймлапс и печатать" +msgstr "Отключить таймлапс и продолжить" -# AI Translated msgid "Clean Up" msgstr "Очистить" @@ -10081,47 +9945,38 @@ msgstr "Будет затрачено на %d г материала и на %d msgid "nozzle" msgstr "сопло" -# AI Translated #, c-format, boost-format msgid "Refreshing information of hotends(%d/%d)." msgstr "Обновление информации о хотэндах (%d/%d)." -# AI Translated msgid "There are not enough available hotends currently." -msgstr "Сейчас недостаточно доступных хотэндов." +msgstr "Доступных хотэндов сейчас недостаточно." -# AI Translated msgid "Please complete the hotend rack setup and try again." msgstr "Завершите настройку стойки хотэндов и повторите попытку." -# AI Translated msgid "Please refresh the nozzle information and try again." msgstr "Обновите информацию о соплах и повторите попытку." -# AI Translated msgid "Please re-slice to avoid filament waste." -msgstr "Выполните повторную нарезку во избежание расхода материала впустую." +msgstr "Выполните повторную нарезку во избежание излишнего расхода материала." -# AI Translated msgid "The reported hotend information may be unreliable." msgstr "Переданная информация о хотэнде может быть недостоверной." -# AI Translated #, c-format, boost-format msgid "The printer has no nozzle matching the slicing file (%s)." msgstr "На принтере нет сопла, соответствующего файлу нарезки (%s)." -# AI Translated msgid "Please install a matching nozzle in the hotend rack, or set the corresponding printer preset while slicing." msgstr "Установите подходящее сопло в стойку хотэндов или задайте соответствующий профиль принтера при нарезке." -# AI Translated msgid "The toolhead and hotend rack are full. Please remove at least one hotend before printing." -msgstr "Печатающая голова и стойка хотэндов заполнены. Перед печатью снимите хотя бы один хотэнд." +msgstr "Все места в печатающей голове и стойке хотэндов заняты. Перед печатью снимите хотя бы один хотэнд." #, c-format, boost-format msgid "The nozzle flow setting of %s(%s) doesn't match with the slicing file(%s). Please make sure the nozzle installed matches with settings in printer, then set the corresponding printer preset while slicing." -msgstr "Настройка потока сопла %s(%s) не совпадает с файлом нарезки (%s). Убедитесь, что настройки принтера соответствуют установленному соплу, затем выберите соответствующий профиль принтера при нарезке." +msgstr "Настройка расхода сопла %s(%s) не совпадает с файлом нарезки (%s). Убедитесь, что настройки принтера соответствуют установленному соплу, затем выберите соответствующий профиль принтера при нарезке." msgid "Tips: If you changed your nozzle of your printer lately, please go to 'Device -> Printer parts' to change your nozzle setting." msgstr "Совет: после замены сопла в принтере необходимо обновить его настройки («Принтер» → «Части принтера»)." @@ -10139,28 +9994,23 @@ msgstr "обоих экструдерах" #, c-format, boost-format msgid "The hardness of current material (%s) exceeds the hardness of %s(%s). Please verify the nozzle or material settings and try again." -msgstr "Требования к твёрдости у выбранного материала (%s) превышают возможности %s(%s). Проверьте настройки профиля принтера или материала и попробуйте ещё раз." +msgstr "Требования к твёрдости у выбранного материала (%s) превышают возможности %s (%s). Проверьте настройки профиля принтера или материала и попробуйте ещё раз." -# AI Translated msgid "Your current firmware version cannot start this print job. Please update to the latest version and try again." -msgstr "Текущая версия прошивки не может запустить это задание печати. Обновите до последней версии и повторите попытку." +msgstr "Текущая версия прошивки не может обработать этот файл. Обновитесь до последней версии и повторите попытку." -# AI Translated #, c-format, boost-format msgid "The hardness of current material (%s) exceeds the hardness of %s(%s). It may cause nozzle wear, leading to material leakage and unstable flow. Please exercise caution when using it." -msgstr "Твёрдость текущего материала (%s) превышает твёрдость %s(%s). Это может вызвать износ сопла, приводящий к утечке материала и нестабильному потоку. Соблюдайте осторожность при использовании." +msgstr "Требования к твёрдости у выбранного материала (%s) превышают возможности %s (%s). Это может привести к износу сопла и утечкам материала/нестабильному потоку в будущем. Используйте материал с осторожностью." -# AI Translated msgid "Some filaments may switch between extruders during printing. Manual K-value calibration cannot be applied throughout the entire print, which may affect print quality. Enabling Flow Dynamics Calibration is recommended." -msgstr "Некоторые материалы могут переключаться между экструдерами во время печати. Ручную калибровку K-value нельзя применить на протяжении всей печати, что может повлиять на её качество. Рекомендуется включить калибровку динамики потока (Flow Dynamics Calibration)." +msgstr "Некоторые материалы могут переключаться между экструдерами во время печати. Ручная калибровка K-фактора не применима для всей печати, что может повлиять на её качество. Рекомендуется включить калибровку динамики потока (Flow Dynamics Calibration)." -# AI Translated msgid "There is stringing-prone filament in this file. For best print quality, we recommend switching nozzle clumping detection to Auto mode." -msgstr "В этом файле есть материал, склонный к образованию волос. Для наилучшего качества печати рекомендуем переключить обнаружение налипания на сопло в режим «Авто»." +msgstr "В текущем проекте есть материал, склонный к образованию паутины. Во избежание проблем с качеством рекомендуется включить автоматический режим обнаружения налипаний на сопло." -# AI Translated msgid "If 'Dynamic Flow Calibration' is set to Auto/On, the system will use the manual calibration value or the default value and skip the flow calibration process. You can perform a manual flow calibration for TPU filament on the 'Calibration' page." -msgstr "Если «Динамическая калибровка потока» установлена в «Авто/Вкл», система будет использовать значение ручной калибровки или значение по умолчанию и пропустит процесс калибровки потока. Вы можете выполнить ручную калибровку потока для материала TPU на странице «Калибровка»." +msgstr "Если «Калибровка динамики потока» установлена в «Авто/Вкл», система будет использовать значение ручной калибровки или значение по умолчанию и пропустит процесс калибровки. Ручную калибровку TPU можно выполнить на странице «Калибровка»." #, c-format, boost-format msgid "[ %s ] requires printing in a high-temperature environment. Please close the door." @@ -10231,16 +10081,16 @@ msgid "The printer is executing instructions. Please restart printing after it e msgstr "Принтер выполняет команды. Перезапустите печать после их завершения." msgid "AMS is setting up. Please try again later." -msgstr "AMS настраивается. Пожалуйста, попробуйте позже." +msgstr "AMS настраивается. Попробуйте позднее." msgid "Not all filaments used in slicing are mapped to the printer. Please check the mapping of filaments." -msgstr "Не все филаменты, использованные при нарезке, назначены на принтер. Проверьте назначение филаментов." +msgstr "Не все материалы, использованные при нарезке, сопоставлены с принтером. Проверьте назначение материалов." msgid "Please do not mix-use the Ext with AMS." -msgstr "Пожалуйста, не используйте одновременно внешнюю катушку и AMS." +msgstr "Не стоит использовать AMS и внешние катушки совместно." msgid "Invalid nozzle information, please refresh or manually set nozzle information." -msgstr "Недопустимая информация о сопле. Обновите или вручную задайте информацию о сопле." +msgstr "Недопустимая информация о сопле. Обновите или задайте её вручную." msgid "Storage needs to be inserted before printing via LAN." msgstr "Перед печатью по локальной сети необходимо вставить хранилище данных." @@ -10267,24 +10117,21 @@ msgid "TPU 90A/TPU 85A is too soft and does not support automatic Flow Dynamics msgstr "TPU 85A/90A слишком мягкий для автоматической калибровки." msgid "Set dynamic flow calibration to 'OFF' to enable custom dynamic flow value." -msgstr "Установите калибровку динамического потока в «ВЫКЛ.», чтобы задать пользовательское значение динамического потока." +msgstr "Отключите калибровку динамики потока, чтобы задать пользовательское значение." msgid "This printer does not support printing all plates." msgstr "Принтер не поддерживает печать нескольких столов." -# AI Translated #, c-format, boost-format msgid "The current firmware supports a maximum of %s materials. You can either reduce the number of materials to %s 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." -msgstr "Текущая прошивка поддерживает не более %s материалов. Вы можете либо уменьшить количество материалов до %s или менее на странице подготовки, либо попробовать обновить прошивку. Если после обновления ограничение сохраняется, дождитесь поддержки в последующих версиях прошивки." +msgstr "Текущая прошивка поддерживает не более %s материалов. Попробуйте обновить прошивку или уменьшить количество материалов до %s (или менее) на странице подготовки. Если после обновления ограничение сохраняется, ожидайте добавления поддержки в последующих версиях." msgid "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." msgstr "Тип материала на внешней катушке неизвестен или не соответствует материалу в файле печати. Убедитесь, что установлена внешняя катушка с требуемым материалом." -# AI Translated msgid "TPU 90A/TPU 85A are too soft. It is recommended to perform manual flow calibration on the 'Calibration' page. If 'Dynamic Flow Calibration' is set to auto/on, the system will use the previous calibration value and skip the flow calibration process." -msgstr "TPU 90A/TPU 85A слишком мягкие. Рекомендуется выполнить ручную калибровку потока на странице «Калибровка». Если «Динамическая калибровка потока» установлена в «авто/вкл», система будет использовать предыдущее значение калибровки и пропустит процесс калибровки потока." +msgstr "TPU 90A/TPU 85A слишком мягкий. Рекомендуется выполнить ручную калибровку потока на странице «Калибровка». Если «Калибровка динамики потока» установлена в «Авто/Вкл», система будет использовать предыдущие результаты и пропустит процесс калибровки." -# AI Translated msgid "The filament in the AMS may be insufficient for this print. Please refill or replace it." msgstr "Материала в AMS может быть недостаточно для этой печати. Пополните или замените его." @@ -10456,7 +10303,6 @@ msgstr "Удалить этот профиль" msgid "Search in preset" msgstr "Поиск в профиле" -# AI Translated msgid "Synchronization of different extruder drives or nozzle volume types is not supported." msgstr "Синхронизация разных приводов экструдера или типов объёма сопла не поддерживается." @@ -10466,9 +10312,8 @@ msgstr "Перенести изменения в настройки другог msgid "Click to reset all settings to the last saved preset." msgstr "Сбросить все изменения" -# AI Translated msgid "Prime tower is required for nozzle changing. There may be flaws on the model without prime tower. Are you sure you want to disable prime tower?" -msgstr "Для смены сопла требуется черновая башня. Без черновой башни на модели могут появиться дефекты. Вы уверены, что хотите отключить черновую башню?" +msgstr "Для смены сопла требуется черновая башня. Без черновой башни на модели могут появиться дефекты. Вы действительно хотите отключить черновую башню?" msgid "A prime tower is required for smooth timelapse mode. There may be flaws on the model without a prime tower. Are you sure you want to disable the prime tower?" msgstr "Для сглаженного таймлапса требуется черновая башня, без неё на модели могут возникнуть дефекты. Вы действительно хотите отключить черновую башню?" @@ -10484,7 +10329,7 @@ msgid "A prime tower is required for clumping detection. There may be flaws on t msgstr "Для обнаружения налипаний на сопле требуется черновая башня, без неё на модели могут образоваться дефекты. Включить обнаружение налипаний?" msgid "Enabling both precise Z height and the prime tower may cause slicing errors. Do you still want to enable precise Z height?" -msgstr "Включение «Точной высоты по Z» вместе с черновой башней может привести к ошибкам нарезки. Продолжить?" +msgstr "Включение «Точной высоты по Z» совместно с черновой башней может привести к ошибкам нарезки. Продолжить?" msgid "A prime tower is required for smooth timelapse mode. There may be flaws on the model without prime tower. Do you want to enable the prime tower?" msgstr "Для сглаженного таймлапса требуется черновая башня, без неё на модели могут возникнуть дефекты. Включить черновую башню?" @@ -10696,6 +10541,7 @@ msgstr "Материал поддержки" msgid "Support ironing" msgstr "Разглаживание поддержки" +# Технически точной локализацией было бы "фрактальные поддержки", т.к. сама структура представляет собой фрактал, а не дерево. Но у всех уже на слуху, так что менять нет смысла. Хотя звучало бы прям круто :3 msgid "Tree supports" msgstr "Древовидная поддержка" @@ -10722,13 +10568,12 @@ msgstr "G-код при смене типа линии" msgid "Post-processing Scripts" msgstr "Скрипты постобработки" -# AI Translated msgid "Slicing Pipeline Plugin" msgstr "Плагин конвейера нарезки" -# AI Translated +# В данном контексте можно, наверное, "конфигурация", т.к. тут именно управление набором плагинов, а не просто их настройками msgid "Plugin Configuration" -msgstr "Настройка плагина" +msgstr "Настройка плагинов" msgid "Notes" msgstr "Заметки" @@ -10885,7 +10730,7 @@ msgid "Multi Filament" msgstr "Печать несколькими материалами" msgid "Tool change parameters with single extruder MM printers" -msgstr "Смена материала при комбинированной печати одним экструдером" +msgstr "Смена материала при печати одним экструдером" msgid "Set" msgstr "Выбор" @@ -11050,10 +10895,8 @@ msgstr "" msgid "Firmware Retraction" msgstr "Откат из прошивки" -# Изменения в настройках ... будут сброшены при переключении на принтер с -# другим типом или количеством сопел. msgid "Switching to a printer with different extruder types or numbers will discard or reset changes to extruder or multi-nozzle-related parameters." -msgstr "Переключение на принтер с другим типом или количеством экструдеров приведёт к сбросу или удалению изменений параметров, связанных с экструдерами и многосопельной конфигурацией." +msgstr "Изменения в настройках экструдера и параметрах сопел не будут перенесены в профиль принтера с другим типом или количеством сопел." msgid "Use Modified Value" msgstr "Использовать изменённое значение" @@ -11068,7 +10911,7 @@ msgstr "" "• профили материалов: %d\n" "• профили настроек: %d\n" "\n" -"Эти профили будут удалены при удалении принтера." +"Эти профили будут удалены вместе с принтером." # ??? Профили, наследуемые от других профилей, не могут быть удалены. msgid "Presets inherited by other presets cannot be deleted!" @@ -11096,8 +10939,8 @@ msgid "" "If the preset corresponds to a filament currently in use on your printer, please reset the filament information for that slot." msgstr "" "Вы действительно хотите удалить выбранный профиль? \n" -"Если материал из этого профиля сейчас используется в вашем принтере,\n" -"необходимо сбросить информацию о материале для этого слота." +"Если вы используете его в принтере, сбросьте информацию\n" +"о нём у соответствующего слота." #, boost-format msgid "Are you sure you want to %1% the selected preset?" @@ -11154,7 +10997,6 @@ msgstr "Продолжить" msgid "Don't warn again for this preset" msgstr "Больше не спрашивать для этого профиля" -# AI Translated #, c-format, boost-format msgid "%s: %s" msgstr "%s: %s" @@ -11307,16 +11149,15 @@ msgstr "" msgid "Extruder count" msgstr "Количество экструдеров" +# Какая-то древняя строка. Ранее – "Характеристики принтера", сейчас используется ещё и в конфигурации плагинов в профиле материала (вкладка "Расширенные") msgid "Capabilities" -msgstr "Характеристики принтера" +msgstr "Возможности" -# AI Translated msgid "Left: " -msgstr "Слева: " +msgstr "Левый: " -# AI Translated msgid "Right: " -msgstr "Справа: " +msgstr "Правый: " msgid "Show all presets (including incompatible)" msgstr "Показать все профили (включая несовместимые)" @@ -11469,7 +11310,7 @@ msgid "Color match" msgstr "Подбор цвета" msgid "Approximate color matching." -msgstr "Приблизительный подбор по цвету ваших прутков." +msgstr "Приблизительный подбор по цвету ваших материалов." msgid "Append" msgstr "Добавить" @@ -11491,7 +11332,7 @@ msgid "" msgstr "выбор цветов можно изменить вручную." msgid "—> " -msgstr "—> " +msgstr "→ " msgid "" "Synchronizing AMS filaments will discard your modified but unsaved filament presets.\n" @@ -11515,7 +11356,7 @@ msgid "Plate" msgstr "Стол" msgid "The connected printer does not match the currently selected printer. Please change the selected printer." -msgstr "Подключённый принтер не соответствует текущему выбранному принтеру. Пожалуйста, измените выбранный принтер." +msgstr "Подключённый принтер не соответствует текущему выбранному. Пожалуйста, измените выбранный принтер." msgid "Mapping" msgstr "Назначение" @@ -11524,7 +11365,7 @@ msgid "Overwriting" msgstr "Переназначение" msgid "Reset all filament mapping" -msgstr "Сбросить все назначения филаментов" +msgstr "Сбросить назначения всех материалов" msgid "(Recommended filament)" msgstr "(рекомендуется)" @@ -11536,8 +11377,8 @@ msgid "" "Check heatbed flatness. Leveling makes extruded height uniform.\n" "*Automatic mode: Level first (about 10 seconds). Skip if surface is fine." msgstr "" -"Проверка ровности стола. Выравнивание обеспечивает равномерную высоту экструзии.\n" -"*Автоматический режим: сначала выполнить выравнивание (около 10 секунд). Пропустить, если поверхность в порядке." +"Снятие карты высот стола. Обеспечивает равномерную высоту слоя.\n" +"*Автоматический режим: выполнить проверку (около 10 секунд). Пропуск, если поверхность в порядке." msgid "" "Calibrate nozzle offsets to enhance print quality.\n" @@ -11553,43 +11394,43 @@ msgid "Tip" msgstr "Совет" msgid "Only synchronize filament type and color, not including AMS slot information." -msgstr "Синхронизировать только тип и цвет филамента, без информации о слотах AMS." +msgstr "Синхронизировать только тип и цвет материала, без информации о слотах AMS." msgid "Replace the project filaments list sequentially based on printer filaments. And unused printer filaments will be automatically added to the end of the list." -msgstr "Заменить список филаментов проекта последовательно на основе филаментов принтера. Неиспользуемые филаменты принтера будут автоматически добавлены в конец списка." +msgstr "Заменить список материалов проекта последовательно на основе материалов принтера. Свободные материалы будут автоматически добавлены в конец списка." msgid "Add unused AMS filaments to filaments list." msgstr "Добавить незадействованные материалы из AMS в список" msgid "Automatically merge the same colors in the model after mapping." -msgstr "Автоматически объединять одинаковые цвета в модели после назначения." +msgstr "Автоматически объединять одинаковые цвета в модели после их назначения." msgid "After being synced, this action cannot be undone." msgstr "После синхронизации это действие нельзя отменить." msgid "After being synced, the project's filament presets and colors will be replaced with the mapped filament types and colors. This action cannot be undone." -msgstr "После синхронизации профили филаментов и цвета проекта будут заменены назначенными типами и цветами филаментов. Это действие нельзя отменить." +msgstr "После синхронизации профили и цвета материалов проекта будут заменены назначенными им типами и цветами материалов. Это действие нельзя отменить." msgid "Are you sure to synchronize the filaments?" -msgstr "Вы уверены, что хотите синхронизировать филаменты?" +msgstr "Вы уверены, что хотите синхронизировать материалы?" msgid "Synchronize now" msgstr "Синхронизировать" msgid "Synchronize Filament Information" -msgstr "Синхронизация информации о филаменте" +msgstr "Синхронизация информации о материале" msgid "Add unused filaments to filaments list." -msgstr "Добавить неиспользуемые филаменты в список." +msgstr "Добавить неиспользуемые материалы в список." msgid "Only synchronize filament type and color, not including slot information." -msgstr "Синхронизировать только тип и цвет филамента, без информации о слотах." +msgstr "Синхронизировать только тип и цвет материала, без информации о слотах." msgid "Ext spool" msgstr "Внешняя катушка" msgid "Please check whether the nozzle type of the device is the same as the preset nozzle type." -msgstr "Проверьте, совпадает ли тип сопла устройства с типом сопла в профиле." +msgstr "Проверьте, совпадает ли тип сопла в принтере с типом сопла в профиле." msgid "Storage is not available or is in read-only mode." msgstr "Хранилище недоступно или защищено от записи." @@ -11602,7 +11443,7 @@ msgid "Timelapse is not supported because Print sequence is set to \"By object\" msgstr "Таймлапс не поддерживается, поскольку для последовательности печати установлено значение «Печать по очереди»." msgid "You selected external and AMS filament at the same time in an extruder, you will need manually change external filament." -msgstr "Вы выбрали одновременно внешний филамент и филамент из AMS в одном экструдере. Вам нужно будет вручную менять внешний филамент." +msgstr "Для одного экструдера одновременно выбраны внешняя катушка и катушка из AMS. Потребуется ручная смена прутка." msgid "Successfully synchronized nozzle information." msgstr "Информация о сопле успешно синхронизирована." @@ -11610,9 +11451,8 @@ msgstr "Информация о сопле успешно синхронизир msgid "Successfully synchronized nozzle and AMS number information." msgstr "Информация о сопле и количестве AMS успешно синхронизирована." -# AI Translated msgid "Do you want to continue to sync filaments?" -msgstr "Хотите продолжить синхронизацию материалов?" +msgstr "Продолжить синхронизацию материалов?" msgid "Successfully synchronized filament color from printer." msgstr "Цвет материала успешно синхронизирован с принтером." @@ -11638,7 +11478,7 @@ msgstr "" #, boost-format msgid "For constant flow rate, hold %1% while dragging." -msgstr "Для постоянного объёмного расхода удерживайте нажатой клавишу %1% при перетаскивании." +msgstr "Для выравнивания значений расхода удерживайте клавишу %1% при перетаскивании." msgid "ms" msgstr "мс" @@ -11691,7 +11531,7 @@ msgid "BambuSource has not correctly been registered for media playing! Press Ye msgstr "Компонент BambuSource неправильно зарегистрирован для воспроизведения медиафайлов! Нажмите «Да», чтобы повторно зарегистрировать его" msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Отсутствует компонент BambuSource для воспроизведения медиа! Пожалуйста, переустановите OrcaSlicer или обратитесь за помощью к сообществу." +msgstr "Отсутствует компонент BambuSource для воспроизведения медиа. Переустановите OrcaSlicer или обратитесь за помощью к сообществу." msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." msgstr "При использовании компонентов BambuSource из другого инсталлятора, воспроизведение видео может работать некорректно! Нажмите «Да», чтобы исправить это." @@ -11699,7 +11539,6 @@ msgstr "При использовании компонентов BambuSource и msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" msgstr "В вашей системе отсутствуют кодеки H.264 для GStreamer, которые необходимы для воспроизведения видео (попробуйте установить пакеты gstreamer1.0-plugins-bad или gstreamer1.0-libav, а затем перезапустить Orca Slicer)." -# AI Translated msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "Облачный агент недоступен. Перезапустите OrcaSlicer и повторите попытку." @@ -11715,9 +11554,8 @@ msgstr "Войти" msgid "Login failed. Please try again." msgstr "Ошибка входа. Попробуйте ещё раз." -# AI Translated msgid "parse json failed" -msgstr "не удалось разобрать JSON" +msgstr "не удалось обработать JSON" msgid "[Action Required] " msgstr "[Требуется действие] " @@ -11909,12 +11747,10 @@ msgctxt "Keyboard Shortcut" msgid "Space" msgstr "Пробел" -# AI Translated msgid "Open actions speed dial" -msgstr "Открыть панель быстрых действий" +msgstr "Открыть строку быстрых действий" # Plater – это название библиотеки. Используется в меню горячих клавиш в качестве заголовка сочетаний клавиш, которые работают внутри пространства Plater. Как минимум на Windows не отображается. -# AI Translated msgid "Plater" msgstr "Рабочая область" @@ -11993,17 +11829,15 @@ msgstr "Информация об изменениях в версии %s:" msgid "Network plug-in update" msgstr "Обновление сетевого плагина" -# AI Translated msgid "Click OK to update the Network plug-in now. If a file is in use, the update will be applied the next time Orca Slicer launches." -msgstr "Нажмите OK, чтобы обновить сетевой плагин сейчас. Если файл используется, обновление будет применено при следующем запуске Orca Slicer." +msgstr "Нажмите OK для обновления сетевого плагина. Если файл занят, обновление будет завершено при следующем запуске Orca Slicer." -# AI Translated msgid "A new Network plug-in is available. Do you want to install it?" -msgstr "Доступен новый сетевой плагин. Хотите установить его?" +msgstr "Доступна новая версия сетевого плагина. Выполнить установку?" #, c-format, boost-format msgid "A new Network plug-in (%s) is available. Do you want to install it?" -msgstr "Доступен новый сетевой плагин (%s). Хотите установить?" +msgstr "Доступна новая версия сетевого плагина: %s. Выполнить установку?" msgid "New version of Orca Slicer" msgstr "Доступна новая версия Orca Slicer" @@ -12058,9 +11892,8 @@ msgstr "Имя принтера" msgid "Where to find your printer's IP and Access Code?" msgstr "Где найти IP-адрес и код доступа к вашему принтеру?" -# AI Translated msgid "How to trouble shooting" -msgstr "Как устранить неполадки" +msgstr "Помощь в устранении неполадок" msgid "Connect" msgstr "Подключить" @@ -12121,13 +11954,13 @@ msgid "Laser 40W" msgstr "40 Вт лазер" msgid "Cutting Module" -msgstr "Модуль обрезки" +msgstr "Модуль резки" # система пожаротушения? msgid "Auto Fire Extinguishing System" msgstr "Автоматическая система пожаротушения" -# AI Translated +# По сути, локализовывается как "Переключатель AMS". Но сами бамбуки используют кривой машинный перевод в русскоязычной документации, и там переводится от случая к случаю. Поэтому имеет полный смысл оставить брендированное название. msgid "Filament Track Switch" msgstr "Filament Track Switch" @@ -12149,7 +11982,6 @@ msgstr "Сбой обновления" msgid "Update successful" msgstr "Обновление успешно завершено" -# AI Translated msgid "Hotends on Rack" msgstr "Хотэнды на стойке" @@ -12247,9 +12079,8 @@ msgstr "" "Input Shaping поддерживается только в Marlin 2.1.2 и новее.\n" "Обновите прошивку и установите тип G-кода на «Marlin 2»." -# AI Translated msgid "Input shaping is only supported by Klipper, RepRapFirmware and Marlin 2." -msgstr "Input shaping поддерживается только Klipper, RepRapFirmware и Marlin 2." +msgstr "Input shaping поддерживается только в Klipper, RepRapFirmware и Marlin 2." msgid "Grouping error: " msgstr "Ошибка группировки: " @@ -12258,9 +12089,8 @@ msgstr "Ошибка группировки: " msgid " can not be placed in the " msgstr " нельзя заправить в " -# AI Translated msgid "Group error in manual mode. Please check nozzle count or regroup." -msgstr "Ошибка группировки в ручном режиме. Проверьте количество сопел или перегруппируйте." +msgstr "Ошибка группировки в ручном режиме. Проверьте количество сопел или измените группировку." msgid "Internal Bridge" msgstr "Внутренний мост" @@ -12408,10 +12238,10 @@ msgid "Clumping detection is not supported when \"by object\" sequence is enable msgstr "Обнаружение налипаний не поддерживается при печати моделей по очереди." msgid "Enabling both precise Z height and the prime tower may cause slicing errors." -msgstr "Одновременное включение точной высоты Z и башни очистки может вызвать ошибки нарезки." +msgstr "Совместное использование точной высоты Z и черновой башни может вызвать ошибки нарезки." msgid "A prime tower is required for clumping detection; otherwise, there may be flaws on the model." -msgstr "Для обнаружения налипаний требуется башня очистки; в противном случае на модели могут быть дефекты." +msgstr "Для обнаружения налипаний требуется черновая башня; в противном случае на модели могут возникнуть дефекты." msgid "Please select \"By object\" print sequence to print multiple objects in spiral vase mode." msgstr "Выберите последовательность печати «По очереди» для поддержки печати несколько моделей в режиме вазы." @@ -12510,10 +12340,10 @@ msgid "Organic support branch diameter must not be smaller than support tree tip msgstr "Диаметр ветвей органической поддержки не может быть меньше диаметра их кончиков." msgid "The Hollow base pattern is not supported by this support type; Rectilinear will be used instead." -msgstr "Шаблон полого основания не поддерживается этим типом поддержки; вместо него будет использоваться прямолинейный." +msgstr "Шаблон «Полость» не поддерживается этим типом поддержек и будет заменён на «Зигзаг»." msgid "Support enforcers are used but support is not enabled. Please enable support." -msgstr "Используется принудительная поддержка, но её генерация не включена. Пожалуйста, включите генерацию поддержки в настройках слайсера." +msgstr "Используется принудительная поддержка, но её генерация не включена. Включите генерацию поддержек в настройках слайсера." msgid "Layer height cannot exceed nozzle diameter." msgstr "Высота слоя не может быть больше диаметра сопла." @@ -12521,24 +12351,21 @@ msgstr "Высота слоя не может быть больше диамет msgid "Bridge line width must not exceed nozzle diameter" msgstr "Ширина линии моста не может превышать диаметр сопла" -# AI Translated msgid "\"G92 E0\" was found in before_layer_change_gcode, but the G or E are not uppercase. Please change them to the exact uppercase \"G92 E0\"." -msgstr "«G92 E0» обнаружено в before_layer_change_gcode, но G или E не в верхнем регистре. Измените их на точное «G92 E0» в верхнем регистре." +msgstr "В G-коде перед сменой слоя обнаружена команда «G92 E0» с неправильным регистром. Измените регистр «G92 E0» на заглавные буквы." -# AI Translated msgid "\"G92 E0\" was found in layer_change_gcode, but the G or E are not uppercase. Please change them to the exact uppercase \"G92 E0\"." -msgstr "«G92 E0» обнаружено в layer_change_gcode, но G или E не в верхнем регистре. Измените их на точное «G92 E0» в верхнем регистре." +msgstr "В G-коде после смены слоя обнаружена команда «G92 E0» с неправильным регистром. Измените регистр «G92 E0» на заглавные буквы." msgid "Relative extruder addressing requires resetting the extruder position at each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to layer_gcode." msgstr "При относительной адресации экструдера его положение необходимо корректировать на каждом слое, чтобы предотвратить потерю точности с плавающей запятой. Добавьте \"G92 E0\" в G-код выполняемый при смене слоя (layer_gcode)." -# AI Translated +# на самом деле, вполне совместима и часто используется в самих прошивках при сбросе координат msgid "\"G92 E0\" was found in before_layer_change_gcode, which is incompatible with absolute extruder addressing." -msgstr "«G92 E0» обнаружено в before_layer_change_gcode, что несовместимо с абсолютной адресацией экструдера." +msgstr "В G-коде перед сменой слоя обнаружена команда «G92 E0», которая несовместима с абсолютными координатами экструдера." -# AI Translated msgid "\"G92 E0\" was found in layer_change_gcode, which is incompatible with absolute extruder addressing." -msgstr "«G92 E0» обнаружено в layer_change_gcode, что несовместимо с абсолютной адресацией экструдера." +msgstr "В G-коде после смены слоя обнаружена команда «G92 E0», которая несовместима с абсолютными координатами экструдера." #, c-format, boost-format msgid "Plate %d: %s does not support filament %s" @@ -12595,15 +12422,14 @@ msgstr "Компенсация усадки материала не будет msgid "Generating skirt & brim" msgstr "Генерация юбки и каймы" -# AI Translated msgid "" "Per-object skirts cannot fit between the objects in By object print sequence.\n" "\n" "Move the objects farther apart, reduce brim/skirt size, switch Skirt type to Combined, or switch Print sequence to By layer." msgstr "" -"Пообъектные юбки не помещаются между моделями при последовательности печати «По объектам».\n" +"Независимые юбки не помещаются между моделями при печати моделей по очереди.\n" "\n" -"Раздвиньте модели дальше друг от друга, уменьшите размер каймы/юбки, переключите тип юбки на «Комбинированная» или измените последовательность печати на «По слоям»." +"Попробуйте увеличить отступ между моделями, уменьшить размер юбки/каймы, использовать совместный тип юбки или печатать модели послойно." msgid "Exporting G-code" msgstr "Экспорт в G-код" @@ -12623,29 +12449,23 @@ msgstr "Область печати" msgid "Extruder printable area" msgstr "Область печати экструдера" -# AI Translated msgid "Support parallel printheads" -msgstr "Поддержка параллельных печатающих головок" +msgstr "Поддержка параллельных печатающих голов" -# AI Translated msgid "Enable printer settings for machines that can use multiple printheads in parallel." -msgstr "Включает настройки принтера для машин, способных использовать несколько печатающих головок параллельно." +msgstr "Отобразить настройки для принтеров, способных параллельно использовать несколько зависимых печатающих голов." -# AI Translated msgid "Parallel printheads count" -msgstr "Количество параллельных печатающих головок" +msgstr "Количество зависимых голов" -# AI Translated msgid "Set the number of parallel printheads for machines like OrangeStorm Giga printer." -msgstr "Задаёт количество параллельных печатающих головок для машин вроде принтера OrangeStorm Giga." +msgstr "Задаёт количество зависимых печатающих голов для принтеров вроде OrangeStorm Giga." -# AI Translated msgid "Parallel printheads bed exclude areas" -msgstr "Исключаемые зоны стола для параллельных печатающих головок" +msgstr "Области исключения для зависимых голов" -# AI Translated msgid "Ordered list of bed exclude areas by parallel printhead count. Item 1 applies to one printhead, item 2 to two printheads, and so on. Leave an item empty for no excluded area." -msgstr "Упорядоченный список исключаемых зон стола по количеству параллельных печатающих голов. Поле 1 применяется к одной голове, поле 2 — к двум, и так далее. Оставьте поле пустым, если исключаемые зоны отсутствуют." +msgstr "Список исключаемых областей стола, упорядоченный по количеству зависимых голов. 1 – область для одной головы, 2 — область для двух, и т.д. Оставьте пустым, если исключаемые области отсутствуют." msgid "Excluded bed area" msgstr "Область исключения" @@ -12666,23 +12486,21 @@ msgid "This shrinks the first layer on the build plate to compensate for elephan msgstr "Сужает контур первого слоя на заданное значение для компенсации дефекта слоновьей ноги." msgid "Elephant foot compensation layers" -msgstr "Компенсирующих слоёв «слоновьей ноги»" +msgstr "Слои компенсации" msgid "The number of layers on which the elephant foot compensation will be active. The first layer will be shrunk by the elephant foot compensation value, then the next layers will be linearly shrunk less, up to the layer indicated by this value." -msgstr "Количество слоёв, на которые будет распространяться компенсация слоновьей ноги. Первый слой будет уменьшен на величину компенсации слоновьей ноги с последующим линейным уменьшением до слоя, указанного здесь." +msgstr "Количество слоёв для компенсации избытка материала. Сужение контура первого слоя управляется настройкой выше, последующие слои линейно расширяются до нормального размера." msgid "Elephant foot layers density" -msgstr "Плотность слоёв компенсации" +msgstr "Плотность слоя компенсации" -# AI Translated msgid "" "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." msgstr "" -"Плотность внутреннего сплошного заполнения для компенсации слоёв «слоновьей ноги».\n" -"Задаётся начальное значение для второго слоя.\n" -"Последующие слои линейно уплотняются на высоту, заданную в elefant_foot_compensation_layers." +"Начальное значение плотности сплошного заполнения для компенсации дефекта «слоновьей ноги».\n" +"Позволяет компенсировать избыток материала за счёт снижения плотности первых слоёв с постепенным её восстановлением к слою, указанному выше." msgid "This is the height for each layer. Smaller layer heights give greater accuracy but longer printing time." msgstr "Высота каждого слоя. Чем меньше, тем выше качество поверхности и затраты времени (и наоборот)." @@ -12716,7 +12534,7 @@ msgid "Allow controlling BambuLab's printer through 3rd party print hosts." msgstr "Позволяет управлять принтером BambuLab через сторонние хосты печати." msgid "Use 3MF instead of G-code" -msgstr "Сжимать G-код перед отправкой" +msgstr "Сжатие G-кода перед отправкой" msgid "Enable this if the printer accepts a 3MF file as the print job. When enabled, Orca Slicer sends the sliced file as a .gcode.3mf, instead of a plain .gcode file." msgstr "Рекомендуется для принтеров, поддерживающих печать из архивов 3MF. Файлы печати будут отправляться с расширением \".gcode.3mf\"." @@ -12784,9 +12602,8 @@ msgstr "API-ключ" msgid "HTTP digest" msgstr "HTTP digest-авторизация" -# AI Translated msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly." -msgstr "Конфигурация возможностей плагинов, используемых этим профилем, переопределяющая глобальную конфигурацию возможностей. Хранится как необработанный массив JSON и редактируется через диалоговое окно за кнопкой, а не вводится напрямую." +msgstr "Настройки функционала плагинов, используемого этим профилем. Переопределяет глобальные настройки функционала. Хранится как необработанный массив JSON и редактируется через диалоговое окно по кнопке." # Логическая ошибка; пересекаются не периметры, а траектория холостого # перемещения со стенкой модели @@ -13236,7 +13053,7 @@ msgstr "" "Фактический поток для поддержек рассчитывается путём умножения этого значения на поток материала и общий поток модели (если он задан)." msgid "Support interface flow ratio" -msgstr "Интерфейс поддержек" +msgstr "Связующие слои" msgid "" "This factor affects the amount of material for the support interface.\n" @@ -13283,6 +13100,7 @@ msgstr "Дополнительные периметры на нависания msgid "Create additional perimeter paths over steep overhangs and areas where bridges cannot be anchored." msgstr "" "Создание дополнительных периметров над крутыми нависаниями и участками, где невозможно закрепить мосты.\n" +"\n" "Внимание: включение этой настройки может повлиять на корректность генерации мостов!" # ??? Реверс на чётных слоях нависаний @@ -13365,7 +13183,7 @@ msgstr "Включение динамического управления ск msgid "Slow down for curled perimeters" msgstr "Замедляться на изогнутых периметрах" -# AI Translated +# Обновил, отформатировал и провёл семантическую оптимизацию #, no-c-format, no-boost-format msgid "" "Enable this option to slow down printing in areas where perimeters may have curled upwards.\n" @@ -13383,20 +13201,20 @@ msgid "" "Note: When this option is enabled, overhang perimeters are treated like overhangs, meaning the overhang speed is applied even if the overhanging perimeter is part of a bridge.\n" "For example, when the perimeters are 100% overhanging, with no wall supporting them from underneath, the 100% overhang speed will be applied." msgstr "" -"Включите эту опцию, чтобы замедлять печать в областях, где периметры могли загнуться вверх.\n" -"Например, дополнительное замедление будет применяться при печати нависаний на острых углах, таких как нос корпуса Benchy, уменьшая загибание, которое накапливается на нескольких слоях.\n" +"Позволяет автоматически замедлять печать в областях, где выступающие периметры могут деформироваться из-за усадки.\n" +"Например, форштевень Benchy, который сильнее подвержен накоплению усадочной деформации.\n" "\n" -"Обычно рекомендуется держать эту опцию включённой, если только охлаждение вашего принтера не достаточно мощное или скорость печати не достаточно низкая, чтобы загибание периметров не происходило. \n" -"При печати с высокой скоростью внешнего периметра этот параметр может вносить артефакты на стенках при замедлении из-за потенциально большого разброса скоростей печати, из-за которого экструдер не успевает за требуемым изменением потока.\n" -"Коренная причина этих артефактов, скорее всего, — слегка неточная настройка PA, особенно в сочетании с большим временем сглаживания PA.\n" +"Рекомендуется использовать в случаях, если скоростной режим, конструкция принтера или его система охлаждения не способны обеспечить качественного сопротивления усадке материала.\n" "\n" -"Рекомендации при включении этой опции:\n" -"1. Уменьшите время сглаживания Pressure Advance до 0,015 - 0,02, чтобы экструдер быстро реагировал на изменения скорости.\n" -"2. Увеличьте минимальные скорости печати, чтобы ограничить величину замедления и уменьшить разброс между быстрыми и медленными участками.\n" -"3. Если артефакты всё ещё появляются, включите сглаживание скорости экструзии (ERS) для дальнейшего сглаживания переходов потока.\n" +"Примечание: отключает скоростной режим мостов для нависающих периметров (передаёт его в управление настройкам нависаний ниже).\n" "\n" -"Примечание: когда эта опция включена, нависающие периметры рассматриваются как нависания, то есть скорость нависания применяется, даже если нависающий периметр является частью моста.\n" -"Например, когда периметры нависают на 100%, без стенки, поддерживающей их снизу, будет применена скорость нависания 100%." +"Внимание: требуется крайне точная настройка коррекции давления. В противном случае при быстрой печати стенок в местах перепада скоростей будут возникать заметные артефакты поверхности.\n" +"\n" +"Рекомендации по настройке:\n" +"1. Уменьшите время сглаживания Pressure Advance до 0.015-0.02, чтобы\n" +"    повысить реактивность экструдера на изменения скорости.\n" +"2. Повысьте ограничения скоростей нависаний.\n" +"3. Если это не помогло, воспользуйтесь сглаживанием расхода." msgid "mm/s or %" msgstr "мм/с или %" @@ -13527,16 +13345,45 @@ msgstr "Послойно" msgid "By object" msgstr "По очереди" -# ???Внутрислойный порядок печати msgid "Intra-layer order" msgstr "Очерёдность моделей" -msgid "Print order within a single layer." -msgstr "Последовательность печати моделей в пределах одного слоя." +# До 2.5.0 было легко и просто, теперь взяли и кучу подкапотных алгоритмов на пользователя вывалили... Упростил, насколько это возможно без потери смысла, чтобы всем угодить. Контекст: в 2.5.0 настройку переработали, чтобы все алгоритмы создавали цикличный маршрут, при котором конечная точка была бы максимально близко к началу (предположительно, следующего слоя). Цикличный маршрут позволяет избежать перемещений над уже напечатанным на слое, что убирает необходимость в Z-hop для простых моделей. PR: https://github.com/OrcaSlicer/OrcaSlicer/pull/13578 +# +# Примечания: Default использует алгоритм Greedy, 2-opt – алгоритм устранения самопересечений. Кратчайший путь проверяет всего 2 стратегии, остальные уже удалены как неэффективные и медленные. +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Последовательность печати моделей в пределах одного слоя. Влияет на суммарное время перемещений от модели к модели.\n" +"\n" +"• По умолчанию: поиск ближайших моделей с оптимизацией пути\n" +"   и устранением пересечений. Быстрый универсальный вариант.\n" +"• По списку: сохранять тот же порядок, что и в списке моделей, без\n" +"   какой-либо оптимизации. Полезно для ручной настройки очерёдности.\n" +"• Кратчайший путь: выбор кратчайшего маршрута из всех стратегий.\n" +"   Маршрут может меняться от слоя к слою из-за изменения числа\n" +"   отдельных контуров. Требует больше времени.\n" +"• Змейкой: зигзагообразный маршрут с оптимизацией. Хорошо\n" +"   подходит для массивов из множества мелких деталей.\n" +"\n" +"Примечание: при использовании нескольких материалов приоритет отдаётся минимизации числа их смен. Очерёдность определяется для каждого материала отдельно, и визуально маршрут может казаться неоптимальным." msgid "As object list" msgstr "По списку" +msgid "Best of all (shortest path)" +msgstr "Кратчайший путь" + +msgid "Snake" +msgstr "Змейкой" + msgid "Slow printing down for better layer cooling" msgstr "Замедлять печать для охлаждения слоёв" @@ -13588,17 +13435,17 @@ msgstr "" "Включение вытяжного вентилятора для лучшего охлаждения внутренней области принтера.\n" "Команда G-кода: M106 P3 S(0-255)" -# AI Translated +# Сломано и не отображается, портировано для X2D msgid "Enable this to override the fan speed set in custom G-code during print." -msgstr "Включите, чтобы переопределить скорость вентилятора, заданную в пользовательском G-code во время печати." +msgstr "Заменять процент скорости вентилятора во время печати, указанную через пользовательский G-код." -# AI Translated +# Сломано и не отображается, портировано для X2D msgid "On completion" msgstr "По завершении" -# AI Translated +# Сломано и не отображается, портировано для X2D msgid "Enable this to override the fan speed set in custom G-code after print completion." -msgstr "Включите, чтобы переопределить скорость вентилятора, заданную в пользовательском G-code после завершения печати." +msgstr "Заменить процент скорости вентилятора после завершения печати, указанную через пользовательский G-код." msgid "Speed of exhaust fan during printing. This speed will override the speed in filament custom G-code." msgstr "Скорость вытяжного вентилятора во время печати. Эта скорость переопределяет скорость в пользовательском G-коде материала." @@ -14090,7 +13937,7 @@ msgid "Extruder Color" msgstr "Цвет экструдера" msgid "Only used as a visual help on UI." -msgstr "Используется только в качестве визуальной помощи в пользовательском интерфейсе." +msgstr "Используется для визуализации в интерфейсе слайсера." msgid "Extruder offset" msgstr "Смещение координат экструдера" @@ -14167,11 +14014,11 @@ msgstr "" " • наиболее высокий расход при печати (обычно, заполнения).\n" "Выбор тестируемых ускорений:\n" " • наиболее низкое ускорение из настроек печати\n" -" • наиболее высокое ускорение (не должно превышать\n" -"    рекомендуемый предел калибровщика Input Shaper в Klipper)\n" +" • наиболее высокое ускорение (не должно превышать предел\n" +"    рекомендуемого шейпера в Klipper)\n" "\n" -"2. Выпишите коэффициенты PA по примеру выше для каждой пары расхода/ускорения. Удельный расход можно посмотреть в «Просмотре нарезки», выбрав режим отображения «Объёмный расход». Значение отображается над горизонтальной шкалой печати слоя. Особенности:\n" -"• Как правило, значение PA должно снижаться с повышением расхода.\n" +"2. Выпишите коэффициенты PA по примеру выше для каждой пары расхода/ускорения. Значения расхода можно посмотреть в «Просмотре нарезки», выбрав режим отображения «Объёмный расход». Значение отображается над горизонтальной шкалой печати слоя. Особенности:\n" +"• Как правило, коэффициент должен снижаться с повышением расхода.\n" "   Если это не так, проверьте экструдер и корректность тестов.\n" "• Диапазон PA растёт со снижением скоростей и ускорений.\n" "• Если разницы между тестами не наблюдается, выбирайте PA из\n" @@ -14182,7 +14029,6 @@ msgstr "" msgid "Enable adaptive pressure advance within features (beta)" msgstr "Адаптироваться к изменениям линии" -# AI Translated msgid "" "Enable adaptive PA whenever there are flow changes in a feature, such as line width changes in a corner or overhangs.\n" "\n" @@ -14190,11 +14036,11 @@ msgid "" "\n" "This is an experimental option, as if the PA profile is not set accurately, it will cause uniformity issues." msgstr "" -"Включает адаптивный PA всякий раз, когда в элементе есть изменения потока, например изменение ширины линии на углу или нависаниях.\n" +"Экспериментальный режим смены коэффициента РА прямо посреди печати линии для адаптации к изменениям расхода на ней (например, на нависаниях или периметрах переменной ширины).\n" "\n" -"Несовместимо с принтерами Prusa, так как они делают паузу для обработки изменений PA, что вызывает задержки и дефекты.\n" +"Предупреждение: неточный подбор значений РА может привести к дефектам при работе этой настройки.\n" "\n" -"Это экспериментальная опция: если профиль PA задан неточно, это вызовет проблемы с однородностью." +"Внимание: несовместимо с принтерами Prusa, поскольку им требуется остановка для изменения коэффициента РА." msgid "Static pressure advance for bridges" msgstr "Фиксированный PA на мостах" @@ -14265,18 +14111,18 @@ msgid "Minimum HRC of nozzle required to print the filament. A value of 0 means msgstr "Минимальная твёрдость материала сопла (HRC), необходимая для печати материалом. 0 – отключение проверки твёрдости сопел." msgid "Filament map to extruder" -msgstr "Назначение филамента на экструдер" +msgstr "Назначение материала на экструдер" msgid "Filament map to extruder." -msgstr "Назначение филамента на экструдер." +msgstr "Назначение материала на экструдер." msgid "Auto For Flush" msgstr "Авто для прочистки" +# Не смог найти в интерфейсе msgid "Auto For Match" msgstr "Авто для сопоставления" -# AI Translated msgid "Nozzle Manual" msgstr "Ручная настройка сопел" @@ -14286,9 +14132,8 @@ msgstr "Температура прочистки" msgid "Temperature when flushing filament. 0 indicates the upper bound of the recommended nozzle temperature range." msgstr "Температура при прочистке. 0 – использовать максимально допустимую температуру." -# AI Translated msgid "Flush temperature used in fast purge mode." -msgstr "Температура прочистки, используемая в режиме быстрой прочистки." +msgstr "Температура в режиме быстрой прочистки." msgid "Flush volumetric speed" msgstr "Расход при прочистке" @@ -14358,9 +14203,9 @@ msgid "" "\n" "Note: Experimental and incomplete feature imported from BBS. Functional for some profiles that already have the variable saved." msgstr "" -"При включении поток экструзии ограничивается меньшим из расчётного значения (вычисленного по ширине линии и высоте слоя) и заданного пользователем максимального потока. При отключении применяется только заданный пользователем максимальный поток.\n" +"Регулирует значение максимального расхода при печати тонких и узких линий для достижения оптимальной линейной скорости. По сути, ограничивает расход материала в случаях, когда завышенная скорость движения сопла не позволяет материалу надёжно спекаться с предыдущим слоем.\n" "\n" -"Примечание: экспериментальная и неполная функция, перенесённая из BBS. Работает для некоторых профилей, в которых уже сохранена эта переменная." +"Внимание: требует настройки модели расхода и пока работает только у преднастроенных производителем профилей материалов." msgid "Max volumetric speed multinomial coefficients" msgstr "Коэффициенты расчёта максимального расхода" @@ -14452,28 +14297,27 @@ msgstr "Мин. объём прочистки на черновой башне" msgid "After a tool change, the exact position of the newly loaded filament inside the nozzle may not be known, and the filament pressure is likely not yet stable. Before purging the print head into an infill or a sacrificial object, Orca Slicer will always prime this amount of material into the wipe tower to produce successive infill or sacrificial object extrusions reliably." msgstr "После смены инструмента, точное положение вновь загруженного прутка внутри него может быть неизвестно, и давление прутка, вероятно, ещё не стабильно. Перед тем, как очистить печатающую головку в заполнение или в «жертвенную» модель Orca Slicer всегда будет выдавливать это количество материала на черновую башню, чтобы обеспечить надёжную печать заполнения или «жертвенной» модели." -# AI Translated +# Не реализовано msgid "Wipe tower cooling" -msgstr "Охлаждение черновой башни" +msgstr "Охлаждение на черновой башне" -# AI Translated msgid "Temperature drop before entering filament tower" -msgstr "Снижение температуры перед входом в башню материала" +msgstr "Снижение температуры перед входом в башню" msgid "Interface layer pre-extrusion distance" -msgstr "Расстояние предэкструзии слоя интерфейса" +msgstr "Дистанция избыточной подачи при смене" msgid "Pre-extrusion distance for prime tower interface layer (where different materials meet)." -msgstr "Расстояние предэкструзии слоя интерфейса башни очистки (где соприкасаются разные материалы)." +msgstr "Протяжённость первичного движения прочистки после смены материала. Позволяет быстро набрать давление в сопле и сбросить перегретый материал.\n\nПримечание: фактическая длина может быть ограничена шириной башни." msgid "Interface layer pre-extrusion length" -msgstr "Длина предэкструзии слоя интерфейса" +msgstr "Длина прутка для избыточной подачи" msgid "Pre-extrusion length for prime tower interface layer (where different materials meet)." -msgstr "Длина предэкструзии слоя интерфейса башни очистки (где соприкасаются разные материалы)." +msgstr "Длина прутка, которую необходимо продавить на этапе избыточной подачи.\n\n0 – отключить этот этап." msgid "Tower ironing area" -msgstr "Разглаживание черновой башни" +msgstr "Разглаживание кончиков" # У H2D не требует, на Вики при этом написано, что требует... В баганном порте # "улучшений" башни вообще не работает ни при каких обстоятельствах. @@ -14486,15 +14330,18 @@ msgstr "" msgid "mm²" msgstr "мм²" +# Сломано и ни на что не влияет, даже на H2D и даже в Bambu Studio. msgid "Interface layer purge length" msgstr "Прочистка на слое интерфейса" +# Из ченжлогов Bambu: Studio will do nozzle wiping before flushing rather than after flushing, and print the prime tower directly, reducing extrusion volume fluctuations and improving layer height consistency. Added a new parameter for interface-layer flushing length. msgid "Purge length for prime tower interface layer (where different materials meet)." -msgstr "Длина прочистки на слое интерфейса башни (где соприкасаются разные материалы)." +msgstr "В настоящее время ничего не делает. Задумывалось как настройка расстояния внешней очистки сопла перед основной процедурой его прочистки." msgid "Interface layer print temperature" msgstr "Температура при прочистке" +# Не используется, настройка сломана. Перевёл на случай, если починят в будущем. msgid "Print temperature for prime tower interface layer (where different materials meet). If set to -1, use max recommended nozzle temperature." msgstr "" "Целевая температура при печати слоёв прочистки в черновой башне (место контакта разных материалов).\n" @@ -14569,11 +14416,9 @@ msgstr "Пригодный для печати" msgid "The filament is printable in extruder." msgstr "Материалом можно печатать через экструдер." -# AI Translated msgid "Filament-extruder compatibility" msgstr "Совместимость материала и экструдера" -# AI Translated msgid "A single 32-bit int encoding the compatibility level of a filament across all extruders (up to 10). Every 3 bits represent one extruder (bits [3*i, 3*i+2] for extruder i). 0: printable, 1: error, 2: critical warning, 3: warning, 4-7: reserved." msgstr "Одно 32-битное целое число, кодирующее уровень совместимости материала со всеми экструдерами (до 10). Каждые 3 бита представляют один экструдер (биты [3*i, 3*i+2] для экструдера i). 0: пригоден для печати, 1: ошибка, 2: критическое предупреждение, 3: предупреждение, 4-7: зарезервировано." @@ -14819,36 +14664,35 @@ msgstr "" "Внимание: параметр является устаревшим и в новых версиях Klipper был переименован в \"minimum_cruise_ratio\"." msgid "Default jerk." -msgstr "Рывок по умолчанию." +msgstr "Рывки по умолчанию." msgid "Marlin Firmware Junction Deviation (replaces the traditional XY Jerk setting)." msgstr "Junction Deviation для прошивки Marlin (заменяет традиционную настройку рывка XY)." msgid "Jerk of outer walls." -msgstr "Рывок для внешних периметров." +msgstr "Рывки на внешних периметрах." msgid "Jerk of inner walls." -msgstr "Рывок для внутренних периметров." +msgstr "Рывки на внутренних периметрах." msgid "Jerk for top surface." -msgstr "Рывок для верхней поверхности." +msgstr "Рывки на верхней поверхности." msgid "Jerk for infill." -msgstr "Рывок для заполнения." +msgstr "Рывки на заполнении." msgid "Jerk for the first layer." -msgstr "Рывок для первого слоя." +msgstr "Рывки на первом слое." msgid "Jerk for travel." -msgstr "Рывок при перемещении." +msgstr "Рывки при перемещениях." -# AI Translated msgid "" "Travel jerk of first layer.\n" "The percentage value is relative to Travel Jerk." msgstr "" -"Рывок перемещения первого слоя.\n" -"Процентное значение задаётся относительно рывка перемещения." +"Рывки при перемещениях на первом слое.\n" +"Можно указать процент от рывков при обычных перемещениях." msgid "Line width of the first layer. If expressed as a %, it will be computed over the nozzle diameter." msgstr "Ширина линий первого слоя. Можно указать процент от диаметра сопла." @@ -14971,7 +14815,7 @@ msgid "Ironing line spacing" msgstr "Интервал линий" msgid "Filament-specific override for ironing line spacing. This allows you to customize the spacing between ironing lines for each filament type." -msgstr "Индивидуальная настройка расстояния между линиями разглаживания для каждого типа филамента." +msgstr "Замещение интервала между линиями разглаживания. Позволяет настроить интервал отдельно для каждого материала." # "Разглаживание" явно задано в заголовке раздела msgid "Ironing inset" @@ -15071,7 +14915,7 @@ msgid "" msgstr "" "Тип шума, используемый для генерации нечёткой оболочки.\n" "\n" -"• Случайный: равномерно резкий шум.\n" +"• Классический: равномерно резкий шум.\n" "• Шум Перлина: согласованный однородный шум.\n" "• Волновой: более резкий вариант шума Перлина.\n" "• Ребристый: резкий сглаженный шум с мраморной текстурой.\n" @@ -15080,9 +14924,9 @@ msgstr "" "\n" "Примечание: для разных алгоритмов оптимальны разные масштабы." -# Поменял на "случайный" из-за нехватки места. +# Поменял на "случайный" из-за нехватки места. UPD: Вернул из-за конфликта с генератором периметров msgid "Classic" -msgstr "Случайный" +msgstr "Классический" msgid "Perlin" msgstr "Шум Перлина" @@ -15268,31 +15112,28 @@ msgstr "Наилучшее расположение модели при авто msgid "Enable this option if machine has auxiliary part cooling fan. G-code command: M106 P2 S(0-255)." msgstr "" -"Если в принтере имеется вспомогательный вентилятор для охлаждения моделей (обычно это боковой вентилятор), можете включить эту опцию.\n" +"Включить управление вспомогательным вентилятором из настроек материала.\n" "Команда G-кода: M106 P2 S(0-255)." -# AI Translated msgid "Fan direction" msgstr "Направление вентилятора" -# AI Translated msgid "Cooling fan direction of the printer" -msgstr "Направление вентилятора охлаждения принтера" +msgstr "Направление потока охлаждения вспомогательного вентилятора" -# AI Translated msgid "Both" -msgstr "Оба" +msgstr "Обе стороны" +# "only custom start G-code" в Орке не существует. Вероятно, забыли стереть при портировании из SuperSlicer. msgid "" "Start the fan this number of seconds earlier than its target start time (you can use fractional seconds). It assumes infinite acceleration for this time estimation, and will only take into account G1 and G0 moves (arc fitting is unsupported).\n" "It won't move fan commands from custom G-code (they act as a sort of 'barrier').\n" "It won't move fan commands into the start G-code if the 'only custom start G-code' is activated.\n" "Use 0 to deactivate." msgstr "" -"Запуск вентилятора на указанное количество секунд раньше целевого времени запуска (поддерживаются доли секунды). При этом предполагается бесконечное ускорение для оценки этого времени, и учёт только перемещений G1 и G0 (Аппроксимация дугами).\n" -"Это не приведёт к сдвигу команд вентилятора из пользовательских G-кодов (они действуют как своего рода барьер).\n" -"Это не приведёт к сдвигу команд вентилятора в стартовом G-коде, если активировано «только пользовательский стартовый G-код».\n" -"Установите 0 для отключения." +"Сместить управление вентилятором на заданное время для его запуска заранее. Можно указать дробное количество секунд.\n" +"\n" +"Примечание: расчёт смещения не учитывает ускорения, команды движения по дуге (аппроксимацию дугами) и пользовательский G-код." msgid "Only overhangs" msgstr "Только на нависаниях" @@ -15308,7 +15149,8 @@ msgid "" "This is useful for fans where a low PWM/power may be insufficient to get the fan started spinning from a stop, or to get the fan up to speed faster.\n" "Set to 0 to deactivate." msgstr "" -"Время принудительного запуска (kick-start) вентилятора на максимальной скорости, после чего скорость снижается до целевой. Это необходимо для вентиляторов у которых низкое значение уровня ШИМ/мощности может быть недостаточен для запуска вентилятора после остановки или для более быстрого увеличения скорости его вращения.\n" +"Время принудительного запуска на максимальных оборотах перед выходом на заданный процент скорости. Полезно для повышения отзывчивости вентиляторов с инертным ротором (а также в случаях, когда для его страгивания требуется дополнительное усилие).\n" +"\n" "Установите 0 для отключения." msgid "Minimum non-zero part cooling fan speed" @@ -15352,16 +15194,15 @@ msgid "" "Enable this if printer support air filtration\n" "G-code command: M106 P3 S(0-255)" msgstr "" -"Если в принтере имеется вытяжной вентилятор и вам требуется дополнительное охлаждение внутренней области принтера, включите эту опцию.\n" +"Включить управление вытяжным вентилятором из настроек материала.\n" "Команда G-кода: M106 P3 S(0-255)" -# AI Translated +# Из ченжлогов Bambu: Added a filtering option with cooling mode for the adaptive air circulation system. This option can be enabled via the slicer or the printer UI, and it's mainly used to filter the air when exhausting the air for low-temperature filaments msgid "Use cooling filter" -msgstr "Использовать фильтр охлаждения" +msgstr "Охлаждать через фильтр" -# AI Translated msgid "Enable this if printer support cooling filter" -msgstr "Включите, если принтер поддерживает фильтр охлаждения" +msgstr "Включить управление вытяжным вентилятором." msgid "G-code flavor" msgstr "Тип G-кода" @@ -15542,33 +15383,29 @@ msgstr "Угол нависания заполнения" msgid "The angle of the infill angled lines. 60° will result in a pure honeycomb." msgstr "Угол нависания линий заполнения. При 60° получаются правильные соты." -# AI Translated msgid "Lightning overhang angle" -msgstr "Угол нависания для «Молнии»" +msgstr "Наклон поверхности для поддержки молнией" -# AI Translated msgid "Maximum overhang angle for Lightning infill support propagation." -msgstr "Максимальный угол нависания для распространения поддержки заполнения «Молния»." +msgstr "Максимальный угол наклона внутренних поверхностей для их поддержки отдельными ветвями молнии." -# AI Translated msgid "Prune angle" -msgstr "Угол обрезки" +msgstr "Наклон опор" -# AI Translated +# Оооочень технично. Самая главная проблема в понимании – шаблон генерируется "сверху вниз" (а не наоборот, как можно бы подумать), из-за чего и возникает вся эта техничность в содержании подсказок. На Вики чуть понятнее, но всё равно чрезвычайно технично. Убрал описание тонкостей фильтрации алгоритма и заменил на то, что по сути делает настройка. msgid "" "Controls how aggressively short or unsupported Lightning branches are pruned.\n" "This angle is converted internally to a per-layer distance." msgstr "" -"Определяет, насколько агрессивно обрезаются короткие или неподдерживаемые ветви «Молнии».\n" -"Внутренне этот угол преобразуется в расстояние на слой." +"Допустимый наклон опор молнии. Чем выше, тем быстрее и экономичнее распространяются её ветви." -# AI Translated +# "Выпрямление" здесь, вопреки первой мысли – это как раз-таки наоборот искажение шаблона по ходу печати для сокращения количества ветвей. Короче, опять путаница из-за того, что генерация ветвей происходит сверху вниз. При печати снизу вверх шаблон именно что искажается. msgid "Straightening angle" -msgstr "Угол выпрямления" +msgstr "Наклон локальных искажений" -# AI Translated +# При минимальном значении сразу понятно, что делает. Может стоит это указать, чтобы людям было проще осваивать настройку. msgid "Maximum straightening angle used to simplify Lightning branches." -msgstr "Максимальный угол выпрямления, используемый для упрощения ветвей «Молнии»." +msgstr "Дополнительные искажения позволяют эффективнее объединять опоры для ветвей. Чем больше наклон, тем сильнее может искажаться контур молнии." msgid "Sparse infill anchor length" msgstr "Длина привязок шаблона заполнения" @@ -15939,37 +15776,30 @@ msgstr "Минимальная скорость холостых перемещ msgid "Minimum travel speed (M205 T)" msgstr "Минимальная скорость перемещения без печати (M205 T)" -# AI Translated msgid "Maximum force of the Y axis" msgstr "Максимальное усилие оси Y" -# AI Translated +# По сути, перемножение массы на ускорение msgid "The allowed maximum output force of Y axis" -msgstr "Допустимое максимальное выходное усилие оси Y" +msgstr "Максимально допустимое усилие по оси Y." -# AI Translated msgid "N" msgstr "Н" -# AI Translated msgid "Bed mass of the Y axis" -msgstr "Масса стола по оси Y" +msgstr "Масса стола (оси Y)" -# AI Translated msgid "The machine bed mass load of Y axis" -msgstr "Массовая нагрузка стола машины по оси Y" +msgstr "Пассивная нагрузка механики оси Y массой стола." -# AI Translated msgid "g" msgstr "г" -# AI Translated msgid "The allowed max printed mass" -msgstr "Допустимая максимальная масса печати" +msgstr "Максимально допустимая масса печати" -# AI Translated msgid "The allowed max printed mass on a plate" -msgstr "Допустимая максимальная масса печати на столе" +msgstr "Максимально допустимая масса деталей на столе." msgid "Maximum acceleration for extruding" msgstr "Максимальное ускорение при печати" @@ -16127,8 +15957,9 @@ msgid "The highest printable layer height for the extruder. Used to limit the ma msgstr "Максимальная высота слоя для печати этим экструдером. Используется в качестве ограничения при использовании адаптивной высоты слоя." msgid "Extrusion rate smoothing" -msgstr "Сглаживание подачи" +msgstr "Сглаживание расхода" +# Провёл семантическую оптимизацию, очень уж длинно расписано. Плюс убрал про PrusaSlicer, т.к. в локализациях одинаково. + пояснения про скорость/ширину, т.к. Орка теперь умеет напрямую раскрашивать расход без необходимости считать его ручками. msgid "" "This parameter smooths out sudden extrusion rate changes that happen when the printer transitions from printing a high flow (high speed/larger width) extrusion to a lower flow (lower speed/smaller width) extrusion and vice versa.\n" "\n" @@ -16144,16 +15975,15 @@ msgid "" "\n" "Note: this parameter disables arc fitting." msgstr "" -"Сглаживает резкие изменения скорости подачи материала, которые происходят при переходе от печати с большим расходом (высокая скорость/большая ширина линии) к печати с меньшим расходом (меньшая скорость/меньшая ширина) и наоборот.\n" +"Сглаживает резкие изменения скорости подачи материала, которые происходят при переходе от печати с бóльшим расходом к печати с меньшим (и наоборот).\n" +"\n" +"По сути, ограничение производной от расхода: ограничивает скорость, с которой расход материала может меняться за единицу времени. Чем выше лимит, тем быстрее может меняться расход.\n" "\n" -"Параметр задаёт максимальную скорость, с которой расход материала может измениться за единицу времени. Чем выше лимит, тем быстрее может меняться расход материала. \n" "Установите 0 для отключения.\n" "\n" -"Для скоростных принтеров с прямой системой подачи и производительным экструдером (например, Bambu lab или Voron) сглаживание подачи обычно не требуется. Однако в некоторых случаях, когда скорость печати сильно различается, это может принести дополнительную пользу. Например, когда происходят резкие замедления из-за нависаний. В этих случаях рекомендуется использовать высокое значение, составляющее около 300-350 мм³/с², при оптимально настроенном Pressure Advance (коррекции давления) это поможет достичь более плавного перехода.\n" +"Для скоростных принтеров с производительным экструдером сглаживание обычно не требуется, но может быть полезным в местах с высоким перепадом скоростей. Например, для сглаживания замедлений при печати нависаний. При точно настроенной коррекции давления (коэффициент PA и время сглаживания) значения около 300-350 мм³/с² помогут дополнительно сгладить такие места.\n" "\n" -"У более медленных принтеров с внешней системой подачи или прошивкой без коррекции давления значение должно быть значительно ниже. 10-15 мм³/с² является хорошей отправной точкой для экструдеров с прямой подачей и 5-10 мм³/с² для внешней.\n" -"\n" -"В Prusa Slicer эта функция известна как «Сглаживание расхода» (Pressure equalizer).\n" +"Для более медленных принтеров с внешней системой подачи или прошивкой без коррекции давления значение должно быть гораздо ниже: 10-15 мм³/с² при прямой подаче и 5-10 мм³/с² при внешней.\n" "\n" "Примечание: при ненулевом значении отключает аппроксимацию дугами." @@ -16161,7 +15991,7 @@ msgid "mm³/s²" msgstr "мм³/с²" msgid "Smoothing segment length" -msgstr "Длина сглаживающего сегмента" +msgstr "Протяжённость сглаживания" msgid "" "A lower value results in smoother extrusion rate transitions. However, this results in a significantly larger G-code file and more instructions for the printer to process.\n" @@ -16176,14 +16006,13 @@ msgstr "" "\n" "Допустимые значения: 0,5–5" -# ??? msgid "Apply only on external features" -msgstr "Применять только к видимым элементам" +msgstr "Применять только к видимым элементам" msgid "Applies extrusion rate smoothing only on external perimeters and overhangs. This can help reduce artefacts due to sharp speed transitions on externally visible overhangs without impacting the print speed of features that will not be visible to the user." msgstr "" -"Сглаживание скорости экструзии будет применяться только к внешним периметрам и нависаниям.\n" -"Это помогает уменьшить количество артефактов, вызванные резкими перепадами скорости на видимых внешних участках, без влияния на скорость печати внутренних элементов, которые не видны пользователю." +"Применять сглаживание расхода только к внешним периметрам и нависаниям.\n" +"Помогает компенсировать видимые артефакты перепада скоростей без влияния на скорость печати внутренних элементов." msgid "Minimum speed for part cooling fan." msgstr "Минимальная скорость вентилятора обдува модели." @@ -16192,29 +16021,28 @@ msgid "" "Speed of auxiliary part cooling fan. Auxiliary fan will run at this speed during printing except the first several layers which is defined by no cooling layers.\n" "Please enable auxiliary_fan in printer settings to use this feature. G-code command: M106 P2 S(0-255)" msgstr "" -"Скорость вращения вспомогательного вентилятора для охлаждения моделей. Обычно это боковой вентилятор. Он всегда будет работать с этой скоростью, за исключением первых нескольких слоёв, которые обычно настроены на работу без охлаждения.\n" -"Пожалуйста, включите вспомогательный вентилятор для охлаждения моделей (auxiliary_fan) в настройках принтера, чтобы использовать эту функцию.\n" +"Процент скорости вспомогательного вентилятора для охлаждения моделей. Используется на протяжении всей печати (кроме слоёв, указанных в разделе «Охлаждение начала печати»).\n" +"Для работы этой настройки необходимо включить поддержку вспомогательного вентилятора на стороне принтера в его профиле.\n" "Команда G-кода: M106 P2 S(0-255)." -# AI Translated msgid "For the first" msgstr "Для первых" -# AI Translated msgid "Set special auxiliary cooling fan for the first certain layers." -msgstr "Задаёт особую скорость вспомогательного вентилятора обдува для первых нескольких слоёв." +msgstr "Особая скорость вспомогательного вентилятора для первых нескольких слоёв." -# AI Translated msgid "" "Auxiliary fan speed will be ramped up linearly from layer \"For the first\" to maximum at layer \"Full fan speed at layer\".\n" "\"Full fan speed at layer\" will be ignored if lower than \"For the first\", in which case the fan will run at maximum allowed speed at layer \"For the first\" + 1." msgstr "" -"Скорость вспомогательного вентилятора будет линейно увеличиваться от слоя «Для первых» до максимума на слое «Полная скорость вентилятора на слое».\n" -"«Полная скорость вентилятора на слое» будет проигнорирована, если она меньше «Для первых»; в этом случае вентилятор будет работать на максимально допустимой скорости на слое «Для первых» + 1." +"Начиная с указанного слоя, интенсивность охлаждения будет равномерно меняться для перехода к требуемым условиям обдува детали.\n" +"\n" +"Если активна настройка «Не обдувать первые N слоёв» – с учётом этих слоёв.\n" +"\n" +"Примечание: если слоёв с заблокированным обдувом больше, чем указано здесь, то восстановление происходит моментально на первом доступном слое." -# AI Translated msgid "Special auxiliary cooling fan speed, effective only for the first x layers." -msgstr "Особая скорость вспомогательного вентилятора обдува, действует только для первых x слоёв." +msgstr "Особая скорость вспомогательного вентилятора для первых N слоёв." msgid "The lowest printable layer height for the extruder. Used to limit the minimum layer height when enable adaptive layer height." msgstr "Минимальная высота слоя для печати этим экструдером. Используется в качестве ограничения при использовании адаптивной высоты слоя." @@ -16336,9 +16164,9 @@ msgstr "Глухие отверстия в основании модели ра msgid "Detect overhang walls" msgstr "Обнаруживать нависающие периметры" -#, fuzzy, c-format, boost-format +#, c-format, boost-format msgid "This detects the overhang percentage relative to line width and uses a different speed to print. For 100%% overhang, bridging speed is used." -msgstr "Определяет процент нависания относительно ширины линии и использует разную скорость печати. Для 100%-го нависания используется скорость печати мостов." +msgstr "Использовать разную скорость печати в зависимости от выноса линии относительно её опоры. Для нависаний без опоры используется скорость печати мостов." # В секции "Материал для линий" msgid "Outer walls" @@ -16396,17 +16224,15 @@ msgstr "G-код при смене типа линии (настройки пе msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code." msgstr "Команды в G-коде, которые выполняются между печатью разных элементов структуры (например, при переходе от периметра к заполнению). Выполняются после команд смены типа линии из настроек принтера и материала." -# AI Translated msgid "Plugins Used" msgstr "Используемые плагины" -# AI Translated +# Функционал плагинов для этого прояиля, указывается... msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability." -msgstr "Возможности плагинов, на которые ссылается этот профиль, хранятся как name;uuid;capability." +msgstr "Функционал плагинов, на который ссылается этот профиль, указывается как name;uuid;capability." -# AI Translated msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental." -msgstr "Плагины Python, вызываемые на каждом шаге конвейера нарезки для чтения и изменения промежуточных данных нарезки, включая финальный шаг постобработки G-code. Исследовательская/экспериментальная функция." +msgstr "Python-плагины, вызываемые на каждом этапе нарезки для чтения и изменения промежуточных её данных (включая финальную постобработку G-кода). Тестовая/экспериментальная функция." msgid "Printer type" msgstr "Тип принтера" @@ -16475,18 +16301,17 @@ msgstr "" "\n" "Примечание: значение не может быть меньше 25% или больше 100% и будет скорректировано автоматически при нарезке." -# AI Translated msgid "Retract amount after wipe" -msgstr "Величина отката после обтирания" +msgstr "Вторичный откат" -# AI Translated #, no-c-format, no-boost-format msgid "" "The length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" -"Длина быстрого отката после обтирания относительно длины отката.\n" -"Значение будет ограничено 100% минус величина отката до обтирания." +"Быстрый откат после очистки, выраженный в процентах от общей длины отката. В некоторых случаях позволяет значительно снизить количество «паутины»." +"\n" +"Примечание: суммарное значение не должно превышать 100% и будет скорректировано автоматически." msgid "Retract on layer change" msgstr "Откат при смене слоя" @@ -16613,18 +16438,16 @@ msgstr "Прямой (Direct)" msgid "Bowden" msgstr "Внешний (Bowden)" -# AI Translated +# https://wiki.bambulab.com/ru/h2c/manual/bambu-studio-h2c-operation#:~:text=Гибридный msgid "Hybrid" msgstr "Гибридный" -# Разобраться позже: wiki.bambulab.com/en/software/bambu-studio/filament-track-switch-dynamic-mapping -# AI Translated +# https://wiki.bambulab.com/ru/software/bambu-studio/filament-track-switch-dynamic-mapping msgid "Enable filament dynamic map" -msgstr "Включить динамическое сопоставление материалов" +msgstr "Динамическое сопоставление материалов" -# AI Translated msgid "Enable dynamic filament mapping during print." -msgstr "Включает динамическое сопоставление материалов во время печати." +msgstr "Включить динамическое сопоставление материалов во время печати." msgid "Has filament switcher" msgstr "Автосмена материала" @@ -16651,15 +16474,13 @@ msgid "Deretraction speed" msgstr "Скорость возврата" msgid "Speed for reloading filament into the nozzle. Zero means same speed of retraction." -msgstr "Скорость возврата материала в экструдер после отката. При значении 0 используется скорость отката." +msgstr "Скорость возврата материала в сопло после отката.\n0 – использовать скорость отката." -# AI Translated msgid "Deretraction speed (extruder change)" -msgstr "Скорость подачи (смена экструдера)" +msgstr "Скорость возврата (смена экструдера)" -# AI Translated msgid "Speed for reloading filament into the nozzle when switching extruder." -msgstr "Скорость возврата материала в сопло при смене экструдера." +msgstr "Скорость возврата материала в сопло после смены экструдера." msgid "Use firmware retraction" msgstr "Откат на уровне прошивки" @@ -16920,13 +16741,13 @@ msgstr "Тип юбки" # Про расширенное описание см. в комментарии к перевод подсказки настройки "Skirt minimum extrusion length" msgid "Combined - single skirt for all objects, Per object - individual object skirt." msgstr "" -"Выбор типа печатаемой юбки – одна общая для всех моделей или отдельные юбки для каждой модели.\n" +"Выбор типа печатаемой юбки – одна общая для всех моделей или независимые юбки для каждой модели.\n" "\n" "Внимание: при создании индивидуальных юбок проверка пересечения не совершается, из-за чего при близком расположении моделей они могут накладываться друг на друга. В таких случаях рекомендуется понизить количество контуров." # Отдельный (антоним к "совместный") msgid "Per object" -msgstr "Для каждой модели" +msgstr "Независимый" msgid "Skirt loops" msgstr "Контуров юбки" @@ -17032,21 +16853,20 @@ msgstr "" "Можно указать своё конечное значение потока, чтобы избежать подобных проблем." msgid "If smooth or traditional mode is selected, a timelapse video will be generated for each print. After each layer is printed, a snapshot is taken with the chamber camera. All of these snapshots are composed into a timelapse video when printing completes. If smooth mode is selected, the toolhead will move to the excess chute after each layer is printed and then take a snapshot. Since the melt filament may leak from the nozzle during the process of taking a snapshot, a prime tower is required for smooth mode to wipe the nozzle." -msgstr "На протяжении всей печати встроенная камера делает снимки, которые затем объединяются в ускоренное видео. Избыточные резкие движения в кадре можно сгладить при помощи соответствующего режима; после печати каждого слоя для создания снимка экструдер будет отводиться к лотку для удаления излишков. В этом режиме необходима черновая башня для устранения возможных подтёков во время создания снимка." +msgstr "На протяжении всей печати в конце слоя встроенная камера делает снимки, которые затем объединяются в ускоренное видео. Избыточные резкие движения в кадре можно сгладить при помощи «Плавного» режима, в котором для создания снимка экструдер будет отводиться к лотку для сброса материала. В этом режиме необходима черновая башня для устранения возможных подтёков во время создания снимка." msgid "Traditional" -msgstr "По умолчанию" +msgstr "Обычный" +# Для кнопки "Сгладить" добавили контекст, теперь их можно разделить. msgid "Smooth" -msgstr "Сгладить" +msgstr "Плавный" -# AI Translated msgid "Farthest point timelapse" -msgstr "Таймлапс из дальней точки" +msgstr "Съёмка из дальней точки" -# AI Translated msgid "When enabled, the timelapse snapshot is taken at the farthest point from camera instead of traveling to the wipe tower or excess chute. Only effective in traditional timelapse mode on non-I3 printers." -msgstr "Когда включено, снимок таймлапса делается из наиболее удалённой от камеры точки вместо перемещения к черновой башне или лотку сброса излишков. Действует только в традиционном режиме таймлапса на принтерах, отличных от I3." +msgstr "Делать снимки из наиболее удалённой от камеры точки вместо перемещения к черновой башне или лотку для сброса материала. Работает только в обычном режиме таймлапса на принтерах с кинематикой, отличной от I3." msgid "Temperature variation" msgstr "Разница температур" @@ -17096,10 +16916,10 @@ msgid "Enable this option to omit the custom Change filament G-code only at the msgstr "Полезно для смены материала вручную при совместной печати через общий экструдер, где для этого используются команды M600/PAUSE. Отключает выполнение «G-кода смены материала» в самом начале печати (обычно это не требуется, так как пруток уже заправлен). Команда смены инструмента (например, T0) будет пропускаться на протяжении всей печати." msgid "Wipe tower type" -msgstr "Тип башни очистки" +msgstr "Тип черновой башни" msgid "Choose the wipe tower implementation for multi-material prints. Type 1 is recommended for Bambu and Qidi printers with a filament cutter. Type 2 offers better compatibility with multi-tool and MMU printers and provide overall better compatibility." -msgstr "Выберите реализацию башни очистки для многоматериальной печати. Тип 1 рекомендуется для принтеров Bambu и Qidi с обрезчиком филамента. Тип 2 обеспечивает лучшую совместимость с многоинструментальными и MMU-принтерами и в целом более универсален." +msgstr "Выбор реализации черновой башни при печати несколькими материалами. Тип 1 рекомендуется для принтеров Bambu и Qidi с обрезкой прутка. Тип 2 – универсальный вариант с поддержкой широкого спектра принтеров (в т.ч. с системами смены материала и инструментов)." msgid "Type 1" msgstr "Тип 1" @@ -17736,24 +17556,22 @@ msgstr "" "\n" "Примечание: влияет только на принтеры Bambu, в остальных случаях башня автоматически сужается по необходимости." -# ??? настройка отключена в коде +# настройка отключена в коде msgid "Purging volumes" msgstr "Объём прочистки" -# ??? настройка отключена в коде +# настройка отключена в коде msgid "Flush multiplier" msgstr "Множитель прочистки" msgid "The actual flushing volumes is equal to the flush multiplier value multiplied by the flushing volumes in the table." msgstr "Реальные объёмы прочистки равны произведению множителя и значений, указанных в таблице." -# AI Translated msgid "Flush multiplier (Fast mode)" msgstr "Множитель прочистки (быстрый режим)" -# AI Translated msgid "The flush multiplier used in fast purge mode." -msgstr "Множитель прочистки, используемый в режиме быстрой прочистки." +msgstr "Множитель для режима быстрой прочистки." msgid "Prime volume" msgstr "Объём сброса материала на черновой башне" @@ -17761,24 +17579,20 @@ msgstr "Объём сброса материала на черновой баш msgid "This is the volume of material to prime the extruder with on the tower." msgstr "Объём материала, который необходимо выдавить для подготовки экструдера на черновой башне." -# AI Translated msgid "Prime volume mode" -msgstr "Режим объёма подготовки" +msgstr "Режим прочистки" -# AI Translated msgid "Selects how the wipe-tower prime and flush volumes are computed on multi-extruder printers." -msgstr "Определяет, как вычисляются объёмы подготовки и прочистки черновой башни на многоэкструдерных принтерах." +msgstr "Режим расчёта прочистки на черновой башне для многоэкструдерных принтеров." -# AI Translated msgid "Saving" msgstr "Экономия" -# AI Translated msgid "Fast" msgstr "Быстрый" msgid "This is the width of prime towers." -msgstr "Размер черновой башни по оси X. Размер по оси Y будет автоматически вычислен исходя из необходимого объёма очистки и ширины башни. Таким образом, увеличивая ширину башни вы уменьшаете её длину и наоборот." +msgstr "Размер черновой башни по оси X. Размер по оси Y будет автоматически вычислен исходя из необходимого объёма прочистки и ширины башни. Таким образом, увеличивая ширину башни вы уменьшаете её длину и наоборот." msgid "Wipe tower rotation angle" msgstr "Угол поворота черновой башни" @@ -17810,7 +17624,7 @@ msgid "" "For the wipe tower external perimeters the internal perimeter speed is used regardless of this setting." msgstr "" "Максимальная скорость печати при очистке в черновую башню и печати её разреженных слоёв.\n" -"Во время очистки программа сопоставляет скорость разреженного заполнения и скорость, рассчитанную по 'максимальному объёмному расходу', и использует наименьшую.\n" +"Во время прочистки программа сопоставляет скорость разреженного заполнения и скорость, рассчитанную по 'максимальному объёмному расходу', и использует наименьшую.\n" "При печати разреженных слоёв программа сопоставляет скорость внутренних периметров и скорость, рассчитанную по 'максимальному объёмному расходу', и также использует наименьшую.\n" "\n" "Увеличение этой скорости может повлиять на устойчивость башни, а также увеличить силу, с которой сопло сталкивается с любыми наплывами, которые могли образоваться на черновой башне.\n" @@ -17844,7 +17658,7 @@ msgid "Extra rib length" msgstr "Вынос основания ребра" msgid "Positive values can increase the size of the rib wall, while negative values can reduce the size. However, the size of the rib wall can not be smaller than that determined by the cleaning volume." -msgstr "Положительное значение может увеличить длину ребра, а отрицательное - уменьшить. Однако она не может быть меньше размера, определяемого объёмом очистки." +msgstr "Положительное значение может увеличить длину ребра, а отрицательное - уменьшить. Однако она не может быть меньше размера, определяемого объёмом прочистки." msgid "Rib width" msgstr "Ширина ребра" @@ -18106,79 +17920,62 @@ msgstr "" "\n" "Примечание: периметр может расширяться до ширины элемента." -# AI Translated msgid "Hotend change time" msgstr "Время смены хотэнда" -# AI Translated msgid "Time to change hotend." -msgstr "Время смены хотэнда." +msgstr "Время, затрачиваемое на смену хотэнда." -# AI Translated msgid "Hotend change" msgstr "Смена хотэнда" -# AI Translated msgid "When changing the hotend, it is recommended to extrude a certain length of filament from the original nozzle. This helps minimize nozzle oozing." -msgstr "При смене хотэнда рекомендуется выдавить определённую длину материала из исходного сопла. Это помогает минимизировать вытекание из сопла." +msgstr "При смене хотэнда рекомендуется выдавить немного материала из прежнего сопла. Помогает минимизировать последующие подтёки." -# AI Translated msgid "Extruder change" msgstr "Смена экструдера" msgid "To prevent oozing, the nozzle will perform a reverse travel movement for a certain period after the ramming is complete. The setting define the travel time." -msgstr "Чтобы материал не подтекал, материал после рэмминга немного отъезжает назад. Этот параметр задаёт время движения в обратном направлении." +msgstr "Время движения сопла в обратном направлении во избежание подтёков из него. Выполняется по завершении рэмминга." msgid "To prevent oozing, the nozzle temperature will be cooled during ramming. Therefore, the ramming time must be greater than the cooldown time. 0 means disabled." -msgstr "Для предотвращения подтекания материала, температура сопла будет снижена во время рэмминга. Поэтому время рэмминга должно быть больше времени охлаждения. 0 значит отключено." +msgstr "Во избежание подтёков температура сопла будет снижена на время рэмминга. Поэтому время рэмминга должно быть больше времени охлаждения. 0 значит отключено." -# AI Translated msgid "The maximum volumetric speed for ramming before extruder change, where -1 means using the maximum volumetric speed." -msgstr "Максимальный объёмный расход при рэмминге перед сменой экструдера, где -1 означает использование максимального объёмного расхода." +msgstr "Максимальный объёмный расход для рэмминга перед сменой экструдера.\n-1 – использовать максимальный расход." -# AI Translated msgid "To prevent oozing, the nozzle temperature will be cooled during ramming. Note: only a cooldown command and fan activation are triggered, reaching the target temperature is not guaranteed. 0 means disabled." -msgstr "Во избежание вытекания температура сопла будет снижена во время рэмминга. Примечание: срабатывают только команда охлаждения и включение вентилятора; достижение целевой температуры не гарантируется. 0 означает отключено." +msgstr "Во избежание подтёков температура сопла будет снижена на время рэмминга.\n0 – не менять температуру.\n\nПримечание: срабатывают только команда охлаждения и включение вентилятора; достижение целевой температуры не гарантируется." -# AI Translated msgid "The maximum volumetric speed for ramming before a hotend change, where -1 means using the maximum volumetric speed." -msgstr "Максимальный объёмный расход при рэмминге перед сменой хотэнда, где -1 означает использование максимального объёмного расхода." +msgstr "Максимальный объёмный расход для рэмминга перед сменой хотэнда.\n-1 – использовать максимальный расход." -# AI Translated msgid "length when change hotend" -msgstr "длина при смене хотэнда" +msgstr "Откат при смене хотэнда" -# AI Translated msgid "When this retraction value is modified, it will be used as the amount of filament retracted inside the hotend before changing hotends." -msgstr "При изменении этого значения отката оно будет использоваться как величина отката материала внутри хотэнда перед сменой хотэндов." +msgstr "Величина отката материала внутри хотэнда перед его сменой." -# AI Translated msgid "Support fast purge mode" -msgstr "Поддержка режима быстрой прочистки" +msgstr "Режим быстрой прочистки" -# AI Translated msgid "Whether this printer supports fast purge mode with optimized temperature and multiplier." -msgstr "Поддерживает ли этот принтер режим быстрой прочистки с оптимизированной температурой и множителем." +msgstr "Поддерживает ли принтер режим быстрой прочистки с оптимизированной температурой и множителем." -# AI Translated msgid "Filament change" msgstr "Смена материала" -# AI Translated msgid "The volume of material required to prime the extruder on the tower, excluding a hotend change." -msgstr "Объём материала, необходимый для подготовки экструдера на башне, исключая смену хотэнда." +msgstr "Объём материала, необходимый для прочистки экструдера на башне, не считая смены хотэнда." -# AI Translated msgid "The volume of material required to prime the extruder for a hotend change on the tower." -msgstr "Объём материала, необходимый для подготовки экструдера при смене хотэнда на башне." +msgstr "Объём материала, необходимый для прочистки экструдера на башне при смене хотэнда." -# AI Translated msgid "Preheat temperature delta" -msgstr "Дельта температуры предварительного нагрева" +msgstr "Дельта преднагрева" -# AI Translated msgid "Temperature delta applied during pre-heating before tool change." -msgstr "Дельта температуры, применяемая при предварительном нагреве перед сменой инструмента." +msgstr "Разница температуры для предварительного нагрева перед сменой инструмента." msgid "Detect narrow internal solid infills" msgstr "Оптимизация заполнения узких мест" @@ -18301,11 +18098,11 @@ msgstr "Экспорт настроек в файл." # командная строка? нужен ли пеевод? msgid "Send progress to pipe" -msgstr "Отправлять прогресс в канал" +msgstr "Send progress to pipe" # ??? это относится к командной строке msgid "Send progress to pipe." -msgstr "Отправлять прогресс в канал." +msgstr "Send progress to pipe." msgid "Arrange Options" msgstr "Параметры расстановки" @@ -18455,15 +18252,14 @@ msgstr "" msgid "Log file" msgstr "Файл журнала" -# AI Translated msgid "Redirects debug logging to file.\n" -msgstr "Перенаправляет отладочный журнал в файл.\n" +msgstr "Направляет отладочные записи в файл.\n" msgid "Enable timelapse for print" msgstr "Вкл. таймлапс для печати" msgid "If enabled, this slicing will be considered using timelapse." -msgstr "Если включено, текущая нарезка будет выполнена с учётом функции таймлапса." +msgstr "Выполнять нарезку с учётом записи таймлапса." msgid "Load custom G-code" msgstr "Загрузить пользовательский G-код" @@ -18471,7 +18267,7 @@ msgstr "Загрузить пользовательский G-код" msgid "Load custom G-code from json." msgstr "Загрузить G-код из json." -# ??? назначить идентификаторы +# назначить идентификаторы msgid "Load filament IDs" msgstr "Загрузить идентификаторы материалов" @@ -18481,7 +18277,6 @@ msgstr "Загрузить идентификаторы материалов д msgid "Allow multiple colors on one plate" msgstr "Игнорировать разницу в цвете" -# ???? msgid "If enabled, Arrange will allow multiple colors on one plate." msgstr "Если включено, модели разных цветов не будут разделяться на разные столы." @@ -18530,9 +18325,8 @@ msgstr "Список значений метаданных, добавляемы msgid "Allow 3MF with newer version to be sliced" msgstr "Разрешить нарезку 3MF более новой версии" -# ??? msgid "Allow 3MF with newer version to be sliced." -msgstr "Разрешить нарезку новых версий 3MF-файлов." +msgstr "Разрешить нарезку проектов из более новых версий." msgid "Current Z-hop" msgstr "Подъём оси Z" @@ -18877,13 +18671,13 @@ msgid "" "An object's XY size compensation will not be used because it is also color-painted.\n" "XY Size compensation cannot be combined with color-painting." msgstr "" -"Коррекция горизонтальных размеров модели не будет действовать, поскольку для этой модели была выполнена операция окрашивания.\n" -"Коррекция горизонтальных размеров модели не может использоваться в сочетании с функцией раскрашивания." +"Функция «Расширение контура/пустот слоя» игнорируется.\n" +"Коррекцию невозможно выполнить для нескольких материалов в окрашенной модели." msgid "" "An object has enabled XY Size compensation which will not be used because it is also fuzzy skin painted.\n" "XY Size compensation cannot be combined with fuzzy skin painting." -msgstr "Функция «Расширение контура слоя» игнорируется. Коррекцию контура слоя невозможно выполнить, если его часть принадлежит нечёткой оболочке." +msgstr "Функция «Расширение контура/пустот слоя» игнорируется. Коррекцию невозможно выполнить, если часть слоя принадлежит нечёткой оболочке." msgid "Object name" msgstr "Имя модели" @@ -19034,7 +18828,7 @@ msgstr "" #, c-format, boost-format msgid "Only one of the results with the same name: %s will be saved. Are you sure you want to override the other results?" -msgstr "Будет сохранён только один из одноимённых результатов (%s). Вы действительно хотите перезаписать остальные?" +msgstr "Будет сохранён только один из одноимённых результатов (%s). Перезаписать остальные?" #, c-format, boost-format msgid "There is already a previous calibration result with the same name: %s. Only one result with a name is saved. Are you sure you want to overwrite the previous result?" @@ -19045,7 +18839,7 @@ msgid "" "Within the same extruder, the name(%s) must be unique when the filament type, nozzle diameter, and nozzle flow are the same.\n" "Are you sure you want to override the historical result?" msgstr "" -"Для одного экструдера имя (%s) должно быть уникальным, если тип материала, диаметр сопла и поток одинаковы.\n" +"В рамках одного экструдера имя (%s) должно быть уникальным, если тип материала, диаметр сопла и поток одинаковы.\n" "Перезаписать прошлый результат?" #, c-format, boost-format @@ -19177,13 +18971,11 @@ msgstr "Введите имя для сохранения на принтере. msgid "The name cannot exceed 40 characters." msgstr "Максимальная длина имени 40 символов." -# AI Translated msgid "Nozzle ID" msgstr "ID сопла" -# AI Translated msgid "Standard Flow" -msgstr "Стандартный расход" +msgstr "Обычный расход" msgid "Please find the best line on your plate" msgstr "Пожалуйста, найдите лучшую линию на столе" @@ -19350,7 +19142,7 @@ msgstr "История успешных результатов калибров msgid "Refreshing the previous Flow Dynamics Calibration records" msgstr "Обновление записей прошлых калибровок динамики потока" -# AI Translated +# Подставляется toolhead_display_name #, c-format, boost-format msgid "Note: The hotend number on the %s is tied to the holder. When the hotend is moved to a new holder, its number will update automatically." msgstr "Примечание: номер хотэнда на %s привязан к держателю. При перемещении хотэнда в новый держатель его номер обновится автоматически." @@ -19367,7 +19159,7 @@ msgstr "Редактировать калибровку динамики пот #, c-format, boost-format msgid "Within the same extruder, the name '%s' must be unique when the filament type, nozzle diameter, and nozzle flow are identical. Please choose a different name." -msgstr "Для одного экструдера имя «%s» должно быть уникальным при одинаковых типе филамента, диаметре и потоке сопла. Пожалуйста, выберите другое имя." +msgstr "В рамках одного экструдера имя (%s) должно быть уникальным, если тип материала, диаметр сопла и поток одинаковы. Укажите другое имя." msgid "New Flow Dynamic Calibration" msgstr "Новая калибровка динамики потока" @@ -19413,6 +19205,20 @@ msgstr "" "По имени хоста %1% обнаружено несколько IP-адресов.\n" "Выберите адрес для использования." +# В калибровке температуры и расхода +msgid "Auto-scale for nozzle" +msgstr "Адаптация к соплу" + +# Речь о температурной башне +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Тестовая модель рассчитана на сопло 0,4 мм и высоту слоя 0,2 мм.\n" +"При включении адаптации (рекомендуется) её размер динамически подстраивается под диаметр текущего сопла и подходящую высоту слоя, благодаря чему тест получается более точным и читаемым.\n" +"Отключать имееет смысл для печати эталонной модели ровно в исходном виде." + # В заголовке окна куча места msgid "PA Calibration" msgstr "Калибровка Pressure Advance" @@ -19549,6 +19355,15 @@ msgstr "Начальная скорость: " msgid "End speed: " msgstr "Конечная скорость: " +msgid "Auto-adjust to max volumetric speed" +msgstr "Адаптация к расходу" + +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "" +"Автоматически уменьшать высоту слоя для обеспечения требуемой скорости. Позволяет не упираться в предел объёмного расхода материала.\n" +"\n" +"Примечание: скорость всё равно может снижаться в случае упора в минимальную высоту слоя из заданных ограничений принтера." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -19560,6 +19375,50 @@ msgstr "" "Шаг ≥ 0\n" "Конечное > начальное + шаг" +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"Конечная скорость (%.0f мм/с) приводит к превышению предела объёмного расхода материала (%.1f мм³/с). При такой ширине линии периметров и высоте слоя расход ограничивает линейную скорость примерно до %.0f мм/с, и верхние сегменты башни не смогут достичь заданной скорости.\n" +"\n" +"%s" + +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"Конечная скорость (%.0f мм/с) приводит к превышению предела объёмного расхода материала (%.1f мм³/с) при высоте слоя по умолчанию (%.2f мм).\n" +"\n" +"Высота слоя уменьшена до %.2f мм (минимально значение из профиля принтера), чтобы башня могла достичь заданной скорости." + +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Конечная скорость (%.0f мм/с) приводит к превышению предела объёмного расхода материала (%.1f мм³/с) даже при минимально допустимой высоте слоя (в соответствии с профилем принтера, %.2f мм).\n" +"\n" +"Высота слоя будет установлена на %.2f мм, а конечная скорость снижена до %.0f мм/с.\n" +"\n" +"Продолжить?" + +msgid "Continue anyway?" +msgstr "Всё равно продолжить?" + +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Включить адаптацию к расходу для автоматического исправления?\nНет – игнорировать предупреждение." + +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Включить адаптацию к соплу и расходу для автоматического исправления?\nНет – игнорировать предупреждение." + msgid "Start retraction length: " msgstr "Начальная длина отката: " @@ -20056,10 +19915,10 @@ msgid "Create Nozzle for Existing Printer" msgstr "Сопло для принтера" msgid "Create from Template" -msgstr "Создать из шаблона" +msgstr "Создать из общих шаблонов" msgid "Create Based on Current Printer" -msgstr "Создать на основе профиля выбранного принтера" +msgstr "Создать из профилей производителя" msgid "Import Preset" msgstr "Импорт профиля" @@ -20188,8 +20047,8 @@ msgid "" "The system preset does not allow creation. \n" "Please re-enter the printer model or nozzle diameter." msgstr "" -"Системный профиль не допускает создания.\n" -"Пожалуйста, повторно введите модель принтера или диаметр сопла." +"Имя совпадает с системным профилем.\n" +"Назовите модель принтера или диаметр сопла иначе." msgid "" "\n" @@ -20383,11 +20242,12 @@ msgid "" "All the filament presets belong to this filament would be deleted.\n" "If you are using this filament on your printer, please reset the filament information for that slot." msgstr "" -"Все профили прутка, относящиеся к этому материалу, будут удалены.\n" -"Если вы используете этот пруток в принтере, пожалуйста, сбросьте информацию о прутке для этого слота." +"Все профили, относящиеся к этому материалу, будут удалены.\n" +"Если вы используете его в принтере, сбросьте информацию о\n" +"нём у соответствующего слота." msgid "Delete filament" -msgstr "Удаление прутка" +msgstr "Удаление материала" msgid "Add Preset" msgstr "Добавить профиль" @@ -20396,13 +20256,13 @@ msgid "Add preset for new printer" msgstr "Добавление профиля для нового принтера" msgid "Copy preset from filament" -msgstr "Копировать профиль из прутка" +msgstr "Копировать профиль из материала" msgid "The filament choice not find filament preset, please reselect it" -msgstr "Не удалось найти профиль прутка. Выберите его повторно" +msgstr "Не удалось найти профиль материала. Выберите его повторно" msgid "[Delete Required]" -msgstr "[Необходимо удалить]" +msgstr "[Требуется удаление]" msgid "Edit Preset" msgstr "Изменить профиль" @@ -20469,8 +20329,8 @@ msgid "" "The currently selected nozzle type of %s extruder does not match the actual printer nozzle type.\n" "Please click the Sync button above and restart the calibration." msgstr "" -"Выбранный тип сопла экструдера %s не соответствует фактическому типу сопла принтера.\n" -"Нажмите кнопку «Синхронизация» выше и перезапустите калибровку." +"Выбранный тип сопла экструдера (%s) не соответствует фактическому типу сопла принтера.\n" +"Нажмите кнопку синхронизации выше и перезапустите калибровку." msgid "Unable to calibrate: maybe because the set calibration value range is too large, or the step is too small" msgstr "Невозможно выполнить калибровку: возможно, установленный диапазон значений калибровки слишком велик или шаг слишком мал" @@ -21132,11 +20992,9 @@ msgstr "Ошибка печати" msgid "Removed" msgstr "Удалено" -# AI Translated msgid "Enable smart filament assign: Assign one filament to multiple nozzles to maximize savings" -msgstr "Включить умное назначение материалов: назначайте один материал нескольким соплам для максимальной экономии" +msgstr "Включить умное назначение материалов: назначить один материал нескольким соплам для максимальной экономии" -# AI Translated msgid "Fila Saving" msgstr "Экономия материала" @@ -21175,10 +21033,10 @@ msgstr "Видеоурок" msgid "(Sync with printer)" msgstr " (состояние принтера)" -# AI Translated +# Отвратительная подстановка левое/правое и тип расхода сопла #, c-format, boost-format msgid "Error: %s extruder has no available %s nozzle, current group result is invalid." -msgstr "Ошибка: у экструдера %s нет доступного сопла %s, текущий результат группировки недействителен." +msgstr "Ошибка: %s сопло не поддерживает требуемый расход (%s), результат текущей группировки недействителен." msgid "We will slice according to this grouping method:" msgstr "Осуществлять нарезку в соответствии с этой группировкой:" @@ -21186,15 +21044,12 @@ msgstr "Осуществлять нарезку в соответствии с msgid "Tip: You can drag the filaments to reassign them to different nozzles." msgstr "Совет: для назначения материала перетащите его в нужное поле." -# AI Translated msgid "Please adjust your grouping or click " -msgstr "Отрегулируйте группировку или нажмите " +msgstr "Измените группировку или нажмите " -# AI Translated msgid " to set nozzle count" msgstr " для задания количества сопел" -# AI Translated msgid "Set the physical nozzle count..." msgstr "Задать физическое количество сопел..." @@ -21431,7 +21286,7 @@ msgid "Skipping objects." msgstr "Исключение объектов." msgid "Select Filament" -msgstr "Выбрать филамент" +msgstr "Выбрать материал" msgid "Null Color" msgstr "Цвет не задан" @@ -21464,7 +21319,7 @@ msgstr "Ошибка: %s" msgid "Show details" msgstr "Подробнее" -# AI Translated +# В информации о сетевом плагине msgid "Hide details" msgstr "Скрыть подробности" @@ -21493,9 +21348,8 @@ msgstr "Установить обновление" msgid "(Latest)" msgstr "(новейшая)" -# AI Translated msgid "(installed)" -msgstr "(установлено)" +msgstr "(установлена)" msgid "The Bambu Network Plug-in has been installed successfully." msgstr "Сетевой плагин Bambu успешно установлен." @@ -21547,7 +21401,6 @@ msgstr "Сохранить как настройки по умолчанию" msgid "If enabled, the values above are stored as the defaults used for future STEP imports (and shown in Preferences)." msgstr "Активируйте для сохранения настроек импорта после его завершения." -# AI Translated msgid "PresetBundle" msgstr "PresetBundle" @@ -21574,7 +21427,6 @@ msgstr "Удаление пакета" msgid "Unsubscribe bundle?" msgstr "Отписаться от пакета?" -# AI Translated msgid "UnsubscribeBundle" msgstr "UnsubscribeBundle" @@ -21585,11 +21437,9 @@ msgstr "Не удалось отписаться от пакета." msgid "Unsubscribe Bundle" msgstr "Ошибка" -# AI Translated msgid "ExportPresetBundle" msgstr "ExportPresetBundle" -# AI Translated msgid "Save preset bundle" msgstr "Сохранить пакет профилей" @@ -21643,190 +21493,146 @@ msgstr "Просмотр архива" msgid "Open File" msgstr "Открыть файл" -# AI Translated msgid "AMS Dryness Control" msgstr "Управление сушкой AMS" -# AI Translated msgid "Filament Drying Settings" msgstr "Настройки сушки материала" -# AI Translated msgid "Stopping" msgstr "Остановка" -# AI Translated msgid "Unable to dry temporarily due to ..." msgstr "Временно невозможно выполнить сушку из-за ..." -# AI Translated msgid "Drying Error" msgstr "Ошибка сушки" -# AI Translated msgid "Please check the Assistant for troubleshooting" msgstr "Обратитесь к Помощнику для устранения неполадок" -# AI Translated msgid "Please remove and store the filament (as shown)." msgstr "Извлеките и уберите материал на хранение (как показано)." -# AI Translated msgid "The AMS can rotate the filament which is properly stored, providing better drying results." -msgstr "AMS может вращать правильно уложенный на хранение материал, обеспечивая лучший результат сушки." +msgstr "AMS может вращать правильно уложенный на хранение материал, тем самым улучшая эффективность сушки." -# AI Translated msgid "Rotate spool when drying" msgstr "Вращать катушку при сушке" -# AI Translated msgctxt "amsdrying" msgid "Back" msgstr "Назад" -# AI Translated msgid "Drying-Heating" msgstr "Сушка — нагрев" -# AI Translated msgid "Drying-Dehumidifying" -msgstr "Сушка — осушение" +msgstr "Сушка — вывод влаги" -# AI Translated msgid " maximum drying temperature is " msgstr " максимальная температура сушки — " -# AI Translated msgid " minimum drying temperature is " msgstr " минимальная температура сушки — " -# AI Translated msgid "This filament may not be completely dried." -msgstr "Этот материал может быть высушен не полностью." +msgstr "Сушка этого материала может не быть эффективной." -# AI Translated msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature." -msgstr "Этот AMS сейчас печатает. Для обеспечения качества печати температура сушки не может превышать рекомендованную температуру сушки." +msgstr "AMS сейчас печатает. Во избежание проблем с печатью температура сушки не должна превышать рекомендованную." -# AI Translated msgid "The temperature shall not exceed the filament's heat distortion temperature" -msgstr "Температура не должна превышать температуру тепловой деформации материала" +msgstr "Температура сушки не должна превышать температуру размягчения материала." -# AI Translated msgid "Minimum time value cannot be less than 1." -msgstr "Минимальное значение времени не может быть меньше 1." +msgstr "Минимальное время не может быть меньше 1." -# AI Translated msgid "Maximum time value cannot be greater than 24." -msgstr "Максимальное значение времени не может быть больше 24." +msgstr "Максимальное время не может быть больше 24." -# AI Translated msgid "Insufficient power" -msgstr "Недостаточно питания" +msgstr "Нехватка мощности" -# AI Translated msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting." -msgstr " Слишком много AMS сушат одновременно. Подключите питание или остановите другие процессы сушки перед началом." +msgstr " Слишком много AMS выполняют сушку. Подключите питание или остановите другие сеансы сушки перед началом." -# AI Translated msgid "AMS is busy" -msgstr "AMS занят" +msgstr "AMS занята" -# AI Translated msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait." -msgstr " AMS калибруется | считывает RFID | загружает/выгружает материал, подождите." +msgstr " AMS калибруется | считывает RFID | меняет материал, подождите." -# AI Translated +# на Вики бамбу есть упоминание: https://wiki.bambulab.com/ru/h2/troubleshooting/hmscode/0700_2000_0002_0025#:~:text=выходного%20отверстия%20AMS msgid "Filament in AMS outlet" msgstr "Материал в выходном отверстии AMS" -# AI Translated msgid " The high drying temperature may cause AMS blockage, please unload first." -msgstr " Высокая температура сушки может вызвать засорение AMS, сначала выгрузите материал." +msgstr " Из-за высокой температуры сушки пруток может застрять в AMS, сначала выгрузите материал." -# AI Translated msgid "Initiating AMS drying" msgstr "Запуск сушки AMS" -# AI Translated msgid "Not supported in 2D mode" -msgstr "Не поддерживается в режиме 2D" +msgstr "Не поддерживается в 2D-режиме" -# AI Translated msgid "Task in progress" msgstr "Выполняется задача" -# AI Translated +# CannotDryReason: DryingInProgress msgid " The AMS might be in use during Task." -msgstr " AMS может использоваться во время задачи." +msgstr " AMS может иметь задачи в процессе." -# AI Translated msgid " Firmware update in progress, please wait..." msgstr " Выполняется обновление прошивки, подождите..." -# AI Translated msgid " Please plug in the power and then use the drying function." msgstr " Подключите питание, а затем используйте функцию сушки." -# AI Translated msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding." -msgstr " Высокая температура сушки может вызвать засорение AMS. Перед продолжением выгрузите материал вручную." +msgstr " Из-за высокой температуры сушки пруток может застрять в AMS. Перед продолжением выгрузите материал вручную." -# AI Translated msgid "System is busy" msgstr "Система занята" -# AI Translated msgid " Initiating other drying processes, please wait a few seconds..." msgstr " Запускаются другие процессы сушки, подождите несколько секунд..." -# AI Translated msgid "For better drying results, remove the filament and allow it to rotate." -msgstr "Для лучшего результата сушки извлеките материал и дайте ему вращаться." +msgstr "Для лучшего результата сушки извлеките материал и включите вращение катушки." -# AI Translated msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance." -msgstr "AMS будет автоматически вращать слоты с уложенным на хранение материалом для повышения эффективности сушки." +msgstr "AMS будет автоматически вращать слоты с хранящимися катушками для повышения эффективности сушки." -# AI Translated msgid "Alternatively, you can dry the filament without removing it." -msgstr "Кроме того, вы можете сушить материал, не извлекая его." +msgstr "Кроме того, сушить материал можно без его извлечения." -# AI Translated msgid "Unknown filaments will be treated as PLA." msgstr "Неизвестные материалы будут рассматриваться как PLA." -# AI Translated msgid "Please store the filament marked with an exclamation mark." msgstr "Уберите на хранение материал, отмеченный восклицательным знаком." -# AI Translated msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU." -msgstr "Материал, оставленный в подающем механизме во время сушки, может размягчиться, поскольку температура сушки превышает точку размягчения таких материалов, как PLA и TPU." +msgstr "Заправленный материал может размягчиться во время сушки, поскольку её сушки превышает точку размягчения материалов вроде PLA и TPU." -# AI Translated msgid "Starting: Checking adapter connection" msgstr "Запуск: проверка подключения адаптера" -# AI Translated msgid "Starting: Checking filament status" msgstr "Запуск: проверка состояния материала" -# AI Translated msgid "Starting: Checking drying presets" msgstr "Запуск: проверка профилей сушки" -# AI Translated msgid "Starting: Checking filament location" msgstr "Запуск: проверка расположения материала" -# AI Translated msgid "Starting: Checking air intake" msgstr "Запуск: проверка забора воздуха" -# AI Translated msgid "Starting: Checking air vent" -msgstr "Запуск: проверка вентиляционного отверстия" +msgstr "Запуск: проверка вентиляции" msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used." msgstr "Материал может быть несовместим с текущими настройками принтера. Будет использоваться базовый профиль материала." @@ -21836,14 +21642,14 @@ msgstr "Материал может быть несовместим с теку # подобных). Она задаётся вручную в файле профиля (производителем) и # отсутствует у большинства системных профилей. msgid "The filament model is unknown. Still using the previous filament preset." -msgstr "Модель филамента неизвестна. Используется предыдущий профиль филамента." +msgstr "Модель материала неизвестна. Используется предыдущий профиль материала." # Не знаю, что за "модель" материала, пропускаю. Возможно, имеется ввиду # модель коррекции объёмного расхода для функции адаптивного расхода у TPU (и # подобных). Она задаётся вручную в файле профиля (производителем) и # отсутствует у большинства системных профилей. msgid "The filament model is unknown. Generic filament presets will be used." -msgstr "Модель филамента неизвестна. Будут использованы стандартные профили филамента." +msgstr "Модель материала неизвестна. Будут использованы стандартные профили материала." msgid "The filament may not be compatible with the current machine settings. A random filament preset will be used." msgstr "Материал может быть несовместим с текущими настройками принтера. Будет использоваться случайный профиль материала." @@ -21853,7 +21659,7 @@ msgstr "Материал может быть несовместим с теку # подобных). Она задаётся вручную в файле профиля (производителем) и # отсутствует у большинства системных профилей. msgid "The filament model is unknown. A random filament preset will be used." -msgstr "Модель филамента неизвестна. Будет использован случайный профиль филамента." +msgstr "Модель материала неизвестна. Будет использован случайный профиль материала." #: resources/data/hints.ini: [hint:Precise wall] msgid "" @@ -22153,6 +21959,9 @@ msgstr "" "Предотвращение коробления материала\n" "Знаете ли вы, что при печати материалами, склонными к короблению, таких как ABS, повышение температуры подогреваемого стола может снизить эту вероятность?" +#~ msgid "Print order within a single layer." +#~ msgstr "Последовательность печати моделей в пределах одного слоя." + #~ msgid "Bottom" #~ msgstr "Снизу" @@ -22226,9 +22035,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Renders cast shadows on the plate in realistic view." #~ msgstr "Отрисовывать тени в режиме продвинутой графики." @@ -22255,9 +22061,6 @@ msgstr "" #~ "\n" #~ "Внимание: несовместимо с принтерами Prusa, поскольку им требуется остановка для изменения коэффициента PA." -#~ msgid "Continue to sync filaments" -#~ msgstr "Продолжить синхронизацию филаментов" - #~ msgctxt "Sync_Nozzle_AMS" #~ msgid "Cancel" #~ msgstr "Отмена" diff --git a/localization/i18n/sv/OrcaSlicer_sv.po b/localization/i18n/sv/OrcaSlicer_sv.po index 4f5d27ad9c..5686fb7d8f 100644 --- a/localization/i18n/sv/OrcaSlicer_sv.po +++ b/localization/i18n/sv/OrcaSlicer_sv.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -4245,6 +4245,10 @@ msgstr "Placerar..." msgid "Arranging" msgstr "Placerar" +# AI Translated +msgid "Arranging " +msgstr "Placerar " + msgid "Arranging canceled." msgstr "Placering avbruten." @@ -9084,24 +9088,24 @@ msgid "Replaced with 3D files from directory:\n" msgstr "Ersatt med 3D-filer från mappen:\n" # AI Translated -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ Hoppade över %1%: samma fil.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ Hoppade över %s: samma fil.\n" # AI Translated -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ Hoppade över %1%: filen finns inte.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ Hoppade över %s: filen finns inte.\n" # AI Translated -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ Hoppade över %1%: det gick inte att ersätta.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ Hoppade över %s: det gick inte att ersätta.\n" # AI Translated -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ Ersatte %1%.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ Ersatte %s.\n" # AI Translated msgid "Replaced volumes" @@ -10187,6 +10191,21 @@ msgstr "Dämpa underliggande lager" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "När du drar i lagerreglaget i den beredda förhandsgranskningen renderas lagren under det aktuella mörkare, så att endast det lager du tittar på visas med full ljusstyrka." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Ljusstyrka för dämpade lager" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"Hur ljust de dämpade lagren återges när \"Dämpa underliggande lager\" är aktiverat.\n" +"99% är knappt mörkare, 0% gör dem helt svarta. Begränsat till 99% eftersom 100% skulle vara detsamma som att stänga av alternativet." + msgid "Login region" msgstr "Logga in region" @@ -14716,13 +14735,37 @@ msgid "Intra-layer order" msgstr "Ordning inom lager" # AI Translated -msgid "Print order within a single layer." -msgstr "Utskriftsordning inom ett enskilt lager." +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Ordningen som objektinstanserna besöks i inom ett och samma lager, vilket avgör hur mycket förflyttning som går åt mellan dem.\n" +"\n" +"Standard: kedjning efter närmaste granne, förfinad med 2-opt och borttagning av korsningar. Ett bra generellt val.\n" +"Som objektlistan: instanserna skrivs ut i samma ordning som i objektlistan, utan någon vägoptimering. Använd det när du behöver en förutsägbar ordning som du styr manuellt.\n" +"Bäst av alla (kortaste vägen): varje strategi utvärderas och den kortaste används. Ordningen för objektinstanserna bestäms en gång för hela utskriften, medan ordningen för enskilda öar bestäms per lager, så olika lager kan sluta med att använda olika strategier. Beredningen blir något långsammare.\n" +"Slingrande: slingrande färdväg rad för rad, förfinad med 2-opt. Passar bra för regelbundna rutnät med många små detaljer.\n" +"\n" +"Med flera filament eller verktyg i samma lager prioriteras att minimera antalet verktygsbyten: objekten grupperas först efter filament och den här inställningen ordnar bara instanserna inom varje filamentgrupp, så den totala sekvensen kanske inte ser ut som den kortaste vägen över plattan." # AI Translated msgid "As object list" msgstr "Som objektlistan" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "Bäst av alla (kortaste vägen)" + +# AI Translated +msgid "Snake" +msgstr "Slingrande" + msgid "Slow printing down for better layer cooling" msgstr "Sakta ner utskrift för bättre kylning av lager" @@ -20823,6 +20866,20 @@ msgstr "" "Det finns flera IP-adresser som pekar på värdnamnet %1%.\n" "Välj vilken som ska användas." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "Autoskala efter nozzel" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Den här modellen är utformad för en nozzel på 0,4 mm med en lagerhöjd på 0,2 mm. \n" +"När skalningsalternativet är aktiverat (rekommenderas) ändras storleken dynamiskt så att den matchar din aktuella nozzeldiameter och en lämplig lagerhöjd, vilket gör testet både noggrant och lättläst.\n" +"Stäng bara av skalningen om du vill skriva ut referensmodellen exakt som den är." + msgid "PA Calibration" msgstr "PA kalibrering" @@ -20969,6 +21026,14 @@ msgstr "Start hastighet: " msgid "End speed: " msgstr "Sluthastighet: " +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "Autojustera till max volymetrisk hastighet" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Om sluthastigheten skulle överskrida filamentets maximala volymetriska hastighet sänks lagerhöjden automatiskt (med bibehållna standardvärden och inom maskinens gränser) för att nå den. Om inte ens den minsta lagerhöjden räcker sänks sluthastigheten i stället." + # AI Translated msgid "" "Please input valid values:\n" @@ -20981,6 +21046,57 @@ msgstr "" "steg >= 0\n" "slut > start + steg" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"Sluthastigheten (%.0f mm/s) överskrider filamentets maximala volymetriska hastighet (%.1f mm³/s), vilket begränsar den yttre väggen till omkring %.0f mm/s vid den här linjebredden och lagerhöjden.\n" +" Högre hastigheter kapas, så tornets övre block skrivs inte ut med den begärda hastigheten.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"Sluthastigheten (%.0f mm/s) överskrider filamentets maximala volymetriska hastighet (%.1f mm³/s) vid standardlagerhöjden (%.2f mm).\n" +"\n" +"Lagerhöjden har sänkts till %.2f mm (ett värde som används av den här skrivarens profiler) så att tornet kan nå den begärda hastigheten." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Även vid den minsta lagerhöjd som används av den här skrivarens profiler (%.2f mm) överskrider sluthastigheten (%.0f mm/s) filamentets maximala volymetriska hastighet (%.1f mm³/s).\n" +"\n" +"Lagerhöjden ställs in på %.2f mm och sluthastigheten sänks till %.0f mm/s.\n" +"\n" +"Vill du fortsätta?" + +# AI Translated +msgid "Continue anyway?" +msgstr "Vill du fortsätta ändå?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Vill du aktivera \"Autojustera\" för att åtgärda detta automatiskt, eller fortsätta ändå?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Vill du aktivera \"Autoskala efter nozzel\" och \"Autojustera\" för att åtgärda detta automatiskt, eller fortsätta ändå?" + msgid "Start retraction length: " msgstr "Starta retraktion längd: " @@ -23955,6 +24071,10 @@ msgstr "" "Undvik vridning\n" "Visste du att när du skriver ut material som är benägna att vrida, såsom ABS, kan en lämplig ökning av värmebäddens temperatur minska sannolikheten för vridning?" +# AI Translated +#~ msgid "Print order within a single layer." +#~ msgstr "Utskriftsordning inom ett enskilt lager." + #~ msgid "Bottom" #~ msgstr "Botten" @@ -24000,9 +24120,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "° C" -#~ msgid "%" -#~ msgstr "%" - #~ msgctxt "Sync_Nozzle_AMS" #~ msgid "Cancel" #~ msgstr "Avbryt" diff --git a/localization/i18n/th/OrcaSlicer_th.po b/localization/i18n/th/OrcaSlicer_th.po index 45352f61a6..a419ba320e 100644 --- a/localization/i18n/th/OrcaSlicer_th.po +++ b/localization/i18n/th/OrcaSlicer_th.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: 2026-06-19 13:40+0700\n" "Last-Translator: Icezaza\n" "Language-Team: Thai\n" @@ -843,7 +843,7 @@ msgid "Hexagon" msgstr "หกเหลี่ยม" msgid "Keep orientation" -msgstr "รักษาปฐมนิเทศ" +msgstr "คงการวางแนว" msgid "Place on cut" msgstr "วางบนการตัด" @@ -891,7 +891,7 @@ msgid "Cut position" msgstr "ตำแหน่งตัด" msgid "Build Volume" -msgstr "ปริมาตรพื้นที่พิมพ์" +msgstr "ปริมาตรการพิมพ์ (Build Volume)" msgid "Multiple" msgstr "หลายรายการ" @@ -1200,7 +1200,7 @@ msgid "Horizontal text" msgstr "ข้อความแนวนอน" msgid "Shift+" -msgstr "กะ+" +msgstr "Shift+" msgid "Mouse move up or down" msgstr "เมาส์เลื่อนขึ้นหรือลง" @@ -2592,7 +2592,7 @@ msgid "Ironing" msgstr "รีดผิว" msgid "Fuzzy skin" -msgstr "ผิวฟัซซี" +msgstr "ผิวฟัซซี (Fuzzy Skin)" msgid "Extruders" msgstr "ชุดดันเส้น" @@ -2817,10 +2817,10 @@ msgid "current" msgstr "ปัจจุบัน" msgid "Scale to build volume" -msgstr "ปรับขนาดเพื่อสร้างปริมาณ" +msgstr "ปรับขนาดให้พอดีกับปริมาตรการพิมพ์" msgid "Scale an object to fit the build volume" -msgstr "ปรับขนาดวัตถุให้พอดีกับปริมาณงานสร้าง" +msgstr "ปรับขนาดวัตถุให้พอดีกับปริมาตรการพิมพ์" msgid "Flush Options" msgstr "ตัวเลือกการไล่เส้น" @@ -2898,10 +2898,10 @@ msgid "Change SVG source file, projection, size, ..." msgstr "เปลี่ยนไฟล์ต้นฉบับ SVG, การฉายภาพ, ขนาด, ..." msgid "Invalidate cut info" -msgstr "ข้อมูลการตัดไม่ถูกต้อง" +msgstr "ยกเลิกข้อมูลการตัด" msgid "Add Primitive" -msgstr "เพิ่มดั้งเดิม" +msgstr "เพิ่มรูปทรงพื้นฐาน" msgid "Add Handy models" msgstr "เพิ่มรุ่นแฮนดี้" @@ -3027,7 +3027,7 @@ msgid "Center" msgstr "กึ่งกลาง" msgid "Drop" -msgstr "หยด" +msgstr "วางลงฐานพิมพ์" msgid "Edit Process Settings" msgstr "แก้ไขการตั้งค่ากระบวนการ" @@ -3182,7 +3182,7 @@ msgid "Switch to per-object setting mode to edit process settings of selected ob msgstr "สลับไปที่โหมดการตั้งค่าต่ออ็อบเจ็กต์เพื่อแก้ไขการตั้งค่ากระบวนการของอ็อบเจ็กต์ที่เลือก" msgid "Remove paint-on fuzzy skin" -msgstr "ลบสีบนผิวที่คลุมเครือ" +msgstr "ลบการระบายสีผิวฟัซซี" # AI Translated msgid "Delete Settings" @@ -3242,7 +3242,7 @@ msgid "Add layers" msgstr "เพิ่มเลเยอร์" msgid "Cut Connectors information" -msgstr "ตัดข้อมูลตัวเชื่อมต่อ" +msgstr "ข้อมูลตัวเชื่อมสำหรับการตัด" msgid "Object manipulation" msgstr "การจัดการวัตถุ" @@ -3279,7 +3279,7 @@ msgid "Layer" msgstr "เลเยอร์" msgid "Selection conflicts" -msgstr "ข้อขัดแย้งในการคัดเลือก" +msgstr "การเลือกขัดแย้งกัน" msgid "If the first selected item is an object, the second should also be an object." msgstr "หากรายการแรกที่เลือกเป็นวัตถุ รายการที่สองก็ควรเป็นวัตถุด้วย" @@ -3390,7 +3390,7 @@ msgid "Plate" msgstr "ฐานพิมพ์" msgid "Brim" -msgstr "ขอบยึดชิ้นงาน" +msgstr "ขอบยึดชิ้นงาน (Brim)" msgid "Object/Part Settings" msgstr "การตั้งค่าวัตถุ/ชิ้นส่วน" @@ -3834,6 +3834,10 @@ msgstr "กำลังจัด..." msgid "Arranging" msgstr "การจัด" +# AI Translated +msgid "Arranging " +msgstr "กำลังจัด " + msgid "Arranging canceled." msgstr "ยกเลิกการจัดเตรียมแล้ว" @@ -4782,7 +4786,7 @@ msgid "" "YES - Keep Prime Tower\n" "NO - Keep Adaptive Layer Height and Independent Support Layer Height" msgstr "" -"ไพรม์ทาวเวอร์ไม่ทำงานเมื่อเปิดใช้งาน Adaptive Layer Height หรือ Independent ส่วนรองรับ Layer Height\n" +"Prime Tower ไม่ทำงานเมื่อเปิดใช้งาน Adaptive Layer Height หรือ Independent ส่วนรองรับ Layer Height\n" "คุณต้องการเก็บอันไหน?\n" "ใช่ - เก็บ Prime Tower ไว้\n" "ไม่ - คงความสูงของเลเยอร์แบบปรับได้และความสูงของเลเยอร์รองรับที่เป็นอิสระ" @@ -4793,7 +4797,7 @@ msgid "" "YES - Keep Prime Tower\n" "NO - Keep Adaptive Layer Height" msgstr "" -"ไพรม์ทาวเวอร์ไม่ทำงานเมื่อเปิด Adaptive Layer Height\n" +"Prime Tower ไม่ทำงานเมื่อเปิด Adaptive Layer Height\n" "คุณต้องการเก็บอันไหน?\n" "ใช่ - เก็บ Prime Tower ไว้\n" "ไม่ - คงความสูงของเลเยอร์แบบปรับได้" @@ -4804,7 +4808,7 @@ msgid "" "YES - Keep Prime Tower\n" "NO - Keep Independent Support Layer Height" msgstr "" -"ไพร์มทาวเวอร์ไม่ทำงานเมื่อเปิดความสูงของเลเยอร์รองรับอิสระ\n" +"Prime Tower ไม่ทำงานเมื่อเปิดความสูงของเลเยอร์รองรับอิสระ\n" "คุณต้องการเก็บอันไหน?\n" "ใช่ - เก็บ Prime Tower ไว้\n" "ไม่ - รักษาความสูงของชั้นรองรับที่เป็นอิสระ" @@ -5377,7 +5381,7 @@ msgid "Pressure Advance" msgstr "แรงดันล่วงหน้า (Pressure Advance)" msgid "Noop" -msgstr "นะ" +msgstr "ไม่มีการดำเนินการ" msgid "Retract" msgstr "ดึงกลับ" @@ -5401,7 +5405,7 @@ msgid "Travel" msgstr "เดินหัวเปล่า" msgid "Wipe" -msgstr "เช็ดหัวฉีด" +msgstr "เช็ดหัวฉีด (Wipe)" msgid "Extrude" msgstr "ฉีดเส้น" @@ -5437,7 +5441,7 @@ msgid "Support interface" msgstr "ผิวสัมผัสส่วนรองรับ" msgid "Prime tower" -msgstr "ทาวเวอร์ไล่เส้น" +msgstr "Prime Tower" msgid "Bottom surface" msgstr "ผิวด้านล่าง" @@ -5482,7 +5486,7 @@ msgid "Jerk: " msgstr "เจิร์ก: " msgid "PA: " -msgstr "พ่อ:" +msgstr "PA: " msgid "mm/s" msgstr "มม./วินาที" @@ -5548,7 +5552,7 @@ msgid "Tips:" msgstr "เคล็ดลับ:" msgid "Current grouping of slice result is not optimal." -msgstr "การจัดกลุ่มผลลัพธ์การแบ่งส่วนในปัจจุบันไม่เหมาะสมที่สุด" +msgstr "การจัดกลุ่มผลการสไลซ์ปัจจุบันยังไม่เหมาะสม" #, boost-format msgid "Increase %1%g filament and %2% changes compared to optimal grouping." @@ -5581,7 +5585,7 @@ msgid "Regroup filament" msgstr "จัดกลุ่มเส้นพลาสติกใหม่" msgid "up to" -msgstr "ขึ้นไป" +msgstr "สูงสุด" msgid "above" msgstr "ข้างบน" @@ -5638,7 +5642,7 @@ msgid "Filament change times" msgstr "จำนวนครั้งที่เปลี่ยนเส้น" msgid "Tool changes" -msgstr "การเปลี่ยนแปลงเครื่องมือ" +msgstr "การเปลี่ยนเครื่องมือ" msgid "Color change" msgstr "เปลี่ยนสี" @@ -5669,7 +5673,7 @@ msgid "Model printing time" msgstr "ระยะเวลาในการพิมพ์โมเดล" msgid "Show stealth mode" -msgstr "แสดงโหมดซ่อนตัว" +msgstr "แสดงโหมดเงียบ" msgid "Show normal mode" msgstr "แสดงโหมดปกติ" @@ -5686,10 +5690,10 @@ msgid "" "Please solve the problem by moving it totally on or off the plate, and confirming that the height is within the build volume." msgstr "" "วัตถุวางอยู่เหนือขอบเขตของแผ่นหรือสูงเกินขีดจำกัดความสูง\n" -"โปรดแก้ไขปัญหาด้วยการเลื่อนเข้าหรือออกจากเพลตโดยสิ้นเชิง และยืนยันว่าความสูงอยู่ภายในปริมาตรงานประกอบ" +"โปรดแก้ไขปัญหาด้วยการเลื่อนเข้าหรือออกจากเพลตโดยสิ้นเชิง และยืนยันว่าความสูงอยู่ภายในปริมาตรการพิมพ์" msgid "Variable layer height" -msgstr "ความสูงของชั้นตัวแปร" +msgstr "ความสูงเลเยอร์แบบแปรผัน" msgid "Adaptive" msgstr "ปรับตัวได้" @@ -5739,7 +5743,7 @@ msgid "Following objects are laid over the boundary of plate or exceeds the heig msgstr "วัตถุต่อไปนี้วางอยู่เหนือขอบเขตของแผ่นหรือสูงเกินขีดจำกัดความสูง:\n" msgid "Please solve the problem by moving it totally on or off the plate, and confirming that the height is within the build volume.\n" -msgstr "โปรดแก้ไขปัญหาด้วยการเลื่อนเข้าหรือออกจากเพลตโดยสิ้นเชิง และยืนยันว่าความสูงอยู่ภายในปริมาตรงานประกอบ\n" +msgstr "โปรดแก้ไขปัญหาด้วยการเลื่อนเข้าหรือออกจากเพลตโดยสิ้นเชิง และยืนยันว่าความสูงอยู่ภายในปริมาตรการพิมพ์\n" #, c-format, boost-format msgid "The position or size of some models exceeds the %s's printable range." @@ -5779,7 +5783,7 @@ msgid "Optimize support interface area" msgstr "ปรับพื้นที่อินเทอร์เฟซส่วนรองรับให้เหมาะสม" msgid "Orient" -msgstr "ตะวันออก" +msgstr "จัดวางแนว" msgid "Arrange options" msgstr "ตัวเลือกจัดเรียง" @@ -5925,7 +5929,7 @@ msgid "Paint Toolbar" msgstr "แถบเครื่องมือสี" msgid "Explosion Ratio" -msgstr "อัตราส่วนการระเบิด" +msgstr "ระดับการแยกชิ้นส่วน" msgid "Section View" msgstr "มุมมองส่วน" @@ -5998,7 +6002,7 @@ msgid "PLA and PETG filaments detected in the mixture. Adjust parameters accordi msgstr "ตรวจพบเส้นพลาสติก PLA และ PETG ในส่วนผสม ปรับพารามิเตอร์ตาม Wiki เพื่อรับรองคุณภาพการพิมพ์" msgid "The prime tower extends beyond the plate boundary." -msgstr "หอคอยหลักขยายออกไปเกินขอบเขตแผ่นเปลือกโลก" +msgstr "Prime Tower ยื่นออกนอกขอบเขตของเพลตพิมพ์" msgid "Partial flushing volume set to 0. Multi-color printing may cause color mixing in models. Please readjust flushing settings." msgstr "ตั้งค่าปริมาณการไล่เส้นบางส่วนเป็น 0 การพิมพ์หลายสีอาจทำให้เกิดการผสมสีในรุ่นต่างๆ โปรดปรับการตั้งค่าการไล่เส้นใหม่" @@ -7949,7 +7953,7 @@ msgid "Enabling traditional timelapse photography may cause surface imperfection msgstr "การเปิดใช้งานการถ่ายภาพไทม์แลปส์แบบดั้งเดิมอาจทำให้เกิดความไม่สมบูรณ์ของพื้นผิวได้ ขอแนะนำให้เปลี่ยนเป็นโหมดราบรื่น" msgid "Smooth mode for timelapse is enabled, but the prime tower is off, which may cause print defects. Please enable the prime tower, re-slice and print again." -msgstr "เปิดใช้งานโหมด Smooth สำหรับไทม์แลปส์แล้ว แต่ไพรม์ทาวเวอร์ปิดอยู่ ซึ่งอาจทำให้เกิดข้อบกพร่องในการพิมพ์ โปรดเปิดใช้งานไพร์มทาวเวอร์ สไลซ์ใหม่และพิมพ์อีกครั้ง" +msgstr "เปิดใช้งานโหมด Smooth สำหรับไทม์แลปส์แล้ว แต่ Prime Tower ปิดอยู่ ซึ่งอาจทำให้เกิดข้อบกพร่องในการพิมพ์ โปรดเปิดใช้งาน Prime Tower สไลซ์ใหม่และพิมพ์อีกครั้ง" msgid "Expand sidebar" msgstr "ขยายแถบด้านข้าง" @@ -8195,21 +8199,21 @@ msgstr "ไม่ได้เลือกไดเรกทอรีสำหร msgid "Replaced with 3D files from directory:\n" msgstr "แทนที่ด้วยไฟล์ 3D จากไดเรกทอรี:\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ ข้าม %1%: ไฟล์เดียวกัน\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ ข้าม %s: ไฟล์เดียวกัน\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ ข้าม %1%: ไม่มีไฟล์อยู่\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ ข้าม %s: ไม่มีไฟล์อยู่\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ ข้าม %1%: ไม่สามารถแทนที่ได้\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ ข้าม %s: ไม่สามารถแทนที่ได้\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔แทนที่ %1%\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔แทนที่ %s\n" msgid "Replaced volumes" msgstr "ปริมาณที่ถูกแทนที่" @@ -9156,6 +9160,21 @@ msgstr "หรี่เลเยอร์ด้านล่าง" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "เมื่อเลื่อนแถบเลเยอร์ในตัวอย่างที่สไลซ์แล้ว จะแสดงเลเยอร์ที่อยู่ต่ำกว่าเลเยอร์ปัจจุบันแบบมืดลง เพื่อให้เห็นเฉพาะเลเยอร์ที่กำลังดูอยู่ด้วยความสว่างเต็มที่" +# AI Translated +msgid "Dimmed layer brightness" +msgstr "ความสว่างของเลเยอร์ที่หรี่" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"ความสว่างในการแสดงผลของเลเยอร์ที่ถูกหรี่ เมื่อเปิดใช้งาน \"หรี่เลเยอร์ด้านล่าง\"\n" +"99% คือหรี่ลงเพียงเล็กน้อย ส่วน 0% จะแสดงเป็นสีดำ ค่าสูงสุดถูกจำกัดไว้ที่ 99% เพราะ 100% จะให้ผลเหมือนกับการปิดตัวเลือกนี้" + msgid "Login region" msgstr "เข้าสู่ระบบภูมิภาค" @@ -9292,7 +9311,7 @@ msgid "" "Attempt to keep painted features (color/seam/support/fuzzy etc.) after changing the object mesh (such as cut/reload from disk/simplify/fix etc.)\n" "Highly experimental! Slow and may create artifact." msgstr "" -"พยายามคงคุณสมบัติการทาสีไว้ (สี/รอยตะเข็บ/ส่วนรองรับ/คลุมเครือ ฯลฯ) หลังจากเปลี่ยนตาข่ายวัตถุ (เช่น ตัด/โหลดซ้ำจากดิสก์/ลดความซับซ้อน/แก้ไข ฯลฯ)\n" +"พยายามคงคุณสมบัติการทาสีไว้ (สี/รอยตะเข็บ/ส่วนรองรับ/ผิวฟัซซี ฯลฯ) หลังจากเปลี่ยนตาข่ายวัตถุ (เช่น ตัด/โหลดซ้ำจากดิสก์/ลดความซับซ้อน/แก้ไข ฯลฯ)\n" "น่าทดลองมาก! ช้าและอาจสร้างสิ่งประดิษฐ์" msgid "Allow Abnormal Storage" @@ -10222,25 +10241,25 @@ msgstr "คลิกเพื่อรีเซ็ตการตั้งค่ # AI Translated msgid "Prime tower is required for nozzle changing. There may be flaws on the model without prime tower. Are you sure you want to disable prime tower?" -msgstr "จำเป็นต้องใช้ทาวเวอร์ไล่เส้นสำหรับการเปลี่ยนหัวฉีด อาจเกิดข้อบกพร่องบนโมเดลหากไม่มีทาวเวอร์ไล่เส้น คุณแน่ใจหรือไม่ว่าต้องการปิดทาวเวอร์ไล่เส้น?" +msgstr "จำเป็นต้องใช้ Prime Tower สำหรับการเปลี่ยนหัวฉีด อาจเกิดข้อบกพร่องบนโมเดลหากไม่มี Prime Tower คุณแน่ใจหรือไม่ว่าต้องการปิด Prime Tower?" msgid "A prime tower is required for smooth timelapse mode. There may be flaws on the model without a prime tower. Are you sure you want to disable the prime tower?" -msgstr "โหมดไทม์แลปส์แบบราบรื่นต้องใช้ไพรม์ทาวเวอร์ หากไม่มีไพรม์ทาวเวอร์อาจเกิดตำหนิบนโมเดลได้ คุณแน่ใจหรือไม่ว่าต้องการปิดไพรม์ทาวเวอร์?" +msgstr "จำเป็นต้องใช้ Prime Tower สำหรับโหมดไทม์แลปส์แบบราบรื่น หากไม่มี Prime Tower อาจเกิดตำหนิบนโมเดลได้ คุณแน่ใจหรือไม่ว่าต้องการปิด Prime Tower?" msgid "A prime tower is required for clumping detection. There may be flaws on the model without prime tower. Are you sure you want to disable prime tower?" -msgstr "ต้องใช้ไพรม์ทาวเวอร์ในการตรวจจับการจับกันเป็นก้อน อาจมีตำหนิตรงรุ่นที่ไม่มีไพร์มทาวเวอร์ คุณแน่ใจหรือไม่ว่าต้องการปิดการใช้งานไพร์มทาวเวอร์?" +msgstr "จำเป็นต้องใช้ Prime Tower ในการตรวจจับการจับกันเป็นก้อน อาจมีตำหนิบนโมเดลที่ไม่มี Prime Tower คุณแน่ใจหรือไม่ว่าต้องการปิด Prime Tower?" msgid "Enabling both precise Z height and the prime tower may cause slicing errors. Do you still want to enable?" -msgstr "การเปิดใช้งานทั้งความสูง Z ที่แม่นยำและหอคอยหลักอาจทำให้เกิดข้อผิดพลาดในการแบ่งส่วน คุณยังต้องการเปิดใช้งานหรือไม่?" +msgstr "การเปิดใช้งานทั้งความสูง Z ที่แม่นยำและ Prime Tower อาจทำให้เกิดข้อผิดพลาดในการแบ่งส่วน คุณยังต้องการเปิดใช้งานหรือไม่?" msgid "A prime tower is required for clumping detection. There may be flaws on the model without prime tower. Do you still want to enable clumping detection?" -msgstr "ต้องใช้ไพรม์ทาวเวอร์ในการตรวจจับการจับกันเป็นก้อน อาจมีตำหนิตรงรุ่นที่ไม่มีไพร์มทาวเวอร์ คุณยังต้องการเปิดใช้งานการตรวจจับการจับกันเป็นก้อนหรือไม่" +msgstr "จำเป็นต้องใช้ Prime Tower ในการตรวจจับการจับกันเป็นก้อน อาจมีตำหนิบนโมเดลที่ไม่มี Prime Tower คุณยังต้องการเปิดใช้งานการตรวจจับการจับกันเป็นก้อนหรือไม่" msgid "Enabling both precise Z height and the prime tower may cause slicing errors. Do you still want to enable precise Z height?" -msgstr "การเปิดใช้งานทั้งความสูง Z ที่แม่นยำและหอคอยหลักอาจทำให้เกิดข้อผิดพลาดในการแบ่งส่วน คุณยังต้องการเปิดใช้งานความสูง Z ที่แม่นยำหรือไม่" +msgstr "การเปิดใช้งานทั้งความสูง Z ที่แม่นยำและ Prime Tower อาจทำให้เกิดข้อผิดพลาดในการแบ่งส่วน คุณยังต้องการเปิดใช้งานความสูง Z ที่แม่นยำหรือไม่" msgid "A prime tower is required for smooth timelapse mode. There may be flaws on the model without prime tower. Do you want to enable the prime tower?" -msgstr "โหมดไทม์แลปส์แบบราบรื่นต้องใช้ไพรม์ทาวเวอร์ หากไม่มีไพรม์ทาวเวอร์อาจเกิดตำหนิบนโมเดลได้ ต้องการเปิดใช้ไพรม์ทาวเวอร์หรือไม่?" +msgstr "จำเป็นต้องใช้ Prime Tower สำหรับโหมดไทม์แลปส์แบบราบรื่น หากไม่มี Prime Tower อาจเกิดตำหนิบนโมเดลได้ ต้องการเปิดใช้ Prime Tower หรือไม่?" msgid "Still print by object?" msgstr "ยังคงพิมพ์ตามวัตถุใช่ไหม" @@ -10392,7 +10411,7 @@ msgid "Z contouring" msgstr "รูปร่าง Z" msgid "Wall generator" -msgstr "เครื่องกำเนิดไฟฟ้าติดผนัง" +msgstr "ตัวสร้างผนัง" msgid "Walls and surfaces" msgstr "ผนังและพื้นผิว" @@ -10458,7 +10477,7 @@ msgid "G-code output" msgstr "เอาต์พุตรหัส G" msgid "Change extrusion role G-code" -msgstr "เปลี่ยนบทบาทการอัดขึ้นรูป G-code" +msgstr "เปลี่ยนประเภทการพิมพ์ G-code" msgid "Post-processing Scripts" msgstr "สคริปต์หลังการประมวลผล" @@ -10597,7 +10616,7 @@ msgid "Filament end G-code" msgstr "G-code สิ้นสุดของเส้นพลาสติก" msgid "Wipe tower parameters" -msgstr "พารามิเตอร์ทาวเวอร์เช็ดหัวฉีด" +msgstr "พารามิเตอร์ Wipe Tower" msgid "Multi Filament" msgstr "เส้นพลาสติกแบบหลากหลาย" @@ -10734,7 +10753,7 @@ msgid "Nozzle diameter" msgstr "เส้นผ่านศูนย์กลางหัวฉีด" msgid "Wipe tower" -msgstr "ทาวเวอร์เช็ดหัวฉีด" +msgstr "Wipe Tower" msgid "Single extruder multi-material parameters" msgstr "พารามิเตอร์วัสดุหลายชุดดันเส้นเดี่ยว" @@ -10761,7 +10780,7 @@ msgstr "" "ต้องการตั้งค่าเป็น 100% เพื่อเปิดใช้งาน Firmware Retraction หรือไม่?" msgid "Firmware Retraction" -msgstr "การเพิกถอนเฟิร์มแวร์" +msgstr "การดึงกลับด้วยเฟิร์มแวร์ (Firmware Retraction)" msgid "Switching to a printer with different extruder types or numbers will discard or reset changes to extruder or multi-nozzle-related parameters." msgstr "การเปลี่ยนไปใช้เครื่องพิมพ์ที่มีประเภทหรือหมายเลขชุดดันเส้นที่แตกต่างกันจะยกเลิกหรือรีเซ็ตการเปลี่ยนแปลงในชุดดันเส้นหรือพารามิเตอร์ที่เกี่ยวข้องกับหัวฉีดหลายตัว" @@ -11577,7 +11596,7 @@ msgid "Gizmo mesh boolean" msgstr "Gizmo mesh บูลีน" msgid "Gizmo FDM paint-on fuzzy skin" -msgstr "Gizmo FDM เพ้นท์บนผิวที่คลุมเครือ" +msgstr "Gizmo FDM เพ้นท์ผิวฟัซซี" msgid "Gizmo SLA support points" msgstr "จุดส่วนรองรับ Gizmo SLA" @@ -11595,7 +11614,7 @@ msgid "Gizmo assemble" msgstr "กิสโมประกอบ" msgid "Gizmo brim ears" -msgstr "กิสโม่ขอบหู" +msgstr "Gizmo หูขอบยึดชิ้นงาน (Brim Ears)" msgid "Zoom in" msgstr "ซูมเข้า" @@ -11917,10 +11936,10 @@ msgid "Parts of the object at these heights may be too thin or the object may ha msgstr "บางส่วนของวัตถุที่ความสูงเหล่านี้อาจบางเกินไป หรือวัตถุอาจมี mesh ผิดปกติ" msgid "Process change extrusion role G-code" -msgstr "กระบวนการเปลี่ยนบทบาทการอัดขึ้นรูป G-code" +msgstr "กระบวนการเปลี่ยนประเภทการพิมพ์ G-code" msgid "Filament change extrusion role G-code" -msgstr "เส้นพลาสติกเปลี่ยนบทบาทการอัดขึ้นรูป G-code" +msgstr "เส้นพลาสติกเปลี่ยนประเภทการพิมพ์ G-code" msgid "No object can be printed. It may be too small." msgstr "ไม่สามารถพิมพ์วัตถุได้ อาจจะเล็กเกินไป" @@ -12081,7 +12100,7 @@ msgid " is too close to clumping detection area, there may be collisions when pr msgstr "อยู่ใกล้พื้นที่การตรวจจับการจับตัวกันมากเกินไป อาจเกิดการชนกันเมื่อพิมพ์" msgid "Prime Tower" -msgstr "ทาวเวอร์ไล่เส้น" +msgstr "Prime Tower" msgid " is too close to others, and collisions may be caused.\n" msgstr "อยู่ใกล้ผู้อื่นมากเกินไปและอาจเกิดการชนได้\n" @@ -12111,10 +12130,10 @@ msgid "Clumping detection is not supported when \"by object\" sequence is enable msgstr "ไม่รองรับการตรวจจับการจับกันเป็นก้อนเมื่อเปิดใช้งานลำดับ \"ตามวัตถุ\"" msgid "Enabling both precise Z height and the prime tower may cause slicing errors." -msgstr "การเปิดใช้งานทั้งความสูง Z ที่แม่นยำและหอคอยหลักอาจทำให้เกิดข้อผิดพลาดในการแบ่งส่วน" +msgstr "การเปิดใช้งานทั้งความสูง Z ที่แม่นยำและ Prime Tower อาจทำให้เกิดข้อผิดพลาดในการแบ่งส่วน" msgid "A prime tower is required for clumping detection; otherwise, there may be flaws on the model." -msgstr "จำเป็นต้องใช้หอคอยหลักในการตรวจจับการจับกันเป็นก้อน มิฉะนั้นอาจมีข้อบกพร่องในแบบจำลอง" +msgstr "จำเป็นต้องใช้ Prime Tower ในการตรวจจับการจับกันเป็นก้อน มิฉะนั้นอาจมีข้อบกพร่องในแบบจำลอง" msgid "Please select \"By object\" print sequence to print multiple objects in spiral vase mode." msgstr "โปรดเลือกลำดับการพิมพ์ \"ตามวัตถุ\" เพื่อพิมพ์วัตถุหลายชิ้นในโหมดแจกันเกลียว" @@ -12124,15 +12143,15 @@ msgstr "โหมดแจกันเกลียวจะไม่ทำงา #, boost-format msgid "While the object %1% itself fits the build volume, it exceeds the maximum build volume height because of material shrinkage compensation." -msgstr "แม้ว่าวัตถุ %1% จะพอดีกับปริมาตรการสร้าง แต่วัตถุนั้นเกินความสูงของปริมาตรการสร้างสูงสุดเนื่องจากการชดเชยการหดตัวของวัสดุ" +msgstr "แม้ว่าวัตถุ %1% จะพอดีกับปริมาตรการพิมพ์ แต่วัตถุนั้นเกินความสูงของปริมาตรการพิมพ์สูงสุดเนื่องจากการชดเชยการหดตัวของวัสดุ" #, boost-format msgid "The object %1% exceeds the maximum build volume height." -msgstr "วัตถุ %1% เกินความสูงของปริมาตรบิลด์สูงสุด" +msgstr "วัตถุ %1% เกินความสูงของปริมาตรการพิมพ์สูงสุด" #, boost-format msgid "While the object %1% itself fits the build volume, its last layer exceeds the maximum build volume height." -msgstr "แม้ว่าออบเจ็กต์ %1% จะพอดีกับปริมาณการสร้าง แต่เลเยอร์สุดท้ายก็เกินความสูงของปริมาตรการสร้างสูงสุด" +msgstr "แม้ว่าวัตถุ %1% จะพอดีกับปริมาตรการพิมพ์ แต่วัตถุนั้นเกินความสูงของปริมาตรการพิมพ์สูงสุด" msgid "You might want to reduce the size of your model or change current print settings and retry." msgstr "คุณอาจต้องการลดขนาดแบบจำลองของคุณหรือเปลี่ยนการตั้งค่าการพิมพ์ปัจจุบันแล้วลองอีกครั้ง" @@ -12141,40 +12160,40 @@ msgid "Variable layer height is not supported with Organic supports." msgstr "ไม่รองรับความสูงของเลเยอร์ที่แปรผันได้ด้วยการรองรับแบบออร์แกนิก" msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." -msgstr "เส้นผ่านศูนย์กลางของหัวฉีดที่แตกต่างกันและเส้นผ่านศูนย์กลางของเส้นพลาสติกที่แตกต่างกันอาจทำงานได้ไม่ดีนักเมื่อเปิดใช้งานไพรม์ทาวเวอร์ ยังเป็นการทดลองอยู่มาก ดังนั้นโปรดดำเนินการด้วยความระมัดระวัง" +msgstr "เส้นผ่านศูนย์กลางของหัวฉีดที่แตกต่างกันและเส้นผ่านศูนย์กลางของเส้นพลาสติกที่แตกต่างกันอาจทำงานได้ไม่ดีนักเมื่อเปิดใช้งาน Prime Tower ยังเป็นการทดลองอยู่มาก ดังนั้นโปรดดำเนินการด้วยความระมัดระวัง" msgid "The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)." msgstr "ขณะนี้ Wipe Tower รองรับการกำหนดที่อยู่ของชุดดันเส้นแบบสัมพันธ์เท่านั้น (use_relative_e_distances=1)" msgid "Ooze prevention is only supported with the wipe tower when 'single_extruder_multi_material' is off." -msgstr "รองรับการป้องกันน้ำซึมด้วยหอเช็ดเมื่อปิด 'single_extruder_multi_material' เท่านั้น" +msgstr "รองรับการป้องกันน้ำซึมด้วย Wipe Tower เมื่อปิด 'single_extruder_multi_material' เท่านั้น" msgid "The prime tower is currently only supported for the Marlin, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors." -msgstr "ขณะนี้ไพรม์ทาวเวอร์รองรับเฉพาะรสชาติ Marlin, RepRap/Sprinter, RepRapFirmware และ Repetier G-code เท่านั้น" +msgstr "ขณะนี้ Prime Tower รองรับเฉพาะรสชาติ Marlin, RepRap/Sprinter, RepRapFirmware และ Repetier G-code เท่านั้น" msgid "A prime tower is not supported in “By object” print." -msgstr "ไม่รองรับไพรม์ทาวเวอร์ในการพิมพ์ \"ตามวัตถุ\"" +msgstr "ไม่รองรับ Prime Tower ในการพิมพ์ \"ตามวัตถุ\"" msgid "A prime tower is not supported when adaptive layer height is on. It requires that all objects have the same layer height." -msgstr "ไม่รองรับไพรม์ทาวเวอร์เมื่อเปิดความสูงของเลเยอร์แบบปรับได้ กำหนดให้วัตถุทั้งหมดมีความสูงของชั้นเท่ากัน" +msgstr "ไม่รองรับ Prime Tower เมื่อเปิดความสูงของเลเยอร์แบบปรับได้ กำหนดให้วัตถุทั้งหมดมีความสูงของชั้นเท่ากัน" msgid "A prime tower requires any “support gap” to be a multiple of layer height." -msgstr "ไพรม์ทาวเวอร์ต้องการให้ “support gap” เป็นจำนวนเท่าของความสูงชั้น" +msgstr "Prime Tower ต้องการให้ “support gap” เป็นจำนวนเท่าของความสูงชั้น" msgid "A prime tower requires that all objects have the same layer height." -msgstr "ไพรม์ทาวเวอร์ต้องการให้วัตถุทั้งหมดมีความสูงชั้นเท่ากัน" +msgstr "Prime Tower ต้องการให้วัตถุทั้งหมดมีความสูงชั้นเท่ากัน" msgid "A prime tower requires that all objects are printed over the same number of raft layers." -msgstr "ไพรม์ทาวเวอร์ต้องการให้วัตถุทั้งหมดพิมพ์บนจำนวนชั้น raft เท่ากัน" +msgstr "Prime Tower ต้องการให้วัตถุทั้งหมดพิมพ์บนจำนวนชั้น raft เท่ากัน" msgid "The prime tower is only supported for multiple objects if they are printed with the same support_top_z_distance." -msgstr "ไพรม์ทาวเวอร์รองรับวัตถุหลายชิ้นเท่านั้นหากพิมพ์ด้วย support_top_z_distance เท่ากัน" +msgstr "Prime Tower รองรับวัตถุหลายชิ้นเท่านั้นหากพิมพ์ด้วย support_top_z_distance เท่ากัน" msgid "A prime tower requires that all objects are sliced with the same layer height." -msgstr "ไพรม์ทาวเวอร์ต้องการให้วัตถุทั้งหมดถูกสไลซ์ด้วยความสูงชั้นเท่ากัน" +msgstr "Prime Tower ต้องการให้วัตถุทั้งหมดถูกสไลซ์ด้วยความสูงชั้นเท่ากัน" msgid "The prime tower is only supported if all objects have the same variable layer height." -msgstr "ไพรม์ทาวเวอร์ได้รับส่วนรองรับก็ต่อเมื่อวัตถุทั้งหมดมีความสูงของเลเยอร์ที่แปรผันเท่ากัน" +msgstr "Prime Tower ได้รับส่วนรองรับก็ต่อเมื่อวัตถุทั้งหมดมีความสูงของเลเยอร์ที่แปรผันเท่ากัน" msgid "One or more object were assigned an extruder that the printer does not have." msgstr "วัตถุอย่างน้อยหนึ่งชิ้นถูกกำหนดให้เป็นชุดดันเส้นที่เครื่องพิมพ์ไม่มี" @@ -12189,7 +12208,7 @@ msgid "Printing with multiple extruders of differing nozzle diameters. If suppor msgstr "การพิมพ์ด้วยชุดดันเส้นหลายเครื่องที่มีเส้นผ่านศูนย์กลางหัวฉีดต่างกัน หากจะพิมพ์ส่วนรองรับด้วยฟิลาเมนต์ปัจจุบัน (support_filament == 0 หรือ support_interface_filament == 0) หัวฉีดทั้งหมดจะต้องมีเส้นผ่านศูนย์กลางเท่ากัน" msgid "A prime tower requires that support has the same layer height as the object." -msgstr "ไพรม์ทาวเวอร์ต้องการให้ส่วนรองรับมีความสูงชั้นเท่ากับวัตถุ" +msgstr "Prime Tower ต้องการให้ส่วนรองรับมีความสูงชั้นเท่ากับวัตถุ" msgid "For Organic supports, two walls are supported only with the Hollow/Default base pattern." msgstr "สำหรับการรองรับแบบออร์แกนิก ผนังทั้งสองได้รับการรองรับด้วยรูปแบบฐานกลวง/ค่าเริ่มต้นเท่านั้น" @@ -12826,9 +12845,9 @@ msgid "" "\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." msgstr "" -"ปัจจัยนี้ส่งผลต่อปริมาณวัสดุในชั้นแรกสำหรับบทบาทเส้นทางการอัดขึ้นรูปที่แสดงอยู่ในส่วนนี้\n" +"ปัจจัยนี้ส่งผลต่อปริมาณวัสดุในชั้นแรกสำหรับประเภทการพิมพ์ที่แสดงอยู่ในส่วนนี้\n" "\n" -"สำหรับชั้นแรก อัตราการไหลตามจริงสำหรับแต่ละบทบาทของเส้นทาง (ไม่ส่งผลต่อขอบยึดชิ้นงานและเส้นล้อมชิ้นงาน) จะถูกคูณด้วยค่านี้" +"สำหรับชั้นแรก อัตราการไหลตามจริงสำหรับแต่ละประเภทการพิมพ์ (ไม่ส่งผลต่อขอบยึดชิ้นงานและเส้นล้อมชิ้นงาน) จะถูกคูณด้วยค่านี้" msgid "Outer wall flow ratio" msgstr "อัตราส่วนการไหลของผนังด้านนอก" @@ -13119,7 +13138,7 @@ msgstr "" "หมายเหตุ: ค่าผลลัพธ์จะไม่ได้รับผลกระทบจากอัตราส่วนการไหลของชั้นแรก" msgid "Brim follows compensated outline" -msgstr "ขอบยึดชิ้นงาน ปฏิบัติตามโครงร่างที่ได้รับการชดเชย" +msgstr "Brim ตามแนวที่ชดเชยแล้ว" msgid "" "When enabled, the brim is aligned with the first-layer perimeter geometry after Elephant Foot Compensation is applied.\n" @@ -13142,10 +13161,10 @@ msgid "Brim ears" msgstr "หู ขอบยึดชิ้นงาน" msgid "Only draw brim over the sharp edges of the model." -msgstr "วาดขอบยึดชิ้นงานไว้เหนือขอบคมของนางแบบเท่านั้น" +msgstr "วาดขอบยึดชิ้นงานไว้เหนือขอบคมของชิ้นงานเท่านั้น" msgid "Brim ear max angle" -msgstr "มุมสูงสุดของหูขอบยึดชิ้นงานนก" +msgstr "มุมสูงสุดของหูขอบยึดชิ้นงาน (Brim Ears)" msgid "" "Maximum angle to let a brim ear appear.\n" @@ -13190,12 +13209,37 @@ msgstr "ตามวัตถุ" msgid "Intra-layer order" msgstr "คำสั่งภายในชั้น" -msgid "Print order within a single layer." -msgstr "สั่งพิมพ์ภายในชั้นเดียว" +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"ลำดับการเข้าถึงอินสแตนซ์ของวัตถุภายในเลเยอร์เดียวกัน ซึ่งกำหนดว่าต้องเดินหัวเปล่าระหว่างกันมากเพียงใด\n" +"\n" +"ค่าเริ่มต้น: การเชื่อมต่อแบบเพื่อนบ้านที่ใกล้ที่สุด ปรับปรุงด้วย 2-opt และการกำจัดเส้นทางที่ตัดกัน เป็นตัวเลือกทั่วไปที่ดี\n" +"เป็นรายการวัตถุ: พิมพ์อินสแตนซ์ตามลำดับเดียวกับรายการวัตถุ โดยไม่มีการปรับปรุงเส้นทางใด ๆ ใช้เมื่อคุณต้องการลำดับที่คาดเดาได้และควบคุมเองได้\n" +"ดีที่สุดจากทั้งหมด (เส้นทางสั้นที่สุด): จะประเมินทุกกลยุทธ์แล้วเลือกใช้กลยุทธ์ที่สั้นที่สุด ลำดับอินสแตนซ์ของวัตถุจะถูกกำหนดครั้งเดียวสำหรับทั้งงานพิมพ์ ส่วนลำดับของแต่ละเกาะจะถูกกำหนดแยกในแต่ละเลเยอร์ ดังนั้นเลเยอร์ต่าง ๆ อาจใช้กลยุทธ์ที่ต่างกัน สไลซ์ช้าลงเล็กน้อย\n" +"แบบงูเลื้อย: การไล่ทีละแถวแบบงูเลื้อย ปรับปรุงด้วย 2-opt เหมาะกับกริดที่เป็นระเบียบของชิ้นงานเล็ก ๆ จำนวนมาก\n" +"\n" +"เมื่อมีเส้นพลาสติกหรือหัวพิมพ์หลายชนิดในเลเยอร์เดียวกัน การลดจำนวนการเปลี่ยนหัวพิมพ์จะมีความสำคัญก่อน โดยวัตถุจะถูกจัดกลุ่มตามเส้นพลาสติกก่อน และการตั้งค่านี้จะจัดลำดับเฉพาะอินสแตนซ์ภายในแต่ละกลุ่มเส้นพลาสติกเท่านั้น ลำดับโดยรวมจึงอาจดูไม่เหมือนเส้นทางที่สั้นที่สุดบนฐานพิมพ์" msgid "As object list" msgstr "เป็นรายการวัตถุ" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "ดีที่สุดจากทั้งหมด (เส้นทางสั้นที่สุด)" + +# AI Translated +msgid "Snake" +msgstr "แบบงูเลื้อย" + msgid "Slow printing down for better layer cooling" msgstr "ชะลอการพิมพ์ลงเพื่อการระบายความร้อนที่ดีขึ้น" @@ -13709,7 +13753,7 @@ msgstr "" "อัตราการไหลของวัตถุขั้นสุดท้ายคือค่านี้คูณด้วยอัตราการไหลของเส้นพลาสติก" msgid "Enable pressure advance" -msgstr "เปิดใช้งานPressure Advance" +msgstr "เปิดใช้ Pressure Advance" msgid "Enable pressure advance, auto calibration result will be overwritten once enabled." msgstr "เปิดใช้งานการเลื่อนแรงดัน ผลลัพธ์การสอบเทียบอัตโนมัติจะถูกเขียนทับเมื่อเปิดใช้งาน" @@ -13718,7 +13762,7 @@ msgid "Pressure advance (Klipper) AKA Linear advance factor (Marlin)." msgstr "แรงดันล่วงหน้า (Pressure Advance) (Klipper) AKA Linear Advance Factor (Marlin)" msgid "Enable adaptive pressure advance (beta)" -msgstr "เปิดใช้งานการปรับPressure Advance (เบต้า)" +msgstr "เปิดใช้ Adaptive Pressure Advance (เบต้า)" #, no-c-format, no-boost-format msgid "" @@ -13736,7 +13780,7 @@ msgstr "" "เมื่อเปิดใช้งาน ค่าล่วงหน้าของแรงดันด้านบนจะถูกแทนที่ อย่างไรก็ตาม แนะนำให้ใช้ค่าเริ่มต้นที่สมเหตุสมผลด้านบนเพื่อเป็นทางเลือกและเมื่อมีการเปลี่ยนเครื่องมือ\n" msgid "Adaptive pressure advance measurements (beta)" -msgstr "การวัดล่วงหน้าด้วยแรงดันแบบปรับได้ (เบต้า)" +msgstr "ข้อมูลวัด Adaptive Pressure Advance (เบต้า)" #, no-c-format, no-boost-format msgid "" @@ -13977,7 +14021,7 @@ msgid "Loading speed" msgstr "ความเร็วกำลังโหลด" msgid "Speed used for loading the filament on the wipe tower." -msgstr "ความเร็วที่ใช้ในการโหลดเส้นพลาสติกบนไวด์ทาวเวอร์" +msgstr "ความเร็วที่ใช้ในการโหลดเส้นพลาสติกบน Wipe Tower" msgid "Loading speed at the start" msgstr "ความเร็วในการโหลดเมื่อเริ่มต้น" @@ -13989,7 +14033,7 @@ msgid "Unloading speed" msgstr "ความเร็วในการขนถ่าย" msgid "Speed used for unloading the filament on the wipe tower (does not affect initial part of unloading just after ramming)." -msgstr "ความเร็วที่ใช้ในการขนถ่ายเส้นพลาสติกบนไวด์ทาวเวอร์ (ไม่ส่งผลต่อส่วนเริ่มแรกของการขนถ่ายหลังจากการชน)" +msgstr "ความเร็วที่ใช้ในการขนถ่ายเส้นพลาสติกบน Wipe Tower (ไม่ส่งผลต่อส่วนเริ่มแรกของการขนถ่ายหลังจากการชน)" msgid "Unloading speed at the start" msgstr "ขนถ่ายความเร็วที่จุดเริ่มต้น" @@ -14031,10 +14075,10 @@ msgid "Minimal purge on wipe tower" msgstr "การล้างข้อมูลบน Wipe Tower น้อยที่สุด" msgid "After a tool change, the exact position of the newly loaded filament inside the nozzle may not be known, and the filament pressure is likely not yet stable. Before purging the print head into an infill or a sacrificial object, Orca Slicer will always prime this amount of material into the wipe tower to produce successive infill or sacrificial object extrusions reliably." -msgstr "หลังจากเปลี่ยนเครื่องมือ อาจไม่ทราบตำแหน่งที่แน่นอนของเส้นพลาสติกที่เพิ่งโหลดใหม่ภายในหัวฉีด และความดันเส้นพลาสติกก็มีแนวโน้มว่ายังไม่เสถียร ก่อนที่จะล้างหัวพิมพ์ลงในวัสดุไส้ในหรือวัตถุบูชายัญ Orca Slicer จะเตรียมวัสดุจำนวนนี้ลงในหอเช็ดเสมอเพื่อสร้างการอัดขึ้นรูปวัตถุแบบไส้ในหรือบูชายัญต่อเนื่องกันอย่างน่าเชื่อถือ" +msgstr "หลังจากเปลี่ยนเครื่องมือ อาจไม่ทราบตำแหน่งที่แน่นอนของเส้นพลาสติกที่เพิ่งโหลดใหม่ภายในหัวฉีด และความดันเส้นพลาสติกก็มีแนวโน้มว่ายังไม่เสถียร ก่อนที่จะล้างหัวพิมพ์ลงในวัสดุไส้ในหรือวัตถุบูชายัญ Orca Slicer จะเตรียมวัสดุจำนวนนี้ลงใน Wipe Tower เสมอเพื่อสร้างการอัดขึ้นรูปวัตถุแบบไส้ในหรือบูชายัญต่อเนื่องกันอย่างน่าเชื่อถือ" msgid "Wipe tower cooling" -msgstr "เช็ดทาวเวอร์คูลลิ่ง" +msgstr "Wipe Tower คูลลิ่ง" msgid "Temperature drop before entering filament tower" msgstr "อุณหภูมิลดลงก่อนเข้าหอใย" @@ -14043,19 +14087,19 @@ msgid "Interface layer pre-extrusion distance" msgstr "ระยะการอัดรีดชั้นอินเตอร์เฟซ" msgid "Pre-extrusion distance for prime tower interface layer (where different materials meet)." -msgstr "ระยะก่อนการอัดขึ้นรูปสำหรับชั้นอินเทอร์เฟซของไพรม์ทาวเวอร์ (ที่วัสดุที่แตกต่างกันมาบรรจบกัน)" +msgstr "ระยะก่อนการอัดขึ้นรูปสำหรับชั้นอินเทอร์เฟซของ Prime Tower (ที่วัสดุที่แตกต่างกันมาบรรจบกัน)" msgid "Interface layer pre-extrusion length" msgstr "ความยาวชั้นอินเตอร์เฟซก่อนการอัดขึ้นรูป" msgid "Pre-extrusion length for prime tower interface layer (where different materials meet)." -msgstr "ความยาวก่อนการอัดขึ้นรูปสำหรับชั้นอินเทอร์เฟซของไพรม์ทาวเวอร์ (ที่วัสดุที่แตกต่างกันมาบรรจบกัน)" +msgstr "ความยาวก่อนการอัดขึ้นรูปสำหรับชั้นอินเทอร์เฟซของ Prime Tower (ที่วัสดุที่แตกต่างกันมาบรรจบกัน)" msgid "Tower ironing area" msgstr "พื้นที่รีดผิวแบบทาวเวอร์" msgid "Ironing area for prime tower interface layer (where different materials meet)." -msgstr "พื้นที่รีดผิวสำหรับชั้นอินเทอร์เฟซของไพร์มทาวเวอร์ (บริเวณที่วัสดุต่างกันมาบรรจบกัน)" +msgstr "พื้นที่รีดผิวสำหรับชั้นอินเทอร์เฟซของ Prime Tower (บริเวณที่วัสดุต่างกันมาบรรจบกัน)" msgid "mm²" msgstr "มม.²" @@ -14064,13 +14108,13 @@ msgid "Interface layer purge length" msgstr "ความยาวการล้างเลเยอร์อินเทอร์เฟซ" msgid "Purge length for prime tower interface layer (where different materials meet)." -msgstr "ความยาวในการไล่ล้างสำหรับชั้นอินเทอร์เฟซของไพรม์ทาวเวอร์ (เมื่อวัสดุต่างกันมาบรรจบกัน)" +msgstr "ความยาวในการไล่ล้างสำหรับชั้นอินเทอร์เฟซของ Prime Tower (เมื่อวัสดุต่างกันมาบรรจบกัน)" msgid "Interface layer print temperature" msgstr "อุณหภูมิการพิมพ์เลเยอร์อินเทอร์เฟซ" msgid "Print temperature for prime tower interface layer (where different materials meet). If set to -1, use max recommended nozzle temperature." -msgstr "อุณหภูมิการพิมพ์สำหรับชั้นอินเทอร์เฟซของไพรม์ทาวเวอร์ (เมื่อวัสดุต่างกันมาบรรจบกัน) หากตั้งค่าเป็น -1 ให้ใช้อุณหภูมิหัวฉีดสูงสุดที่แนะนำ" +msgstr "อุณหภูมิการพิมพ์สำหรับชั้นอินเทอร์เฟซของ Prime Tower (เมื่อวัสดุต่างกันมาบรรจบกัน) หากตั้งค่าเป็น -1 ให้ใช้อุณหภูมิหัวฉีดสูงสุดที่แนะนำ" msgid "Speed of the last cooling move" msgstr "ความเร็วของการทำความเย็นครั้งล่าสุด" @@ -14088,7 +14132,7 @@ msgid "Enable ramming for multi-tool setups" msgstr "เปิดใช้งานการกระแทกสำหรับการตั้งค่าหลายเครื่องมือ" msgid "Perform ramming when using multi-tool printer (i.e. when the 'Single Extruder Multimaterial' in Printer Settings is unchecked). When checked, a small amount of filament is rapidly extruded on the wipe tower just before the tool change. This option is only used when the wipe tower is enabled." -msgstr "ทำการกระแทกเมื่อใช้เครื่องพิมพ์แบบหลายเครื่องมือ (เช่น เมื่อไม่ได้เลือก 'Single ชุดดันเส้น Multimaterial' ในการตั้งค่าเครื่องพิมพ์) เมื่อตรวจสอบแล้ว เส้นพลาสติกจำนวนเล็กน้อยจะถูกอัดรีดอย่างรวดเร็วบนไวด์ทาวเวอร์ก่อนที่จะเปลี่ยนเครื่องมือ ตัวเลือกนี้ใช้เฉพาะเมื่อเปิดใช้งาน Wipe Tower เท่านั้น" +msgstr "ทำการกระแทกเมื่อใช้เครื่องพิมพ์แบบหลายเครื่องมือ (เช่น เมื่อไม่ได้เลือก 'Single ชุดดันเส้น Multimaterial' ในการตั้งค่าเครื่องพิมพ์) เมื่อตรวจสอบแล้ว เส้นพลาสติกจำนวนเล็กน้อยจะถูกอัดรีดอย่างรวดเร็วบน Wipe Tower ก่อนที่จะเปลี่ยนเครื่องมือ ตัวเลือกนี้ใช้เฉพาะเมื่อเปิดใช้งาน Wipe Tower เท่านั้น" msgid "Multi-tool ramming volume" msgstr "ปริมาณการกระแทกหลายเครื่องมือ" @@ -14473,13 +14517,13 @@ msgid "Filament-specific override for ironing flow. This allows you to customize msgstr "การแทนที่เส้นพลาสติกเฉพาะสำหรับกระแสการรีดผิว ซึ่งช่วยให้คุณปรับแต่งกระแสการรีดผิวสำหรับเส้นพลาสติกแต่ละประเภทได้ ค่าที่สูงเกินไปส่งผลให้เกิดการอัดขึ้นรูปมากเกินไปบนพื้นผิว" msgid "Ironing line spacing" -msgstr "ระยะห่างระหว่างสายรีดผิว" +msgstr "ระยะห่างระหว่างเส้นรีดผิว" msgid "Filament-specific override for ironing line spacing. This allows you to customize the spacing between ironing lines for each filament type." msgstr "การแทนที่เส้นพลาสติกเฉพาะสำหรับระยะห่างระหว่างรีดผิว ซึ่งช่วยให้คุณปรับแต่งระยะห่างระหว่างเส้นรีดผิวสำหรับเส้นพลาสติกแต่ละประเภทได้" msgid "Ironing inset" -msgstr "อุปกรณ์รีดผิว" +msgstr "ระยะเว้นขอบการรีดผิว" msgid "Filament-specific override for ironing inset. This allows you to customize the distance to keep from the edges when ironing for each filament type." msgstr "การแทนที่เส้นพลาสติกเฉพาะสำหรับส่วนเสริมการรีดผิว ซึ่งช่วยให้คุณปรับแต่งระยะห่างจากขอบเมื่อรีดผิวสำหรับเส้นพลาสติกแต่ละประเภทได้" @@ -14521,10 +14565,10 @@ msgid "The average distance between the random points introduced on each line se msgstr "ระยะห่างเฉลี่ยระหว่างจุดสุ่มที่แนะนำในแต่ละส่วนของเส้น" msgid "Apply fuzzy skin to first layer" -msgstr "ทาผิวที่คลุมเครือเป็นชั้นแรก" +msgstr "ใช้ Fuzzy Skin กับชั้นแรก" msgid "Whether to apply fuzzy skin on the first layer." -msgstr "ไม่ว่าจะทาผิวฟุ้งๆในชั้นแรกหรือไม่" +msgstr "กำหนดว่าจะใช้ Fuzzy Skin กับชั้นแรกหรือไม่" msgid "Fuzzy skin generator mode" msgstr "โหมดสร้างผิวฟัซซี" @@ -14555,7 +14599,7 @@ msgid "Combined" msgstr "รวม" msgid "Fuzzy skin noise type" -msgstr "ประเภทเสียงผิวเลือน" +msgstr "ประเภท Noise ของ Fuzzy Skin" msgid "" "Noise type to use for fuzzy skin generation:\n" @@ -14566,12 +14610,12 @@ msgid "" "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." msgstr "" -"ประเภทเสียงรบกวนที่ใช้สำหรับการสร้างผิวที่คลุมเครือ:\n" +"ประเภท Noise ที่ใช้สำหรับการสร้างผิวฟัซซี:\n" "คลาสสิก: เสียงสุ่มเครื่องแบบคลาสสิก\n" "Perlin: เสียง Perlin ซึ่งให้เนื้อสัมผัสที่สม่ำเสมอยิ่งขึ้น\n" "Billow: คล้ายกับเสียงเพอร์ลิน แต่เป็นกลุ่มมากกว่า\n" "Ridged Multifractal: สัญญาณรบกวนที่คมชัดพร้อมคุณสมบัติหยัก สร้างพื้นผิวเหมือนหินอ่อน\n" -"โวโรนอย: แบ่งพื้นผิวออกเป็นเซลล์โวโรนอย และแทนที่แต่ละเซลล์ด้วยจำนวนสุ่ม สร้างพื้นผิวแบบเย็บปะติดปะต่อกัน\n" +"Voronoi: แบ่งพื้นผิวออกเป็นเซลล์ Voronoi และแทนที่แต่ละเซลล์ด้วยจำนวนสุ่ม สร้างพื้นผิวแบบเย็บปะติดปะต่อกัน\n" "ระลอกคลื่น: รูปแบบระลอกคลื่นสม่ำเสมอที่กระเพื่อมไปทางซ้ายและขวาของเส้นทางเดิม ลายซ้ำ ลักษณะการทอ." msgid "Classic" @@ -14587,7 +14631,7 @@ msgid "Ridged Multifractal" msgstr "Multifractal แบบสัน" msgid "Voronoi" -msgstr "โวโรน้อย" +msgstr "Voronoi" msgid "Ripple" msgstr "ระลอกคลื่น" @@ -14599,13 +14643,13 @@ msgid "The base size of the coherent noise features, in mm. Higher values will r msgstr "ขนาดฐานของคุณสมบัติเสียงที่สอดคล้องกัน หน่วยเป็น มม. ค่าที่สูงกว่าจะส่งผลให้มีคุณลักษณะที่ใหญ่ขึ้น" msgid "Fuzzy Skin Noise Octaves" -msgstr "อ็อกเทฟเสียงผิวฟัซซี" +msgstr "จำนวน Octave ของ Noise ใน Fuzzy Skin" msgid "The number of octaves of coherent noise to use. Higher values increase the detail of the noise, but also increase computation time." msgstr "จำนวนอ็อกเทฟของสัญญาณรบกวนที่สอดคล้องกันที่จะใช้ ค่าที่สูงกว่าจะเพิ่มรายละเอียดของสัญญาณรบกวน แต่ยังเพิ่มเวลาในการคำนวณด้วย" msgid "Fuzzy skin noise persistence" -msgstr "ความคงอยู่ของเสียงผิวเลือน" +msgstr "ค่า Persistence ของ Noise ใน Fuzzy Skin" msgid "The decay rate for higher octaves of the coherent noise. Lower values will result in smoother noise." msgstr "อัตราการสลายตัวของอ็อกเทฟที่สูงขึ้นของสัญญาณรบกวนที่สอดคล้องกัน ค่าที่ต่ำกว่าจะส่งผลให้มีสัญญาณรบกวนที่นุ่มนวลขึ้น" @@ -15693,7 +15737,7 @@ msgid "The start and end points which are from the cutter area to the excess chu msgstr "จุดเริ่มต้นและจุดสิ้นสุดตั้งแต่บริเวณเครื่องตัดถึงถังขยะ" msgid "Reduce infill retraction" -msgstr "ลดการหดตัวของ ไส้ใน" +msgstr "ลดการดึงกลับในไส้ใน" msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." msgstr "อย่าถอยกลับเมื่อการเดินทางอยู่ภายในพื้นที่ที่ไส้ในเข้าไปทั้งหมด นั่นหมายความว่าไม่สามารถมองเห็นการรั่วไหลได้ วิธีนี้จะช่วยลดเวลาในการดึงกลับสำหรับโมเดลที่ซับซ้อนและประหยัดเวลาในการพิมพ์ แต่จะทำให้การแบ่งส่วนและการสร้าง G-code ช้าลง โปรดทราบว่า z-hop จะไม่ดำเนินการในพื้นที่ที่มีการข้ามการถอนกลับ" @@ -15781,10 +15825,10 @@ msgid "If you want to process the output G-code through custom scripts, just lis msgstr "หากคุณต้องการประมวลผลเอาต์พุต G-code ผ่านสคริปต์ที่กำหนดเอง เพียงระบุเส้นทางสัมบูรณ์ของสคริปต์ไว้ที่นี่ แยกสคริปต์หลายรายการด้วยเครื่องหมายอัฒภาค สคริปต์จะถูกส่งผ่านเส้นทางสัมบูรณ์ไปยังไฟล์ G-code เป็นอาร์กิวเมนต์แรก และสคริปต์เหล่านี้สามารถเข้าถึงการตั้งค่าการกำหนดค่า Orca Slicer ได้โดยการอ่านตัวแปรสภาพแวดล้อม" msgid "Change extrusion role G-code (process)" -msgstr "เปลี่ยนบทบาทการอัดขึ้นรูป G-code (กระบวนการ)" +msgstr "เปลี่ยนประเภทการพิมพ์ G-code (กระบวนการ)" msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code." -msgstr "G-code นี้จะถูกแทรกเมื่อบทบาทการอัดขึ้นรูปมีการเปลี่ยนแปลง มันทำงานหลังจากบทบาทการอัดขึ้นรูปของเครื่องจักรและการอัดขึ้นรูปเส้นพลาสติก G-code" +msgstr "G-code นี้จะถูกแทรกเมื่อประเภทการพิมพ์มีการเปลี่ยนแปลง มันทำงานหลังจากประเภทการพิมพ์ของเครื่องจักรและเส้นพลาสติก G-code" # AI Translated msgid "Plugins Used" @@ -15853,7 +15897,7 @@ msgid "Only trigger retraction when the travel distance is longer than this thre msgstr "ทริกเกอร์การถอนกลับเมื่อระยะการเดินทางยาวกว่าเกณฑ์นี้เท่านั้น" msgid "Retract amount before wipe" -msgstr "ถอนจำนวนก่อนเช็ด" +msgstr "สัดส่วนการดึงกลับก่อน Wipe" msgid "This is the length of fast retraction before a wipe, relative to retraction length." msgstr "ความยาวของการดึงกลับอย่างรวดเร็วก่อนเช็ด สัมพันธ์กับความยาวการดึงกลับ" @@ -15872,7 +15916,7 @@ msgstr "" "ค่าจะถูกจำกัดด้วย 100% ลบด้วยปริมาณการดึงกลับก่อนค่าเช็ดหัว" msgid "Retract on layer change" -msgstr "ถอนออกเมื่อเปลี่ยนเลเยอร์" +msgstr "ดึงเส้นกลับเมื่อเปลี่ยนเลเยอร์" msgid "This forces a retraction on layer changes." msgstr "บังคับให้ถอนกลับเมื่อเปลี่ยนเลเยอร์" @@ -15881,7 +15925,7 @@ msgid "Retraction Length" msgstr "ระยะดึงกลับ" msgid "Some amount of material in extruder is pulled back to avoid ooze during long travel. Set zero to disable retraction." -msgstr "วัสดุบางส่วนในชุดดันเส้นถูกดึงกลับเพื่อหลีกเลี่ยงไม่ให้ซึ่มในระหว่างการเดินทางระยะไกล ตั้งค่าเป็นศูนย์เพื่อปิดใช้งานการเพิกถอน" +msgstr "วัสดุบางส่วนในชุดดันเส้นถูกดึงกลับเพื่อหลีกเลี่ยงไม่ให้ซึ่มในระหว่างการเดินทางระยะไกล ตั้งเป็น 0 เพื่อปิดการดึงกลับ" msgid "Long retraction when cut (beta)" msgstr "การถอยกลับยาวเมื่อตัด (เบต้า)" @@ -16005,7 +16049,7 @@ msgid "Speed for retracting filament from the nozzle." msgstr "ความเร็วในการดึงเส้นพลาสติกออกจากหัวฉีด" msgid "Deretraction speed" -msgstr "ความเร็วในการถอนกลับ" +msgstr "ความเร็วคืนเส้นหลังดึงกลับ" msgid "Speed for reloading filament into the nozzle. Zero means same speed of retraction." msgstr "ความเร็วในการบรรจุเส้นพลาสติกลงในหัวฉีด ศูนย์หมายถึงความเร็วการถอยกลับเท่ากัน" @@ -16019,7 +16063,7 @@ msgid "Speed for reloading filament into the nozzle when switching extruder." msgstr "ความเร็วในการโหลดเส้นพลาสติกกลับเข้าหัวฉีดเมื่อเปลี่ยนชุดดันเส้น" msgid "Use firmware retraction" -msgstr "ใช้การเพิกถอนเฟิร์มแวร์" +msgstr "ใช้การดึงกลับด้วยเฟิร์มแวร์" msgid "This experimental setting uses G10 and G11 commands to have the firmware handle the retraction. This is only supported in recent Marlin." msgstr "การตั้งค่าทดลองนี้ใช้คำสั่ง G10 และ G11 เพื่อให้เฟิร์มแวร์จัดการกับการเพิกถอน สิ่งนี้รองรับใน Marlin ล่าสุดเท่านั้น" @@ -16071,16 +16115,16 @@ msgstr "" "ปริมาณนี้สามารถระบุได้ในหน่วยมิลลิเมตรหรือเป็นเปอร์เซ็นต์ของเส้นผ่านศูนย์กลางของชุดดันเส้นในปัจจุบัน ค่าเริ่มต้นสำหรับพารามิเตอร์นี้คือ 10%" msgid "Scarf joint seam (beta)" -msgstr "รอยต่อเฉียง (เบต้า)" +msgstr "รอยต่อ Scarf (เบต้า)" msgid "Use scarf joint to minimize seam visibility and increase seam strength." -msgstr "ใช้ข้อต่อเฉียงเพื่อลดการมองเห็นรอยตะเข็บและเพิ่มความแข็งแรงของรอยตะเข็บ" +msgstr "ใช้รอยต่อ Scarf เพื่อลดการมองเห็นรอยตะเข็บและเพิ่มความแข็งแรง" msgid "Conditional scarf joint" -msgstr "ข้อต่อเฉียงแบบมีเงื่อนไข" +msgstr "รอยต่อ Scarf แบบมีเงื่อนไข" msgid "Apply scarf joints only to smooth perimeters where traditional seams do not conceal the seams at sharp corners effectively." -msgstr "ใช้ข้อต่อเฉียงกับขอบเรียบเท่านั้น โดยที่รอยตะเข็บแบบเดิมไม่สามารถปกปิดรอยตะเข็บที่มุมแหลมคมได้อย่างมีประสิทธิภาพ" +msgstr "ใช้รอยต่อ Scarf กับขอบเรียบเท่านั้น โดยที่รอยตะเข็บแบบเดิมไม่สามารถปกปิดรอยตะเข็บที่มุมแหลมคมได้อย่างมีประสิทธิภาพ" msgid "Conditional angle threshold" msgstr "เกณฑ์มุมแบบมีเงื่อนไข" @@ -16089,67 +16133,67 @@ msgid "" "This option sets the threshold angle for applying a conditional scarf joint seam.\n" "If the maximum angle within the perimeter loop exceeds this value (indicating the absence of sharp corners), a scarf joint seam will be used. The default value is 155°." msgstr "" -"ตัวเลือกนี้จะกำหนดมุมเกณฑ์สำหรับการใช้รอยตะเข็บข้อต่อเฉียงแบบมีเงื่อนไข\n" -"หากมุมสูงสุดภายในวงรอบปริมณฑลเกินค่านี้ (แสดงว่าไม่มีมุมแหลมคม) จะใช้รอยตะเข็บข้อต่อเฉียง ค่าเริ่มต้นคือ 155°" +"ตัวเลือกนี้จะกำหนดมุมเกณฑ์สำหรับการใช้รอยต่อ Scarf แบบมีเงื่อนไข\n" +"หากมุมสูงสุดภายในวงรอบปริมณฑลเกินค่านี้ (แสดงว่าไม่มีมุมแหลมคม) จะใช้รอยต่อ Scarf ค่าเริ่มต้นคือ 155°" msgid "Conditional overhang threshold" msgstr "เกณฑ์ระยะยื่นแบบมีเงื่อนไข" #, no-c-format, no-boost-format msgid "This option determines the overhang threshold for the application of scarf joint seams. If the unsupported portion of the perimeter is less than this threshold, scarf joint seams will be applied. The default threshold is set at 40% of the external wall's width. Due to performance considerations, the degree of overhang is estimated." -msgstr "ตัวเลือกนี้จะกำหนดเกณฑ์ส่วนยื่นสำหรับการใช้รอยตะเข็บข้อต่อเฉียง หากส่วนที่ไม่ได้รับส่วนรองรับของเส้นรอบวงน้อยกว่าเกณฑ์นี้ จะมีการเย็บรอยตะเข็บเฉียง เกณฑ์เริ่มต้นตั้งไว้ที่ 40% ของความกว้างของผนังภายนอก เมื่อพิจารณาถึงประสิทธิภาพแล้ว ระดับของระยะยื่นจึงถูกประมาณไว้" +msgstr "ตัวเลือกนี้จะกำหนดเกณฑ์ส่วนยื่นสำหรับการใช้รอยต่อ Scarf หากส่วนที่ไม่ได้รับส่วนรองรับของเส้นรอบวงน้อยกว่าเกณฑ์นี้ จะใช้รอยต่อ Scarf เกณฑ์เริ่มต้นตั้งไว้ที่ 40% ของความกว้างของผนังภายนอก เมื่อพิจารณาถึงประสิทธิภาพแล้ว ระดับของระยะยื่นจึงถูกประมาณไว้" msgid "Scarf joint speed" -msgstr "ความเร็วของข้อต่อเฉียง" +msgstr "ความเร็วรอยต่อ Scarf" msgid "This option sets the printing speed for scarf joints. It is recommended to print scarf joints at a slow speed (less than 100 mm/s). It's also advisable to enable 'Extrusion rate smoothing' if the set speed varies significantly from the speed of the outer or inner walls. If the speed specified here is higher than the speed of the outer or inner walls, the printer will default to the slower of the two speeds. When specified as a percentage (e.g., 80%), the speed is calculated based on the respective outer or inner wall speed. The default value is set to 100%." -msgstr "ตัวเลือกนี้จะตั้งค่าความเร็วในการพิมพ์สำหรับข้อต่อเฉียง ขอแนะนำให้พิมพ์ข้อต่อเฉียงด้วยความเร็วต่ำ (น้อยกว่า 100 มม./วินาที) ขอแนะนำให้เปิดใช้งาน 'การปรับอัตราการอัดรีดให้เรียบ' หากความเร็วที่ตั้งไว้แตกต่างอย่างมากจากความเร็วของผนังด้านนอกหรือด้านใน หากความเร็วที่ระบุที่นี่สูงกว่าความเร็วของผนังด้านนอกหรือด้านใน เครื่องพิมพ์จะตั้งค่าเริ่มต้นไว้ที่ความเร็วที่ช้ากว่าทั้งสอง เมื่อระบุเป็นเปอร์เซ็นต์ (เช่น 80%) ความเร็วจะคำนวณตามความเร็วผนังด้านนอกหรือด้านในตามลำดับ ค่าเริ่มต้นตั้งไว้ที่ 100%" +msgstr "ตัวเลือกนี้จะตั้งค่าความเร็วในการพิมพ์สำหรับรอยต่อ Scarf ขอแนะนำให้พิมพ์รอยต่อ Scarfด้วยความเร็วต่ำ (น้อยกว่า 100 มม./วินาที) ขอแนะนำให้เปิดใช้งาน 'การปรับอัตราการอัดรีดให้เรียบ' หากความเร็วที่ตั้งไว้แตกต่างอย่างมากจากความเร็วของผนังด้านนอกหรือด้านใน หากความเร็วที่ระบุที่นี่สูงกว่าความเร็วของผนังด้านนอกหรือด้านใน เครื่องพิมพ์จะตั้งค่าเริ่มต้นไว้ที่ความเร็วที่ช้ากว่าทั้งสอง เมื่อระบุเป็นเปอร์เซ็นต์ (เช่น 80%) ความเร็วจะคำนวณตามความเร็วผนังด้านนอกหรือด้านในตามลำดับ ค่าเริ่มต้นตั้งไว้ที่ 100%" msgid "Scarf joint flow ratio" -msgstr "อัตราการไหลของข้อต่อเฉียง" +msgstr "อัตราส่วนการไหลของรอยต่อ Scarf" msgid "This factor affects the amount of material for scarf joints." -msgstr "ปัจจัยนี้ส่งผลต่อปริมาณวัสดุสำหรับข้อต่อเฉียง" +msgstr "ปัจจัยนี้ส่งผลต่อปริมาณวัสดุสำหรับรอยต่อ Scarf" msgid "Scarf start height" -msgstr "ความสูงเริ่มต้นของเฉียง" +msgstr "ความสูงเริ่มต้นของรอยต่อ Scarf" msgid "" "Start height of the scarf.\n" "This amount can be specified in millimeters or as a percentage of the current layer height. The default value for this parameter is 0." msgstr "" -"เริ่มต้นความสูงของเฉียง\n" +"ความสูงเริ่มต้นของรอยต่อ Scarf\n" "จำนวนนี้สามารถระบุได้ในหน่วยมิลลิเมตรหรือเป็นเปอร์เซ็นต์ของความสูงของเลเยอร์ปัจจุบัน ค่าเริ่มต้นสำหรับพารามิเตอร์นี้คือ 0" msgid "Scarf around entire wall" -msgstr "เฉียงพันรอบผนังทั้งหมด" +msgstr "ใช้รอยต่อ Scarf ตลอดทั้งผนัง" msgid "The scarf extends to the entire length of the wall." -msgstr "เฉียงยาวตลอดความยาวของผนัง" +msgstr "รอยต่อ Scarf ครอบคลุมตลอดความยาวผนัง" msgid "Scarf length" -msgstr "ความยาวเฉียง" +msgstr "ความยาวรอยต่อ Scarf" msgid "Length of the scarf. Setting this parameter to zero effectively disables the scarf." -msgstr "ความยาวของเฉียง. การตั้งค่าพารามิเตอร์นี้เป็นศูนย์จะปิดใช้เฉียงอย่างมีประสิทธิภาพ" +msgstr "ความยาวของรอยต่อ Scarf ตั้งเป็น 0 เพื่อปิดการใช้ Scarf" msgid "Scarf steps" -msgstr "ขั้นตอนเฉียง" +msgstr "จำนวนขั้นของรอยต่อ Scarf" msgid "Minimum number of segments of each scarf." -msgstr "จำนวนขั้นต่ำของส่วนเฉียงแต่ละอัน" +msgstr "จำนวนเซกเมนต์ขั้นต่ำของรอยต่อ Scarf" msgid "Scarf joint for inner walls" -msgstr "ข้อต่อเฉียงสำหรับผนังด้านใน" +msgstr "รอยต่อ Scarf สำหรับผนังด้านใน" msgid "Use scarf joint for inner walls as well." -msgstr "ใช้ข้อต่อเฉียงสำหรับผนังด้านในด้วย" +msgstr "ใช้รอยต่อ Scarf กับผนังด้านในด้วย" msgid "Role base wipe speed" -msgstr "ความเร็วในการล้างฐานบทบาท" +msgstr "ความเร็ว Wipe ตามประเภทการพิมพ์" msgid "The wipe speed is determined by the speed of the current extrusion role. e.g. if a wipe action is executed immediately following an outer wall extrusion, the speed of the outer wall extrusion will be utilized for the wipe action." -msgstr "ความเร็วในการเช็ดถูกกำหนดโดยความเร็วของบทบาทการอัดขึ้นรูปในปัจจุบัน เช่น หากการดำเนินการเช็ดถูกดำเนินการทันทีหลังจากการอัดขึ้นรูปผนังด้านนอก ความเร็วของการอัดขึ้นรูปผนังด้านนอกจะถูกใช้สำหรับการดำเนินการเช็ด" +msgstr "ความเร็ว Wipe จะอิงจากความเร็วของประเภทการพิมพ์ปัจจุบัน เช่น หากการ Wipe เกิดขึ้นทันทีหลังจากพิมพ์ผนังด้านนอก ความเร็วของผนังด้านนอกจะถูกใช้สำหรับการ Wipe" msgid "Wipe on loops" msgstr "เช็ดบนลูป" @@ -16197,10 +16241,10 @@ msgid "Single loop after first layer" msgstr "วนรอบเดียวหลังจากชั้นแรก" msgid "Limits the skirt/draft shield loops to one wall after the first layer. This is useful, on occasion, to conserve filament but may cause the draft shield/skirt to warp / crack." -msgstr "จำกัดห่วงสเกิร์ต/โล่ครอบไว้ที่ผนังด้านหนึ่งหลังจากชั้นแรก สิ่งนี้มีประโยชน์ในบางครั้งเพื่ออนุรักษ์เส้นพลาสติก แต่อาจทำให้โครง/เส้นล้อมชิ้นงานบิดเบี้ยว/แตกร้าวได้" +msgstr "จำกัดห่วงสเกิร์ต/แนวป้องกันลม (Draft Shield) ไว้ที่ผนังเดียวหลังจากชั้นแรก สิ่งนี้มีประโยชน์ในบางครั้งเพื่อประหยัดเส้นพลาสติก แต่อาจทำให้แนวป้องกันลม/เส้นล้อมชิ้นงานบิดเบี้ยว/แตกร้าวได้" msgid "Draft shield" -msgstr "โล่ร่าง" +msgstr "แนวป้องกันลม (Draft Shield)" msgid "" "A draft shield is useful to protect an ABS or ASA print from warping and detaching from print bed due to wind draft. It is usually needed only with open frame printers, i.e. without an enclosure.\n" @@ -16208,10 +16252,10 @@ msgid "" "Enabled = skirt is as tall as the highest printed object. Otherwise 'Skirt height' is used.\n" "Note: With the draft shield active, the skirt will be printed at skirt distance from the object. Therefore, if brims are active it may intersect with them. To avoid this, increase the skirt distance value.\n" msgstr "" -"แผงครอบมีประโยชน์ในการปกป้องงานพิมพ์ ABS หรือ ASA จากการบิดงอและการหลุดออกจากฐานพิมพ์เนื่องจากกระแสลม โดยทั่วไปจำเป็นต้องใช้กับเครื่องพิมพ์แบบเปิดเฟรมเท่านั้น กล่าวคือ ไม่มีกล่องหุ้ม\n" +"แนวป้องกันลม (Draft Shield) มีประโยชน์ในการปกป้องงานพิมพ์ ABS หรือ ASA จากการบิดงอและการหลุดออกจากฐานพิมพ์เนื่องจากกระแสลม โดยทั่วไปจำเป็นต้องใช้กับเครื่องพิมพ์แบบเปิดเฟรมเท่านั้น กล่าวคือ ไม่มีกล่องหุ้ม\n" "\n" "Enabled = เส้นล้อมชิ้นงานสูงเท่ากับวัตถุที่พิมพ์สูงสุด มิฉะนั้น จะใช้ 'ความสูงของเส้นล้อมชิ้นงาน'\n" -"หมายเหตุ: เมื่อใช้งานดราฟชีลด์ เส้นล้อมชิ้นงานจะถูกพิมพ์ที่ระยะห่างจากเส้นล้อมชิ้นงานจากวัตถุ ดังนั้นหากขอบยึดชิ้นงานยังทำงานอยู่ ขอบยึดชิ้นงานอาจตัดกัน เพื่อหลีกเลี่ยงปัญหานี้ ให้เพิ่มค่าระยะห่างของเส้นล้อมชิ้นงาน\n" +"หมายเหตุ: เมื่อใช้งานแนวป้องกันลม (Draft Shield) เส้นล้อมชิ้นงานจะถูกพิมพ์ที่ระยะห่างจากวัตถุ ดังนั้นหากขอบยึดชิ้นงานยังทำงานอยู่ ขอบยึดชิ้นงานอาจตัดกัน เพื่อหลีกเลี่ยงปัญหานี้ ให้เพิ่มค่าระยะห่างของเส้นล้อมชิ้นงาน\n" msgid "Enabled" msgstr "เปิดใช้" @@ -16318,7 +16362,7 @@ msgid "Sets the finishing flow ratio while ending the spiral. Normally the spira msgstr "ตั้งค่าอัตราส่วนการไหลขั้นสุดท้ายขณะสิ้นสุดเกลียว โดยปกติการเปลี่ยนผ่านของเกลียวจะปรับขนาดอัตราส่วนการไหลจาก 100% เป็น 0% ในระหว่างลูปสุดท้าย ซึ่งในบางกรณีอาจนำไปสู่การรีดขึ้นรูปที่ปลายเกลียว" msgid "If smooth or traditional mode is selected, a timelapse video will be generated for each print. After each layer is printed, a snapshot is taken with the chamber camera. All of these snapshots are composed into a timelapse video when printing completes. If smooth mode is selected, the toolhead will move to the excess chute after each layer is printed and then take a snapshot. Since the melt filament may leak from the nozzle during the process of taking a snapshot, a prime tower is required for smooth mode to wipe the nozzle." -msgstr "หากเลือกโหมดเรียบหรือโหมดดั้งเดิม วิดีโอไทม์แลปส์จะถูกสร้างขึ้นสำหรับการพิมพ์แต่ละครั้ง หลังจากพิมพ์แต่ละชั้นแล้ว กล้องจะถ่ายภาพสแนปช็อตด้วยกล้องแชมเบอร์ สแน็ปช็อตทั้งหมดนี้จะถูกประกอบเป็นวิดีโอไทม์แลปส์เมื่อการพิมพ์เสร็จสิ้น หากเลือกโหมดเรียบ หัวเครื่องมือจะย้ายไปยังรางส่วนเกินหลังจากพิมพ์แต่ละเลเยอร์แล้วจึงถ่ายภาพสแน็ปช็อต เนื่องจากเส้นพลาสติกที่หลอมละลายอาจรั่วไหลออกจากหัวฉีดในระหว่างขั้นตอนการถ่ายภาพ จึงจำเป็นต้องมีไพรม์ทาวเวอร์เพื่อให้โหมดราบรื่นในการเช็ดหัวฉีด" +msgstr "หากเลือกโหมดเรียบหรือโหมดดั้งเดิม วิดีโอไทม์แลปส์จะถูกสร้างขึ้นสำหรับการพิมพ์แต่ละครั้ง หลังจากพิมพ์แต่ละชั้นแล้ว กล้องจะถ่ายภาพสแนปช็อตด้วยกล้องแชมเบอร์ สแน็ปช็อตทั้งหมดนี้จะถูกประกอบเป็นวิดีโอไทม์แลปส์เมื่อการพิมพ์เสร็จสิ้น หากเลือกโหมดเรียบ หัวเครื่องมือจะย้ายไปยังรางส่วนเกินหลังจากพิมพ์แต่ละเลเยอร์แล้วจึงถ่ายภาพสแน็ปช็อต เนื่องจากเส้นพลาสติกที่หลอมละลายอาจรั่วไหลออกจากหัวฉีดในระหว่างขั้นตอนการถ่ายภาพ จึงจำเป็นต้องมี Prime Tower เพื่อให้โหมดราบรื่นในการเช็ดหัวฉีด" msgid "Traditional" msgstr "แบบดั้งเดิม" @@ -16332,7 +16376,7 @@ msgstr "ไทม์แลปส์จุดไกลสุด" # AI Translated msgid "When enabled, the timelapse snapshot is taken at the farthest point from camera instead of traveling to the wipe tower or excess chute. Only effective in traditional timelapse mode on non-I3 printers." -msgstr "เมื่อเปิดใช้งาน ภาพไทม์แลปส์จะถูกถ่ายที่จุดไกลสุดจากกล้องแทนที่จะเดินหัวไปยังทาวเวอร์เช็ดหัวฉีดหรือช่องทิ้งส่วนเกิน มีผลเฉพาะในโหมดไทม์แลปส์แบบดั้งเดิมบนเครื่องพิมพ์ที่ไม่ใช่ I3" +msgstr "เมื่อเปิดใช้งาน ภาพไทม์แลปส์จะถูกถ่ายที่จุดไกลสุดจากกล้องแทนที่จะเดินหัวไปยัง Wipe Tower หรือช่องทิ้งส่วนเกิน มีผลเฉพาะในโหมดไทม์แลปส์แบบดั้งเดิมบนเครื่องพิมพ์ที่ไม่ใช่ I3" msgid "Temperature variation" msgstr "การเปลี่ยนแปลงของอุณหภูมิ" @@ -16381,10 +16425,10 @@ msgid "Enable this option to omit the custom Change filament G-code only at the msgstr "เปิดใช้งานตัวเลือกนี้เพื่อละเว้น G-code เปลี่ยนฟิลาเมนต์แบบกำหนดเองเฉพาะตอนเริ่มต้นการพิมพ์เท่านั้น คำสั่งเปลี่ยนเครื่องมือ (เช่น T0) จะถูกข้ามไปตลอดการพิมพ์ทั้งหมด สิ่งนี้มีประโยชน์สำหรับการพิมพ์หลายวัสดุด้วยตนเอง โดยที่เราใช้ M600/PAUSE เพื่อกระตุ้นการดำเนินการเปลี่ยนเส้นพลาสติกด้วยตนเอง" msgid "Wipe tower type" -msgstr "ชนิดทาวเวอร์เช็ด" +msgstr "ชนิด Wipe Tower" msgid "Choose the wipe tower implementation for multi-material prints. Type 1 is recommended for Bambu and Qidi printers with a filament cutter. Type 2 offers better compatibility with multi-tool and MMU printers and provide overall better compatibility." -msgstr "เลือกการใช้งานไวด์ทาวเวอร์สำหรับการพิมพ์แบบหลายวัสดุ แนะนำให้ใช้ประเภท 1 สำหรับเครื่องพิมพ์ Bambu และ Qidi ที่มีเครื่องตัดเส้นพลาสติก Type 2 ให้ความเข้ากันได้ที่ดีกว่ากับเครื่องพิมพ์หลายเครื่องมือและ MMU และให้ความเข้ากันได้โดยรวมดีขึ้น" +msgstr "เลือกการใช้งาน Wipe Tower สำหรับการพิมพ์แบบหลายวัสดุ แนะนำให้ใช้ประเภท 1 สำหรับเครื่องพิมพ์ Bambu และ Qidi ที่มีเครื่องตัดเส้นพลาสติก Type 2 ให้ความเข้ากันได้ที่ดีกว่ากับเครื่องพิมพ์หลายเครื่องมือและ MMU และให้ความเข้ากันได้โดยรวมดีขึ้น" msgid "Type 1" msgstr "ประเภทที่ 1" @@ -16393,25 +16437,25 @@ msgid "Type 2" msgstr "ประเภทที่ 2" msgid "Purge in prime tower" -msgstr "ระยะเว้นในไพร์มทาวเวอร์" +msgstr "ระยะเว้นใน Prime Tower" msgid "Purge remaining filament into prime tower." -msgstr "ล้างเส้นพลาสติกที่เหลือลงในไพร์มทาวเวอร์" +msgstr "ล้างเส้นพลาสติกที่เหลือลงใน Prime Tower" msgid "Enable filament ramming" msgstr "เปิดใช้งานการอัดกระแทกเส้นเส้นพลาสติก" msgid "Tool change on wipe tower" -msgstr "การเปลี่ยนเครื่องมือบนไวด์ทาวเวอร์" +msgstr "การเปลี่ยนเครื่องมือบน Wipe Tower" msgid "Force the toolhead to travel to the wipe tower before issuing the tool change command (Tx). Only relevant for multi-extruder (multi-toolhead) printers using a Type 2 wipe tower. By default Orca skips the travel on multi-toolhead machines because the firmware handles the head swap, which can result in the Tx command being issued above the printed part. Enable this option if you want the tool change to always be issued above the wipe tower instead." -msgstr "บังคับให้หัวเครื่องมือเคลื่อนที่ไปที่หอเช็ดก่อนที่จะออกคำสั่งเปลี่ยนเครื่องมือ (Tx) เกี่ยวข้องเฉพาะกับเครื่องพิมพ์ที่มีชุดดันเส้นหลายเครื่อง (หลายหัวเครื่องมือ) ที่ใช้แผ่นเช็ดแบบ Type 2 ตามค่าเริ่มต้น Orca จะข้ามการเดินทางบนเครื่องที่มีหัวเครื่องมือหลายหัวเนื่องจากเฟิร์มแวร์จัดการการสลับหัว ซึ่งอาจส่งผลให้มีการออกคำสั่ง Tx เหนือส่วนที่พิมพ์ เปิดใช้งานตัวเลือกนี้หากคุณต้องการให้ทำการเปลี่ยนแปลงเครื่องมือเหนือหอเช็ดแทนเสมอ" +msgstr "บังคับให้หัวเครื่องมือเคลื่อนที่ไปที่ Wipe Tower ก่อนที่จะออกคำสั่งเปลี่ยนเครื่องมือ (Tx) เกี่ยวข้องเฉพาะกับเครื่องพิมพ์ที่มีชุดดันเส้นหลายเครื่อง (หลายหัวเครื่องมือ) ที่ใช้แผ่นเช็ดแบบ Type 2 ตามค่าเริ่มต้น Orca จะข้ามการเดินทางบนเครื่องที่มีหัวเครื่องมือหลายหัวเนื่องจากเฟิร์มแวร์จัดการการสลับหัว ซึ่งอาจส่งผลให้มีการออกคำสั่ง Tx เหนือส่วนที่พิมพ์ เปิดใช้งานตัวเลือกนี้หากคุณต้องการให้ทำการเปลี่ยนแปลงเครื่องมือเหนือ Wipe Tower แทนเสมอ" msgid "No sparse layers (beta)" msgstr "ไม่มีชั้นกระจัดกระจาย (เบต้า)" msgid "If enabled, the wipe tower will not be printed on layers with no tool changes. On layers with a tool change, extruder will travel downward to print the wipe tower. User is responsible for ensuring there is no collision with the print." -msgstr "หากเปิดใช้งาน หอเช็ดจะไม่ถูกพิมพ์บนเลเยอร์โดยไม่มีการเปลี่ยนแปลงเครื่องมือ บนเลเยอร์ที่มีการเปลี่ยนเครื่องมือ ชุดดันเส้นจะเคลื่อนลงด้านล่างเพื่อพิมพ์ไวด์ทาวเวอร์ ผู้ใช้มีหน้าที่รับผิดชอบในการตรวจสอบให้แน่ใจว่าไม่มีการชนกันกับงานพิมพ์" +msgstr "หากเปิดใช้งาน Wipe Tower จะไม่ถูกพิมพ์บนเลเยอร์โดยไม่มีการเปลี่ยนแปลงเครื่องมือ บนเลเยอร์ที่มีการเปลี่ยนเครื่องมือ ชุดดันเส้นจะเคลื่อนลงด้านล่างเพื่อพิมพ์ Wipe Tower ผู้ใช้มีหน้าที่รับผิดชอบในการตรวจสอบให้แน่ใจว่าไม่มีการชนกันกับงานพิมพ์" msgid "Prime all printing extruders" msgstr "ใช้ชุดดันเส้นการพิมพ์ทั้งหมด" @@ -16676,7 +16720,7 @@ msgid "Independent support layer height" msgstr "ความสูงของชั้นรองรับอิสระ" msgid "Support layer uses layer height independent with object layer. This is to support customizing Z-gap and save print time. This option will be invalid when the prime tower is enabled." -msgstr "เลเยอร์ส่วนรองรับใช้ความสูงของเลเยอร์ที่เป็นอิสระจากเลเยอร์วัตถุ เพื่อรองรับการปรับแต่ง Z-gap และประหยัดเวลาในการพิมพ์ ตัวเลือกนี้จะไม่ถูกต้องเมื่อเปิดใช้งานไพรม์ทาวเวอร์" +msgstr "เลเยอร์ส่วนรองรับใช้ความสูงของเลเยอร์ที่เป็นอิสระจากเลเยอร์วัตถุ เพื่อรองรับการปรับแต่ง Z-gap และประหยัดเวลาในการพิมพ์ ตัวเลือกนี้จะไม่ถูกต้องเมื่อเปิดใช้งาน Prime Tower" msgid "Threshold angle" msgstr "มุมเกณฑ์" @@ -16841,13 +16885,13 @@ msgid "This G-code is inserted when filament is changed, including T commands to msgstr "รหัส G นี้จะถูกแทรกเมื่อมีการเปลี่ยนเส้นพลาสติก รวมถึงคำสั่ง T เพื่อกระตุ้นการเปลี่ยนเครื่องมือ" msgid "This G-code is inserted when the extrusion role is changed." -msgstr "G-code นี้จะถูกแทรกเมื่อบทบาทการอัดขึ้นรูปมีการเปลี่ยนแปลง" +msgstr "G-code นี้จะถูกแทรกเมื่อประเภทการพิมพ์มีการเปลี่ยนแปลง" msgid "Change extrusion role G-code (filament)" -msgstr "เปลี่ยนบทบาทการอัดขึ้นรูป G-code (เส้นพลาสติก)" +msgstr "เปลี่ยนประเภทการพิมพ์ G-code (เส้นพลาสติก)" msgid "This G-code is inserted when the extrusion role is changed for the active filament." -msgstr "รหัส G นี้จะถูกแทรกเมื่อมีการเปลี่ยนบทบาทการอัดขึ้นรูปสำหรับเส้นพลาสติกที่ใช้งานอยู่" +msgstr "รหัส G นี้จะถูกแทรกเมื่อมีการเปลี่ยนประเภทการพิมพ์สำหรับเส้นพลาสติกที่ใช้งานอยู่" msgid "Line width for top surfaces. If expressed as a %, it will be computed over the nozzle diameter." msgstr "ความกว้างของเส้นสำหรับพื้นผิวด้านบน หากแสดงเป็น % จะคำนวณตามเส้นผ่านศูนย์กลางของหัวฉีด" @@ -16937,13 +16981,13 @@ msgstr "" "การตั้งค่าในจำนวนการถอนก่อนการล้างการตั้งค่าด้านล่างจะทำการถอนส่วนที่เกินก่อนการล้าง มิฉะนั้นจะดำเนินการหลังจากนั้น" msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." -msgstr "หอเช็ดสามารถใช้เพื่อทำความสะอาดสิ่งตกค้างบนหัวฉีด และทำให้แรงดันในห้องภายในหัวฉีดคงที่ เพื่อหลีกเลี่ยงข้อบกพร่องในลักษณะที่ปรากฏเมื่อพิมพ์วัตถุ" +msgstr "Wipe Tower สามารถใช้เพื่อทำความสะอาดสิ่งตกค้างบนหัวฉีด และทำให้แรงดันในห้องภายในหัวฉีดคงที่ เพื่อหลีกเลี่ยงข้อบกพร่องในลักษณะที่ปรากฏเมื่อพิมพ์วัตถุ" msgid "Internal ribs" -msgstr "ซี่โครงภายใน" +msgstr "ครีบเสริมภายใน" msgid "Enable internal ribs to increase the stability of the prime tower." -msgstr "เปิดใช้งานซี่โครงภายในเพื่อเพิ่มความมั่นคงของหอคอยหลัก" +msgstr "เปิดใช้ครีบเสริมภายในเพื่อเพิ่มความมั่นคงของ Prime Tower" msgid "Purging volumes" msgstr "ปริมาตรการไล่เส้น" @@ -16963,10 +17007,10 @@ msgid "The flush multiplier used in fast purge mode." msgstr "ตัวคูณการไล่เส้นที่ใช้ในโหมดไล่เส้นเร็ว" msgid "Prime volume" -msgstr "ปริมาณเฉพาะ" +msgstr "ปริมาตร Prime" msgid "This is the volume of material to prime the extruder with on the tower." -msgstr "ปริมาตรวัสดุสำหรับเตรียมหัวฉีดบนไพรม์ทาวเวอร์" +msgstr "ปริมาตรวัสดุสำหรับเตรียมหัวฉีดบน Prime Tower" # AI Translated msgid "Prime volume mode" @@ -16974,7 +17018,7 @@ msgstr "โหมดปริมาณการไพรม์" # AI Translated msgid "Selects how the wipe-tower prime and flush volumes are computed on multi-extruder printers." -msgstr "เลือกวิธีการคำนวณปริมาณการไพรม์และการไล่เส้นของทาวเวอร์เช็ดหัวฉีดบนเครื่องพิมพ์แบบหลายชุดดันเส้น" +msgstr "เลือกวิธีการคำนวณปริมาณการไพรม์และการไล่เส้นของ Wipe Tower บนเครื่องพิมพ์แบบหลายชุดดันเส้น" # AI Translated msgid "Saving" @@ -16985,25 +17029,25 @@ msgid "Fast" msgstr "เร็ว" msgid "This is the width of prime towers." -msgstr "ความกว้างของไพรม์ทาวเวอร์" +msgstr "ความกว้างของ Prime Tower" msgid "Wipe tower rotation angle" -msgstr "เช็ดมุมการหมุนของทาวเวอร์" +msgstr "มุมหมุนของ Wipe Tower" msgid "Wipe tower rotation angle with respect to X axis." -msgstr "เช็ดมุมการหมุนของทาวเวอร์ตามแกน X" +msgstr "มุมหมุนของ Wipe Tower เทียบกับแกน X" msgid "Brim width of prime tower, negative number means auto calculated width based on the height of prime tower." -msgstr "ความกว้างขอบของหอคอยหลัก ตัวเลขติดลบหมายถึงความกว้างที่คำนวณโดยอัตโนมัติตามความสูงของหอคอยหลัก" +msgstr "ความกว้างขอบของ Prime Tower ตัวเลขติดลบหมายถึงความกว้างที่คำนวณโดยอัตโนมัติตามความสูงของ Prime Tower" msgid "Stabilization cone apex angle" msgstr "มุมเอเพ็กซ์ของกรวยป้องกันการสั่นไหว" msgid "Angle at the apex of the cone that is used to stabilize the wipe tower. Larger angle means wider base." -msgstr "มุมที่ปลายกรวยที่ใช้เพื่อรักษาเสถียรภาพของหอเช็ด มุมที่ใหญ่ขึ้นหมายถึงฐานที่กว้างขึ้น" +msgstr "มุมที่ปลายกรวยที่ใช้เพื่อรักษาเสถียรภาพของ Wipe Tower มุมที่ใหญ่ขึ้นหมายถึงฐานที่กว้างขึ้น" msgid "Maximum wipe tower print speed" -msgstr "ความเร็วการพิมพ์ไวต์ทาวเวอร์สูงสุด" +msgstr "ความเร็วการพิมพ์ Wipe Tower สูงสุด" msgid "" "The maximum print speed when purging in the wipe tower and printing the wipe tower sparse layers. When purging, if the sparse infill speed or calculated speed from the filament max volumetric speed is lower, the lowest will be used instead.\n" @@ -17020,11 +17064,11 @@ msgstr "" "\n" "เมื่อพิมพ์ชั้นเบาบาง หากความเร็วเส้นรอบวงภายในหรือความเร็วที่คำนวณจากความเร็วปริมาตรสูงสุดของเส้นพลาสติกต่ำกว่า ความเร็วต่ำสุดจะถูกนำมาใช้แทน\n" "\n" -"การเพิ่มความเร็วนี้อาจส่งผลต่อเสถียรภาพของทาวเวอร์ รวมทั้งเพิ่มแรงที่หัวฉีดชนกับหยดใดๆ ที่อาจก่อตัวบนทาวเวอร์เช็ด\n" +"การเพิ่มความเร็วนี้อาจส่งผลต่อเสถียรภาพของทาวเวอร์ รวมทั้งเพิ่มแรงที่หัวฉีดชนกับหยดใดๆ ที่อาจก่อตัวบน Wipe Tower\n" "\n" "ก่อนที่จะเพิ่มพารามิเตอร์นี้เกินกว่าค่าเริ่มต้นที่ 90 มม./วินาที ตรวจสอบให้แน่ใจว่าเครื่องพิมพ์ของคุณสามารถเชื่อมต่อที่ความเร็วที่เพิ่มขึ้นได้อย่างน่าเชื่อถือ และจะมีการควบคุมอย่างดีเมื่อเปลี่ยนเครื่องมือ\n" "\n" -"สำหรับปริมณฑลภายนอกของไวต์ทาวเวอร์ ความเร็วของปริมณฑลภายในจะถูกใช้โดยไม่คำนึงถึงการตั้งค่านี้" +"สำหรับปริมณฑลภายนอกของ Wipe Tower ความเร็วของปริมณฑลภายในจะถูกใช้โดยไม่คำนึงถึงการตั้งค่านี้" msgid "Wall type" msgstr "ชนิดติดผนัง" @@ -17035,10 +17079,10 @@ msgid "" "2. Cone: A cone with a fillet at the bottom to help stabilize the wipe tower.\n" "3. Rib: Adds four ribs to the tower wall for enhanced stability." msgstr "" -"เช็ดทาวเวอร์ชนิดผนังด้านนอก\n" +"Wipe Tower ชนิดผนังด้านนอก\n" "1. สี่เหลี่ยมผืนผ้า: ประเภทผนังเริ่มต้น ซึ่งเป็นสี่เหลี่ยมผืนผ้าที่มีความกว้างและความสูงคงที่\n" -"2. กรวย: กรวยที่มีเนื้ออยู่ด้านล่างเพื่อช่วยรักษาเสถียรภาพของหอเช็ด\n" -"3. ซี่โครง: เพิ่มสี่ซี่โครงเข้ากับผนังหอคอยเพื่อเพิ่มความมั่นคง" +"2. กรวย: กรวยที่มีเนื้ออยู่ด้านล่างเพื่อช่วยรักษาเสถียรภาพของ Wipe Tower\n" +"3. ซี่โครง: เพิ่มสี่ซี่โครงเข้ากับผนัง Wipe Tower เพื่อเพิ่มความมั่นคง" msgid "Rectangle" msgstr "สี่เหลี่ยมผืนผ้า" @@ -17056,40 +17100,40 @@ msgid "Rib width" msgstr "ความกว้างของซี่โครง" msgid "Rib width is always less than half the prime tower side length." -msgstr "ความกว้างของซี่โครงจะน้อยกว่าครึ่งหนึ่งของความยาวด้านของไพรม์ทาวเวอร์เสมอ" +msgstr "ความกว้างของซี่โครงจะน้อยกว่าครึ่งหนึ่งของความยาวด้านของ Prime Tower เสมอ" msgid "Fillet wall" msgstr "ผนังเนื้อ" msgid "The wall of prime tower will fillet." -msgstr "ผนังของไพร์มทาวเวอร์จะแล่เป็นเนื้อเดียวกัน" +msgstr "ผนังของ Prime Tower จะแล่เป็นเนื้อเดียวกัน" msgid "The extruder to use when printing perimeter of the wipe tower. Set to 0 to use the one that is available (non-soluble would be preferred)." -msgstr "ชุดดันเส้นที่จะใช้ในการพิมพ์ปริมณฑลของหอเช็ด ตั้งค่าเป็น 0 เพื่อใช้อันที่มีอยู่ (แนะนำให้ใช้แบบไม่ละลายน้ำ)" +msgstr "ชุดดันเส้นที่จะใช้ในการพิมพ์ปริมณฑลของ Wipe Tower ตั้งค่าเป็น 0 เพื่อใช้อันที่มีอยู่ (แนะนำให้ใช้แบบไม่ละลายน้ำ)" msgid "Purging volumes - load/unload volumes" msgstr "การล้างไดรฟ์ข้อมูล - โหลด/ยกเลิกการโหลดไดรฟ์ข้อมูล" msgid "This vector saves required volumes to change from/to each tool used on the wipe tower. These values are used to simplify creation of the full purging volumes below." -msgstr "เวกเตอร์นี้จะบันทึกปริมาณที่ต้องการเพื่อเปลี่ยนจาก/ไปยังแต่ละเครื่องมือที่ใช้บนไวด์ทาวเวอร์ ค่าเหล่านี้ใช้เพื่อทำให้การสร้างวอลุ่มการล้างข้อมูลทั้งหมดด้านล่างง่ายขึ้น" +msgstr "เวกเตอร์นี้จะบันทึกปริมาณที่ต้องการเพื่อเปลี่ยนจาก/ไปยังแต่ละเครื่องมือที่ใช้บน Wipe Tower ค่าเหล่านี้ใช้เพื่อทำให้การสร้างวอลุ่มการล้างข้อมูลทั้งหมดด้านล่างง่ายขึ้น" msgid "Skip points" msgstr "ข้ามจุด" msgid "The wall of prime tower will skip the start points of wipe path." -msgstr "ผนังของไพร์มทาวเวอร์จะข้ามจุดเริ่มต้นของเส้นทางการเช็ด" +msgstr "ผนังของ Prime Tower จะข้ามจุดเริ่มต้นของเส้นทางการเช็ด" msgid "Enable tower interface features" msgstr "เปิดใช้งานคุณสมบัติอินเทอร์เฟซแบบทาวเวอร์" msgid "Enable optimized prime tower interface behavior when different materials meet." -msgstr "เปิดใช้งานพฤติกรรมอินเทอร์เฟซของไพรม์ทาวเวอร์ที่ได้รับการปรับให้เหมาะสมเมื่อวัสดุที่แตกต่างกันมาบรรจบกัน" +msgstr "เปิดใช้งานพฤติกรรมอินเทอร์เฟซของ Prime Tower ที่ได้รับการปรับให้เหมาะสมเมื่อวัสดุที่แตกต่างกันมาบรรจบกัน" msgid "Cool down from interface boost during prime tower" -msgstr "เย็นลงจากการเพิ่มอินเทอร์เฟซระหว่างหอคอยหลัก" +msgstr "การระบายความร้อนที่เลเยอร์อินเทอร์เฟซของ Prime Tower" msgid "When interface-layer temperature boost is active, set the nozzle back to print temperature at the start of the prime tower so it cools down during the tower." -msgstr "เมื่อเปิดใช้งานการเพิ่มอุณหภูมิของชั้นอินเทอร์เฟซ ให้ตั้งค่าหัวฉีดกลับไปเป็นอุณหภูมิการพิมพ์ที่จุดเริ่มต้นของไพรม์ทาวเวอร์ เพื่อให้เย็นลงระหว่างทาวเวอร์" +msgstr "เมื่อเปิดใช้งานการเพิ่มอุณหภูมิของชั้นอินเทอร์เฟซ ให้ตั้งค่าหัวฉีดกลับไปเป็นอุณหภูมิการพิมพ์ที่จุดเริ่มต้นของ Prime Tower เพื่อให้เย็นลงระหว่าง Prime Tower" msgid "Infill gap" msgstr "การเติมช่องว่าง" @@ -17098,13 +17142,13 @@ msgid "Infill gap." msgstr "การเติมช่องว่าง." msgid "Purging after filament change will be done inside objects' infills. This may lower the amount of waste and decrease the print time. If the walls are printed with transparent filament, the mixed color infill will be visible. It will not take effect unless the prime tower is enabled." -msgstr "การล้างหลังจากเปลี่ยนเส้นพลาสติกจะดำเนินการภายในส่วนไส้ในของวัตถุ สิ่งนี้อาจลดปริมาณขยะและลดเวลาในการพิมพ์ หากผนังพิมพ์ด้วยเส้นพลาสติกโปร่งใส จะเห็นไส้ในสีผสมไว้ด้านนอก มันจะไม่มีผลเว้นแต่จะเปิดใช้งานไพรม์ทาวเวอร์" +msgstr "การล้างหลังจากเปลี่ยนเส้นพลาสติกจะดำเนินการภายในส่วนไส้ในของวัตถุ สิ่งนี้อาจลดปริมาณขยะและลดเวลาในการพิมพ์ หากผนังพิมพ์ด้วยเส้นพลาสติกโปร่งใส จะเห็นไส้ในสีผสมไว้ด้านนอก มันจะไม่มีผลเว้นแต่จะเปิดใช้งาน Prime Tower" msgid "Purging after filament change will be done inside objects' support. This may lower the amount of waste and decrease the print time. It will not take effect unless a prime tower is enabled." -msgstr "การล้างข้อมูลหลังจากเปลี่ยนเส้นพลาสติกจะดำเนินการภายในส่วนรองรับของวัตถุ สิ่งนี้อาจลดปริมาณขยะและลดเวลาในการพิมพ์ มันจะไม่มีผลเว้นแต่จะเปิดใช้งานไพรม์ทาวเวอร์" +msgstr "การล้างข้อมูลหลังจากเปลี่ยนเส้นพลาสติกจะดำเนินการภายในส่วนรองรับของวัตถุ สิ่งนี้อาจลดปริมาณขยะและลดเวลาในการพิมพ์ มันจะไม่มีผลเว้นแต่จะเปิดใช้งาน Prime Tower" msgid "This object will be used to purge the nozzle after a filament change to save filament and decrease the print time. Colors of the objects will be mixed as a result. It will not take effect unless the prime tower is enabled." -msgstr "วัตถุนี้จะใช้ในการล้างหัวฉีดหลังจากเปลี่ยนเส้นพลาสติกเพื่อประหยัดเส้นพลาสติกและลดเวลาในการพิมพ์ สีของวัตถุจะผสมกัน มันจะไม่มีผลเว้นแต่จะเปิดใช้งานไพรม์ทาวเวอร์" +msgstr "วัตถุนี้จะใช้ในการล้างหัวฉีดหลังจากเปลี่ยนเส้นพลาสติกเพื่อประหยัดเส้นพลาสติกและลดเวลาในการพิมพ์ สีของวัตถุจะผสมกัน มันจะไม่มีผลเว้นแต่จะเปิดใช้งาน Prime Tower" msgid "Maximal bridging distance" msgstr "ระยะเชื่อมต่อสูงสุด" @@ -17113,16 +17157,16 @@ msgid "Maximal distance between supports on sparse infill sections." msgstr "ระยะห่างสูงสุดระหว่างส่วนรองรับในส่วน ไส้ใน แบบกระจัดกระจาย" msgid "Wipe tower purge lines spacing" -msgstr "เช็ดระยะห่างบรรทัดล้างทาวเวอร์" +msgstr "ระยะห่างเส้นไล่พลาสติกของ Wipe Tower" msgid "Spacing of purge lines on the wipe tower." -msgstr "ระยะห่างของเส้นไล่ล้างบนหอเช็ด" +msgstr "ระยะห่างของเส้นไล่ล้างบน Wipe Tower" msgid "Extra flow for purging" msgstr "กระแสพิเศษสำหรับการล้าง" msgid "Extra flow used for the purging lines on the wipe tower. This makes the purging lines thicker or narrower than they normally would be. The spacing is adjusted automatically." -msgstr "การไหลพิเศษที่ใช้สำหรับท่อไล่ล้างบนหอเช็ด ซึ่งจะทำให้เส้นการล้างหนาหรือแคบกว่าปกติ ระยะห่างจะถูกปรับโดยอัตโนมัติ" +msgstr "การไหลพิเศษที่ใช้สำหรับท่อไล่ล้างบน Wipe Tower ซึ่งจะทำให้เส้นการล้างหนาหรือแคบกว่าปกติ ระยะห่างจะถูกปรับโดยอัตโนมัติ" msgid "Idle temperature" msgstr "อุณหภูมิว่าง" @@ -17704,10 +17748,10 @@ msgid "Specific for sequential printing. Zero-based index of currently printed o msgstr "เฉพาะสำหรับการพิมพ์ตามลำดับ ดัชนีแบบศูนย์ของวัตถุที่พิมพ์ในปัจจุบัน" msgid "Has wipe tower" -msgstr "มีหอเช็ด" +msgstr "มี Wipe Tower" msgid "Whether or not wipe tower is being generated in the print." -msgstr "มีการสร้างเช็ดทาวเวอร์ในการพิมพ์หรือไม่" +msgstr "มีการสร้าง Wipe Tower ในการพิมพ์หรือไม่" msgid "Initial extruder" msgstr "ชุดดันเส้นเริ่มต้น" @@ -17794,16 +17838,16 @@ msgid "Total cost of all material used in the print. Calculated from filament_co msgstr "ต้นทุนรวมของวัสดุทั้งหมดที่ใช้ในการพิมพ์ คำนวณจากค่า fil_cost ในการตั้งค่า เส้นพลาสติก" msgid "Total wipe tower cost" -msgstr "ต้นทุนเช็ดทาวเวอร์ทั้งหมด" +msgstr "ต้นทุน Wipe Tower ทั้งหมด" msgid "Total cost of the material wasted on the wipe tower. Calculated from filament_cost value in Filament Settings." -msgstr "ต้นทุนรวมของวัสดุที่เสียไปบนไวด์ทาวเวอร์ คำนวณจากค่า fil_cost ในการตั้งค่า เส้นพลาสติก" +msgstr "ต้นทุนรวมของวัสดุที่เสียไปบน Wipe Tower คำนวณจากค่า fil_cost ในการตั้งค่า เส้นพลาสติก" msgid "Wipe tower volume" msgstr "เช็ดปริมาตรทาวเวอร์" msgid "Total filament volume extruded on the wipe tower." -msgstr "ปริมาตรเส้นพลาสติกทั้งหมดที่อัดบนไวด์ทาวเวอร์" +msgstr "ปริมาตรเส้นพลาสติกทั้งหมดที่อัดบน Wipe Tower" msgid "Used filament" msgstr "เส้นพลาสติกที่ใช้แล้ว" @@ -18001,8 +18045,8 @@ msgid "" "An object has enabled XY Size compensation which will not be used because it is also fuzzy skin painted.\n" "XY Size compensation cannot be combined with fuzzy skin painting." msgstr "" -"วัตถุได้เปิดใช้งานการชดเชยขนาด XY ซึ่งจะไม่ถูกใช้เนื่องจากเป็นสีที่ไม่ชัดเจนเช่นกัน\n" -"การชดเชยขนาด XY ไม่สามารถใช้ร่วมกับการลงสีผิวแบบคลุมเครือได้" +"วัตถุได้เปิดใช้งานการชดเชยขนาด XY ซึ่งจะไม่ถูกใช้เนื่องจากถูกระบายสีผิวฟัซซีไว้เช่นกัน\n" +"การชดเชยขนาด XY ไม่สามารถใช้ร่วมกับการระบายสีผิวฟัซซีได้" msgid "Object name" msgstr "ชื่อออบเจ็กต์" @@ -18524,6 +18568,20 @@ msgstr "" "มีที่อยู่ IP หลายแห่งที่ใช้ชื่อโฮสต์ %1%\n" "โปรดเลือกอันที่ควรใช้" +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "ปรับขนาดอัตโนมัติตามหัวฉีด" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"โมเดลนี้ออกแบบมาสำหรับหัวฉีดขนาด 0.4 mm และความสูงเลเยอร์ 0.2 mm \n" +"เมื่อเปิดใช้งานตัวเลือกการปรับขนาด (แนะนำ) โมเดลจะปรับขนาดแบบไดนามิกให้ตรงกับเส้นผ่านศูนย์กลางหัวฉีดปัจจุบันและความสูงเลเยอร์ที่เหมาะสม ทำให้การทดสอบทั้งแม่นยำและอ่านค่าได้ง่าย\n" +"ปิดการปรับขนาดเฉพาะเมื่อคุณต้องการพิมพ์โมเดลอ้างอิงตามขนาดเดิมทุกประการ" + msgid "PA Calibration" msgstr "ปรับเทียบ PA" @@ -18660,6 +18718,14 @@ msgstr "ความเร็วเริ่มต้น:" msgid "End speed: " msgstr "ความเร็วสิ้นสุด:" +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "ปรับอัตโนมัติตามความเร็วปริมาตรสูงสุด" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "หากความเร็วปลายทางจะเกินความเร็วปริมาตรสูงสุดของเส้นพลาสติก ระบบจะลดความสูงเลเยอร์โดยอัตโนมัติ (โดยคงค่ามาตรฐานไว้และอยู่ภายในขีดจำกัดของเครื่อง) เพื่อให้ถึงค่าดังกล่าว หากแม้แต่ความสูงเลเยอร์ต่ำสุดยังไม่เพียงพอ ระบบจะลดความเร็วปลายทางแทน" + msgid "" "Please input valid values:\n" "start > 10\n" @@ -18671,6 +18737,57 @@ msgstr "" "ขั้นตอน >= 0\n" "สิ้นสุด> เริ่มต้น + ขั้นตอน" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"ความเร็วปลายทาง (%.0f mm/s) เกินความเร็วปริมาตรสูงสุดของเส้นพลาสติก (%.1f mm³/s) ซึ่งจำกัดผนังด้านนอกไว้ที่ประมาณ %.0f mm/s ที่ความกว้างเส้นและความสูงเลเยอร์นี้\n" +" ความเร็วที่สูงกว่านี้จะถูกจำกัดไว้ ดังนั้นบล็อกด้านบนของทาวเวอร์จะไม่พิมพ์ด้วยความเร็วที่ร้องขอ\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"ความเร็วปลายทาง (%.0f mm/s) เกินความเร็วปริมาตรสูงสุดของเส้นพลาสติก (%.1f mm³/s) ที่ความสูงเลเยอร์เริ่มต้น (%.2f mm)\n" +"\n" +"ความสูงเลเยอร์ถูกลดลงเป็น %.2f mm (ค่าที่ใช้ในพรีเซ็ตของเครื่องพิมพ์นี้) เพื่อให้ทาวเวอร์ถึงความเร็วที่ร้องขอได้" + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"แม้แต่ที่ความสูงเลเยอร์ต่ำสุดที่ใช้ในพรีเซ็ตของเครื่องพิมพ์นี้ (%.2f mm) ความเร็วปลายทาง (%.0f mm/s) ก็ยังเกินความเร็วปริมาตรสูงสุดของเส้นพลาสติก (%.1f mm³/s)\n" +"\n" +"ความสูงเลเยอร์จะถูกตั้งเป็น %.2f mm และความเร็วปลายทางจะถูกลดลงเป็น %.0f mm/s\n" +"\n" +"ดำเนินการต่อหรือไม่?" + +# AI Translated +msgid "Continue anyway?" +msgstr "ดำเนินการต่ออยู่ดีหรือไม่?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "เปิดใช้งาน \"ปรับอัตโนมัติ\" เพื่อแก้ไขปัญหานี้โดยอัตโนมัติ หรือดำเนินการต่ออยู่ดี?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "เปิดใช้งาน \"ปรับขนาดอัตโนมัติตามหัวฉีด\" และ \"ปรับอัตโนมัติ\" เพื่อแก้ไขปัญหานี้โดยอัตโนมัติ หรือดำเนินการต่ออยู่ดี?" + msgid "Start retraction length: " msgstr "เริ่มต้นความยาวการดึงกลับ:" @@ -20474,7 +20591,7 @@ msgid "Auto-generate" msgstr "สร้างอัตโนมัติ" msgid "Generate brim ears using Max angle and Detection radius" -msgstr "สร้างหูขอบยึดชิ้นงานนกโดยใช้มุมสูงสุดและรัศมีการตรวจจับ" +msgstr "สร้างหูขอบยึดชิ้นงาน (Brim Ears) โดยใช้มุมสูงสุดและรัศมีการตรวจจับ" msgid "Add or Select" msgstr "เพิ่มหรือเลือก" @@ -20489,7 +20606,7 @@ msgid "invalid brim ears" msgstr "หูขอบยึดชิ้นงานไม่ถูกต้อง" msgid "Brim Ears" -msgstr "หูขอบยึดชิ้นงาน" +msgstr "หูขอบยึดชิ้นงาน (Brim Ears)" msgid "Please select single object." msgstr "กรุณาเลือกวัตถุเดียว" @@ -21244,6 +21361,9 @@ msgstr "" "หลีกเลี่ยงการบิดเบี้ยว\n" "คุณรู้หรือไม่ว่าเมื่อพิมพ์วัสดุที่มีแนวโน้มที่จะเกิดการบิดเบี้ยว เช่น ABS การเพิ่มอุณหภูมิฐานพิมพ์อย่างเหมาะสมสามารถลดความน่าจะเป็นของการบิดเบี้ยวได้" +#~ msgid "Print order within a single layer." +#~ msgstr "สั่งพิมพ์ภายในชั้นเดียว" + #~ msgid "Bottom" #~ msgstr "ล่าง" @@ -21331,9 +21451,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Renders cast shadows on the plate in realistic view." #~ msgstr "แสดงเงาแบบทอดบนเพลตในมุมมองแบบสมจริง" @@ -21455,7 +21572,7 @@ msgstr "" #~ msgstr "เนื้อหาที่ตั้งไว้ล่วงหน้ามีขนาดใหญ่เกินกว่าจะซิงค์กับระบบคลาวด์ (เกิน 1MB) โปรดลดขนาดที่กำหนดไว้ล่วงหน้าโดยการลบการกำหนดค่าที่กำหนดเองออกหรือใช้เฉพาะในเครื่องเท่านั้น" #~ msgid "Enable adaptive pressure advance for overhangs (beta)" -#~ msgstr "เปิดใช้งานการปรับPressure Advanceสำหรับระยะยื่น (เบต้า)" +#~ msgstr "เปิดใช้ Adaptive Pressure Advance สำหรับส่วนยื่น (เบต้า)" #~ msgid "" #~ "Enable adaptive PA for overhangs as well as when flow changes within the same feature. This is an experimental option, as if the PA profile is not set accurately, it will cause uniformity issues on the external surfaces before and after overhangs.\n" @@ -21465,7 +21582,7 @@ msgstr "" #~ "ไม่รองรับเครื่องพิมพ์ Prusa เพราะจะหยุดชั่วคราวเพื่อประมวลผลการเปลี่ยน PA ทำให้เกิดความล่าช้าและข้อบกพร่อง" #~ msgid "Pressure advance for bridges" -#~ msgstr "แรงดันล่วงหน้า (Pressure Advance)สำหรับสะพาน" +#~ msgstr "Pressure Advance สำหรับสะพาน" #~ msgid "" #~ "Pressure advance value for bridges. Set to 0 to disable.\n" diff --git a/localization/i18n/tr/OrcaSlicer_tr.po b/localization/i18n/tr/OrcaSlicer_tr.po index 697fa76b56..467b3c355b 100644 --- a/localization/i18n/tr/OrcaSlicer_tr.po +++ b/localization/i18n/tr/OrcaSlicer_tr.po @@ -3,8 +3,8 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" -"PO-Revision-Date: 2026-04-08 23:59+0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" +"PO-Revision-Date: 2026-08-01 20:32+0300\n" "Last-Translator: GlauTech\n" "Language-Team: \n" "Language: tr\n" @@ -12,7 +12,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n==1) ? 0 : 1;\n" -"X-Generator: Po Translator App\n" +"X-Generator: Poedit 3.9\n" # AI Translated msgid "Main Extruder" @@ -84,10 +84,10 @@ msgid "Left Nozzle" msgstr "Sol Nozul" msgid "Left nozzle" -msgstr "Sol meme" +msgstr "Sol nozul" msgid "left nozzle" -msgstr "sol meme" +msgstr "sol nozul" msgid "Right Nozzle" msgstr "Sağ Nozul" @@ -96,7 +96,7 @@ msgid "Right nozzle" msgstr "Sağ nozul" msgid "right nozzle" -msgstr "sağ meme" +msgstr "sağ nozul" # AI Translated msgid "Main Hotend" @@ -818,7 +818,7 @@ msgid "Size" msgstr "Boyut" msgid "Uniform scale" -msgstr "düzgün ölçek" +msgstr "Orantılı ölçekleme" msgid "Planar" msgstr "Düzlemsel" @@ -1159,7 +1159,7 @@ msgid "Show wireframe" msgstr "Wireframe göster" msgid "Unable to apply when processing preview" -msgstr "İşlem önizlemesi sırasında uygulanamaz." +msgstr "Önizleme işlenirken uygulanamaz" msgid "Operation already cancelling. Please wait a few seconds." msgstr "İşlem zaten iptal ediliyor. Lütfen birkaç saniye bekleyin." @@ -1727,7 +1727,7 @@ msgid "Change file" msgstr "Dosyayı değiştir" msgid "Change to another SVG file." -msgstr "Başka bir .svg dosyasına geçin" +msgstr "Farklı bir SVG dosyası seç." msgid "Forget the file path" msgstr "Dosya yolunu unut" @@ -1754,7 +1754,7 @@ msgid "Save SVG file" msgstr "SVG dosyasını kaydet" msgid "Save as SVG file." -msgstr "'.svg' dosyası olarak kaydet" +msgstr "SVG dosyası olarak kaydet." msgid "Size in emboss direction." msgstr "Kabartma yönünde boyut." @@ -2430,7 +2430,7 @@ msgstr "Gizlilik Politikası Güncellemesi" # AI Translated #, c-format, boost-format msgid "your Orca Cloud profile (user ID: \"%s\")" -msgstr "Orca Cloud profiliniz (kullanıcı kimliği: \"%s\")" +msgstr "orca Cloud profiliniz (Kullanıcı ID: \"%s\")" # AI Translated msgid "your default profile" @@ -2991,22 +2991,22 @@ msgid "Auto orientation" msgstr "Otomatik yönlendirme" msgid "Auto orient the object to improve print quality" -msgstr "Baskı kalitesini artırmak için nesneyi otomatik olarak yönlendirin." +msgstr "Baskı kalitesini artırmak için nesneyi otomatik yönlendir" msgid "Edit" msgstr "Düzenle" msgid "Merge with" -msgstr "Şununla birleştir:" +msgstr "Şununla birleştir" msgid "Delete this filament" -msgstr "Bu filamanı sil" +msgstr "Bu filamenti sil" msgid "Select All" msgstr "Hepsini seç" msgid "Select all objects on the current plate" -msgstr "geçerli plakadaki tüm nesneleri seç" +msgstr "Mevcut plakadaki tüm nesneleri seç" msgid "Select All Plates" msgstr "Tüm Plakaları Seç" @@ -3018,7 +3018,7 @@ msgid "Delete All" msgstr "Hepsini sil" msgid "Delete all objects on the current plate" -msgstr "geçerli plakadaki tüm nesneleri sil" +msgstr "Mevcut tabladaki tüm nesneleri sil" msgid "Arrange" msgstr "Hizala" @@ -3410,7 +3410,7 @@ msgid "Invalid numeric." msgstr "Geçersiz sayı." msgid "One cell can only be copied to one or more cells in the same column." -msgstr "bir hücre aynı sütundaki yalnızca bir veya daha fazla hücreye kopyalanabilir" +msgstr "Bir hücre yalnızca aynı sütundaki bir veya daha fazla hücreye kopyalanabilir." msgid "Copying multiple cells is not supported." msgstr "Birden fazla hücre kopyalama desteklenmiyor." @@ -3478,13 +3478,13 @@ msgid "More" msgstr "Daha" msgid "Open Preferences" -msgstr "Tercihler'i açın." +msgstr "Tercihleri Aç" msgid "Open next tip" -msgstr "Sonraki ipucunu açın." +msgstr "Sonraki ipucunu aç" msgid "Open documentation in web browser" -msgstr "Belgeleri web tarayıcısında açın." +msgstr "Dokümantasyonu web tarayıcısında aç" msgid "Color" msgstr "Renk" @@ -3517,7 +3517,7 @@ msgid "Jump to layer" msgstr "Katmana Atla" msgid "Please enter the layer number." -msgstr "Lütfen katman numarasını girin" +msgstr "Lütfen katman numarasını girin." msgid "Add Pause" msgstr "Duraklatma Ekle" @@ -3605,7 +3605,7 @@ msgid "Choose an AMS slot then press \"Load\" or \"Unload\" button to automatica msgstr "Bir AMS yuvası seçin ve filamentleri otomatik olarak yüklemek veya boşaltmak için “Yükle” veya “Boşalt” düğmesine basın." msgid "Filament type is unknown which is required to perform this action. Please set target filament's informations." -msgstr "Bu eylemi gerçekleştirmek için gereken filaman türü bilinmiyor. Lütfen hedef filamanın bilgilerini ayarlayın." +msgstr "Bu eylemi gerçekleştirmek için gereken filament türü bilinmiyor. Lütfen hedef filamentin bilgilerini ayarlayın." # AI Translated msgid "AMS has not been initialized. Please initialize it before use." @@ -3759,10 +3759,10 @@ msgid "Switch track at Filament Track Switch" msgstr "Filament Track Switch'te hattı değiştir" msgid "The maximum temperature cannot exceed " -msgstr "Maksimum sıcaklık aşılamaz" +msgstr "Maksimum sıcaklık şu değeri aşamaz: " msgid "The minmum temperature should not be less than " -msgstr "Minimum sıcaklık," +msgstr "Minimum sıcaklık şu değerden az olamaz: " # AI Translated msgid "Type to filter..." @@ -3913,6 +3913,10 @@ msgstr "Hizalanıyor..." msgid "Arranging" msgstr "Hizalanıyor" +# AI Translated +msgid "Arranging " +msgstr "Hizalanıyor " + msgid "Arranging canceled." msgstr "Hizalama iptal edildi." @@ -4280,7 +4284,7 @@ msgid "" "The nozzle flow is not set. Please set the nozzle flow rate before editing the filament.\n" "'Device -> Print parts'" msgstr "" -"Meme akışı ayarlanmamış. Lütfen filamenti düzenlemeden önce nozül akış hızını ayarlayın.\n" +"Nozul akışı ayarlanmamış. Lütfen filamenti düzenlemeden önce nozul akış hızını ayarlayın.\n" "'Cihaz -> Parçaları yazdır'" msgid "AMS" @@ -4366,7 +4370,7 @@ msgid "" "And you can click it to modify" msgstr "" "Üst yarı alanı: Orijinal\n" -"Alt yarı alan: Eşleme kaldırıldığında orijinal projedeki filaman kullanılacaktır.\n" +"Alt yarı alan: Eşleme kaldırıldığında orijinal projedeki filament kullanılacaktır.\n" "Ve değiştirmek için tıklayabilirsiniz" msgid "" @@ -4467,7 +4471,7 @@ msgstr "AMS'yi Etkinleştirme" # AI Translated msgid "Print using filament on external spool." -msgstr "Harici makaradaki filamenti kullanarak yazdırma" +msgstr "Harici makaradaki filamenti kullanarak yazdır." msgid "Print with filament in AMS" msgstr "AMS içerisindeki filamentlerle yazdırma" @@ -4504,7 +4508,7 @@ msgid "" "When the current filament runs out, the printer will use identical filament to continue printing.\n" "*Identical filament: same brand, type and color." msgstr "" -"Mevcut filaman bittiğinde yazıcı, yazdırmaya devam etmek için aynı filamanı kullanacaktır.\n" +"Mevcut filament bittiğinde yazıcı, yazdırmaya devam etmek için aynı filamenti kullanacaktır.\n" "*Aynı filament: aynı marka, tip ve renkte." msgid "DRY" @@ -4523,14 +4527,14 @@ msgid "The AMS will automatically read the filament information when inserting a msgstr "AMS, yeni bir Bambu Lab filamenti takıldığında filament bilgilerini otomatik olarak okuyacaktır. Bu yaklaşık 20 saniye sürer." msgid "Note: if a new filament is inserted during printing, the AMS will not automatically read any information until printing is completed." -msgstr "Not: Yazdırma sırasında yeni bir filaman takılırsa AMS, yazdırma tamamlanana kadar herhangi bir bilgiyi otomatik olarak okumayacaktır." +msgstr "Not: Yazdırma sırasında yeni bir filament takılırsa AMS, yazdırma tamamlanana kadar herhangi bir bilgiyi otomatik olarak okumayacaktır." msgid "When inserting a new filament, the AMS will not automatically read its information, leaving it blank for you to enter manually." msgstr "Yeni bir filament yerleştirirken AMS, bilgileri otomatik olarak okumaz ve manuel olarak girmeniz için boş bırakır." # AI Translated msgid "Update on startup" -msgstr "Başlangıçta güncelle" +msgstr "Açılışta güncelle" msgid "The AMS will automatically read the information of inserted filament on start-up. It will take about 1 minute. The reading process will rotate the filament spools." msgstr "AMS, başlangıçta takılan filamentin bilgilerini otomatik olarak okuyacaktır. Yaklaşık 1 dakika sürecektir. Okuma işlemi filament makaralarını saracaktır." @@ -4566,7 +4570,7 @@ msgid "The printer is busy and cannot switch AMS type." msgstr "Yazıcı meşgul ve AMS türünü değiştiremiyor." msgid "Please unload all filament before switching." -msgstr "Lütfen değiştirmeden önce tüm filamanı boşaltın." +msgstr "Lütfen değiştirmeden önce tüm filamenti boşaltın." msgid "AMS type switching needs firmware update, taking about 30s. Switch now?" msgstr "AMS tipi anahtarlama, yaklaşık 30 saniye süren ürün yazılımı güncellemesi gerektirir. Şimdi değiştirilsin mi?" @@ -4590,7 +4594,7 @@ msgid "Failed to install the plug-in. The plug-in file may be in use. Please res msgstr "Eklenti yüklenemedi. Eklenti dosyası kullanımda olabilir. Lütfen OrcaSlicer'ı yeniden başlatın ve tekrar deneyin. Ayrıca anti-virüs yazılımı tarafından engellenip engellenmediğini veya silinip silinmediğini de kontrol edin." msgid "Click here to see more info" -msgstr "daha fazla bilgi görmek için burayı tıklayın" +msgstr "Daha fazla bilgi görmek için buraya tıklayın" msgid "The network plug-in was installed but could not be loaded. Please restart the application." msgstr "Ağ eklentisi kuruldu ancak yüklenemedi. Lütfen uygulamayı yeniden başlatın." @@ -4608,7 +4612,7 @@ msgid "Go Home" msgstr "Anasayfaya Git" msgid "An error occurred. The system may have run out of memory, or a bug may have occurred." -msgstr "Bir hata oluştu. Belki sistemin hafızası yeterli değildir veya programın bir hatasıdır" +msgstr "Bir hata oluştu. Sistem belleği tükenmiş veya bir yazılım hatası meydana gelmiş olabilir." #, boost-format msgid "A fatal error occurred: \"%1%\"" @@ -4618,7 +4622,7 @@ msgid "Please save your project and restart the application." msgstr "Lütfen projeyi kaydedin ve programı yeniden başlatın." msgid "Processing G-Code from previous file…" -msgstr "Önceki dosyadan G Kodu işleniyor..." +msgstr "Önceki dosyadan G-Kodu işleniyor…" msgid "Slicing complete" msgstr "Dilimleme tamamlandı" @@ -4682,7 +4686,7 @@ msgid "G-code file exported to %1%" msgstr "G kodu dosyası %1%’e aktarıldı" msgid "Unknown error with G-code export" -msgstr "G kodunu dışa aktarırken bilinmeyen hata." +msgstr "G-code dışa aktarımında bilinmeyen hata" #, boost-format msgid "" @@ -4695,7 +4699,7 @@ msgstr "" "Kaynak dosya %2%." msgid "Copying of the temporary G-code to the output G-code failed." -msgstr "Geçici G kodunun çıkış G koduna kopyalanması başarısız oldu" +msgstr "Geçici G-kodu dosyasının çıktı G-kodu dosyasına kopyalanması başarısız oldu." #, boost-format msgid "Scheduling upload to `%1%`. See Window -> Print Host Upload Queue" @@ -4797,7 +4801,7 @@ msgid "" "Value was reset to 0.5" msgstr "" "Maksimum hacimsel hız çok küçük.\n" -"0,5'e sıfırla." +"Değer 0.5 olarak sıfırlandı" #, c-format, boost-format msgid "Current chamber temperature is higher than the material's safe temperature; this may result in material softening and nozzle clogs. The maximum safe temperature for the material is %d" @@ -4812,24 +4816,24 @@ msgid "" "Layer height too small\n" "It has been reset to 0.2" msgstr "" -"Katman yüksekliği çok küçük.\n" -"0,2'ye sıfırla." +"Katman yüksekliği çok küçük\n" +"Değer 0.2 olarak yeniden ayarlandı" msgid "" "Ironing spacing too small\n" "It has been reset to 0.1" msgstr "" -"Çok küçük ütüleme aralığı.\n" -"0,1'e sıfırla." +"Ütüleme satır aralığı çok küçük\n" +"Değer 0.1 olarak yeniden ayarlandı" msgid "" "Zero initial layer height is invalid.\n" "\n" "The first layer height will be reset to 0.2." msgstr "" -"Sıfır başlangıç katman yüksekliği geçersiz.\n" +"İlk katman yüksekliği sıfır olamaz.\n" "\n" -"İlk katman yüksekliği 0.2 olarak sıfırlanacak." +"İlk katman yüksekliği 0.2 olarak sıfırlandı." # AI Translated msgid "" @@ -4905,8 +4909,8 @@ msgid "" "seam_slope_start_height need to be smaller than layer_height.\n" "Reset to 0." msgstr "" -"Dikiş eğimi başlangıç yüksekliğinin katman yüksekliğinden daha küçük olması gerekir.\n" -"0 a sıfırla." +"seam_slope_start_height, layer_height değerinden küçük olmalıdır.\n" +"Değeri 0 yapın." #, no-c-format, no-boost-format msgid "" @@ -4965,7 +4969,7 @@ msgid "Paused (filament ran out)" msgstr "Duraklatıldı (filament bitti)" msgid "Heating nozzle" -msgstr "Isıtma memesi" +msgstr "Isıtma nozulü" msgid "Calibrating dynamic flow" msgstr "Dinamik akışı kalibre etme" @@ -5061,7 +5065,7 @@ msgid "Measure motion accuracy" msgstr "Hareket doğruluğunu ölçün" msgid "Nozzle offset calibration" -msgstr "Meme ofset kalibrasyonu" +msgstr "Nozul ofset kalibrasyonu" msgid "High temperature auto bed leveling" msgstr "Yüksek sıcaklıkta otomatik yatak tesviyesi" @@ -5118,7 +5122,7 @@ msgid "Measuring Surface" msgstr "Ölçüm Yüzeyi" msgid "Calibrating the detection position of nozzle clumping" -msgstr "Meme topaklanmasının algılama konumunu kalibre etme" +msgstr "Nozul topaklanmasının algılama konumunu kalibre etme" msgid "Update successful." msgstr "Güncelleme başarılı." @@ -5149,17 +5153,17 @@ msgstr "Güvenliğinizi sağlamak için belirli işleme görevleri (lazer gibi) #, c-format, boost-format msgid "The chamber temperature is too high, which may cause the filament to soften. Please wait until the chamber temperature drops below %d℃. You may open the front door or enable fans to cool down." -msgstr "Oda sıcaklığı çok yüksek, bu da filamanın yumuşamasına neden olabilir. Lütfen hazne sıcaklığı %d°C'nin altına düşene kadar bekleyin. Ön kapıyı açabilir veya fanların soğumasını sağlayabilirsiniz." +msgstr "Oda sıcaklığı çok yüksek, bu da filamentin yumuşamasına neden olabilir. Lütfen hazne sıcaklığı %d°C'nin altına düşene kadar bekleyin. Ön kapıyı açabilir veya fanların soğumasını sağlayabilirsiniz." #, c-format, boost-format msgid "AMS temperature is too high, which may cause the filament to soften. Please wait until the AMS temperature drops below %d℃." -msgstr "AMS sıcaklığı çok yüksek, bu da filamanın yumuşamasına neden olabilir. Lütfen AMS sıcaklığı %d°C'nin altına düşene kadar bekleyin." +msgstr "AMS sıcaklığı çok yüksek, bu da filamentin yumuşamasına neden olabilir. Lütfen AMS sıcaklığı %d°C'nin altına düşene kadar bekleyin." msgid "The current chamber temperature or the target chamber temperature exceeds 45℃. In order to avoid extruder clogging, low temperature filament(PLA/PETG/TPU) is not allowed to be loaded." msgstr "Mevcut hazne sıcaklığı veya hedef hazne sıcaklığı 45°C'yi aşıyor. Ekstruderin tıkanmasını önlemek için düşük sıcaklık filamentinin (PLA/PETG/TPU) yüklenmesine izin verilmez." msgid "Low temperature filament(PLA/PETG/TPU) is loaded in the extruder. In order to avoid extruder clogging, it is not allowed to set the chamber temperature." -msgstr "Ekstrudere düşük sıcaklık filamanı (PLA/PETG/TPU) yüklenir. Ekstruderin tıkanmasını önlemek için hazne sıcaklığının ayarlanmasına izin verilmez." +msgstr "Ekstrudere düşük sıcaklık filamenti (PLA/PETG/TPU) yüklenir. Ekstruderin tıkanmasını önlemek için hazne sıcaklığının ayarlanmasına izin verilmez." msgid "When you set the chamber temperature below 40℃, the chamber temperature control will not be activated, and the target chamber temperature will automatically be set to 0℃." msgstr "Hazne sıcaklığını 40°C'nin altına ayarladığınızda, hazne sıcaklık kontrolü etkinleştirilmeyecektir. Ve hedef hazne sıcaklığı otomatik olarak 0°C'ye ayarlanacaktır." @@ -5473,7 +5477,7 @@ msgid "Noop" msgstr "Hayır" msgid "Retract" -msgstr "Geri çekme" +msgstr "Geri Çekme" msgid "Unretract" msgstr "İleri İtme" @@ -5564,10 +5568,10 @@ msgid "Layer Time: " msgstr "Katman Süresi: " msgid "Tool: " -msgstr "Alet:" +msgstr "Kafa: " msgid "Color: " -msgstr "Renk:" +msgstr "Renk: " # AI Translated msgid "Acceleration: " @@ -5577,7 +5581,7 @@ msgid "Jerk: " msgstr "Jerk: " msgid "PA: " -msgstr "PA:" +msgstr "PA: " msgid "mm/s" msgstr "mm/s" @@ -5776,7 +5780,7 @@ msgid "" "Please ensure the filaments used by this object are not arranged to other nozzles." msgstr "" "Yalnızca sol/sağ püskürtme ucu alanına bir nesne yerleştirilmiş veya sol püskürtme ucunun yazdırılabilir yüksekliğini aşıyor.\n" -"Lütfen bu nesne tarafından kullanılan filamanların diğer püskürtme uçlarına göre düzenlenmediğinden emin olun." +"Lütfen bu nesne tarafından kullanılan filamentlerin diğer püskürtme uçlarına göre düzenlenmediğinden emin olun." msgid "" "An object is laid over the boundary of plate or exceeds the height limit.\n" @@ -5848,7 +5852,7 @@ msgid "The position or size of the model %s exceeds the %s's printable range." msgstr "%s modelinin konumu veya boyutu %s'nin yazdırılabilir aralığını aşıyor." msgid " Please check and adjust the part's position or size to fit the printable range:\n" -msgstr "Lütfen parçanın konumunu veya boyutunu kontrol edip yazdırılabilir aralığa uyacak şekilde ayarlayın:\n" +msgstr " Lütfen parçanın konumunu veya boyutunu basılabilir alana sığacak şekilde kontrol edip ayarlayın:\n" #, boost-format msgid "Left nozzle: X:%1%-%2%, Y:%3%-%4%, Z:%5%-%6%\n" @@ -5954,7 +5958,7 @@ msgid "Select Plate" msgstr "Plaka Seç" msgid "Slicing" -msgstr "Dilimleniyor" +msgstr "Dilimleme" msgid "Slice all" msgstr "Hepsini dilimle" @@ -6068,19 +6072,19 @@ msgstr "Araç %d" #, c-format, boost-format msgid "Filament %s is placed in the %s, but the generated G-code path exceeds the printable range of the %s." -msgstr "%s filamanı %s içine yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir aralığını aşıyor." +msgstr "%s filamenti %s içine yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir aralığını aşıyor." #, c-format, boost-format msgid "Filaments %s are placed in the %s, but the generated G-code path exceeds the printable range of the %s." -msgstr "%s filamanları %s içine yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir aralığını aşıyor." +msgstr "%s filamentleri %s içine yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir aralığını aşıyor." #, c-format, boost-format msgid "Filament %s is placed in the %s, but the generated G-code path exceeds the printable height of the %s." -msgstr "%s filamanı %s'e yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir yüksekliğini aşıyor." +msgstr "%s filamenti %s'e yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir yüksekliğini aşıyor." #, c-format, boost-format msgid "Filaments %s are placed in the %s, but the generated G-code path exceeds the printable height of the %s." -msgstr "%s filamanları %s'e yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir yüksekliğini aşıyor." +msgstr "%s filamentleri %s'e yerleştirildi, ancak oluşturulan G kodu yolu %s'nin yazdırılabilir yüksekliğini aşıyor." msgid "Open wiki for more information." msgstr "Daha fazla bilgi için wiki'yi açın." @@ -6196,7 +6200,7 @@ msgstr "" "şekilde gösterildiği gibi yazıcıda:" msgid "Invalid input" -msgstr "Geçersiz Giriş." +msgstr "Geçersiz değer" msgid "New Window" msgstr "Yeni Pencere" @@ -6577,7 +6581,7 @@ msgid "Flow Rate Calibration" msgstr "Akış Hızı Kalibrasyonu" msgid "Retraction" -msgstr "Geri Çekme" +msgstr "Geri çekme" msgid "Cornering" msgstr "Köşe dönüşü" @@ -7189,7 +7193,7 @@ msgid "When printing is paused, filament loading and unloading are only supporte msgstr "Yazdırma duraklatıldığında filament yükleme ve boşaltma yalnızca harici yuvalar için desteklenir." msgid "Current extruder is busy changing filament." -msgstr "Mevcut ekstruder filamanı değiştirmekle meşgul." +msgstr "Mevcut ekstruder filamenti değiştirmekle meşgul." # AI Translated msgid "\"Load\" or \"Unload\" is not supported for external spool while using Filament Track Switch." @@ -7332,7 +7336,7 @@ msgid "Upload failed\n" msgstr "Yükleme başarısız\n" msgid "Obtaining instance_id failed\n" -msgstr "instance_id alınamadı\n" +msgstr "Örnek kimliği (instance_id) alınamadı\n" msgid "" "Your comment result cannot be uploaded due to the following reasons:\n" @@ -7501,13 +7505,13 @@ msgid "Undo integration failed." msgstr "Entegrasyon geri alınamadı." msgid "Exporting" -msgstr "Dışa Aktarılıyor." +msgstr "Dışa aktarılıyor" msgid "An update is available!" -msgstr "Yazılımın Yeni sürümü var." +msgstr "Yeni bir güncelleme mevcut!" msgid "Go to download page" -msgstr "İndirme sayfasına gidin." +msgstr "İndirme sayfasına git" msgid "Open Folder." msgstr "Klasörü Aç." @@ -7722,10 +7726,10 @@ msgid "Nozzle Clumping Detection" msgstr "Nozul Topaklanma Algılaması" msgid "Check if the nozzle is clumping by filaments or other foreign objects." -msgstr "Memenin filamanlar veya diğer yabancı nesneler tarafından topaklanıp topaklanmadığını kontrol edin." +msgstr "Nozulun filamentler veya diğer yabancı nesneler tarafından topaklanıp topaklanmadığını kontrol edin." msgid "Detects air printing caused by nozzle clogging or filament grinding." -msgstr "Nozul tıkanması veya filaman taşlamasından kaynaklanan hava baskısını algılar." +msgstr "Nozul tıkanması veya filament taşlamasından kaynaklanan hava baskısını algılar." msgid "First Layer Inspection" msgstr "Birinci Katman Denetimi" @@ -7897,14 +7901,14 @@ msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "Yazdırmada %1% ile %2%'nin karıştırılması önerilmez.\n" msgid " nozzle" -msgstr "meme" +msgstr " nozul" #, boost-format msgid "It is not recommended to print the following filament(s) with %1%: %2%\n" msgstr "Aşağıdaki filament(ler)in %1%: %2% ile yazdırılması önerilmez.\n" msgid "It is not recommended to use the following nozzle and filament combinations:\n" -msgstr "Aşağıdaki nozul ve filaman kombinasyonlarının kullanılması tavsiye edilmez:\n" +msgstr "Aşağıdaki nozul ve filament kombinasyonlarının kullanılması tavsiye edilmez:\n" #, boost-format msgid "%1% with %2%\n" @@ -7978,7 +7982,7 @@ msgstr "" "Senkronizasyona devam edeceğinizden emin misiniz?" msgid "There are unset nozzle types. Please set the nozzle types of all extruders before synchronizing." -msgstr "Ayarlanmamış nozul tipleri vardır. Lütfen senkronizasyondan önce tüm ekstrüderlerin nozül tiplerini ayarlayın." +msgstr "Ayarlanmamış nozul tipleri vardır. Lütfen senkronizasyondan önce tüm ekstrüderlerin nozul tiplerini ayarlayın." msgid "Sync extruder infomation" msgstr "Ekstruder bilgilerini senkronize et" @@ -8041,7 +8045,7 @@ msgstr "" "Sistem ön ayarlarında bir güncelleme olup olmadığını kontrol etmek için lütfen Orca Slicer'ı güncelleyin veya Orca Slicer'ı yeniden başlatın." msgid "Only filament color information has been synchronized from printer." -msgstr "Yazıcıdan yalnızca filaman renk bilgisi senkronize edildi." +msgstr "Yazıcıdan yalnızca filament renk bilgisi senkronize edildi." msgid "Filament type and color information have been synchronized, but slot information is not included." msgstr "Filament türü ve renk bilgisi senkronize edilmiştir ancak slot bilgisi dahil edilmemiştir." @@ -8245,7 +8249,7 @@ msgid "Export AMF file:" msgstr "AMF dosyasını dışa aktar:" msgid "Save file as" -msgstr "Farklı kaydet:" +msgstr "Dosyayı farklı kaydet" msgid "Export OBJ file:" msgstr "OBJ dosyasını dışa aktar:" @@ -8331,21 +8335,21 @@ msgstr "Değiştirme için dizin seçilmedi" msgid "Replaced with 3D files from directory:\n" msgstr "Dizindeki 3D dosyalarla değiştirildi:\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ %1% atlandı: aynı dosya.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ %s atlandı: aynı dosya.\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ %1% atlandı: dosya mevcut değil.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ %s atlandı: dosya mevcut değil.\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ %1% atlandı: değiştirilemedi.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ %s atlandı: değiştirilemedi.\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ %1% değiştirildi.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ %s değiştirildi.\n" msgid "Replaced volumes" msgstr "Değiştirilen birimler" @@ -8416,7 +8420,7 @@ msgid "" "Would you like to sync now?" msgstr "" "Püskürtme ucu türü ve AMS miktarı bilgileri bağlı yazıcıdan senkronize edilmedi.\n" -"Senkronizasyondan sonra yazılım, dilimleme sırasında baskı süresini ve filaman kullanımını optimize edebilir.\n" +"Senkronizasyondan sonra yazılım, dilimleme sırasında baskı süresini ve filament kullanımını optimize edebilir.\n" "Şimdi senkronize etmek ister misiniz?" msgid "Sync now" @@ -8451,7 +8455,7 @@ msgid "Download failed; unknown file format." msgstr "İndirme başarısız oldu, dosya türü bilinmiyor." msgid "Downloading project..." -msgstr "proje indiriliyor..." +msgstr "Proje indiriliyor..." msgid "Download failed; File size exception." msgstr "İndirme başarısız oldu, Dosya boyutu sorunlu." @@ -8479,10 +8483,10 @@ msgid "The selected file" msgstr "Seçili dosya" msgid "Does not contain valid G-code." -msgstr "geçerli gcode içermiyor." +msgstr "Geçerli bir G-kodu içermiyor." msgid "An Error has occurred while loading the G-code file." -msgstr "G kodu dosyası yüklenirken hata oluşuyor" +msgstr "G-code dosyası yüklenirken bir hata oluştu." #. TRN %1% is archive path #, boost-format @@ -8520,7 +8524,7 @@ msgid "G-code files and models cannot be loaded together!" msgstr "G kodu dosyaları modellerle birlikte yüklenemez!" msgid "Unable to add models in preview mode" -msgstr "Önizleme modundayken model eklenemiyor!" +msgstr "Önizleme modundayken model ekleyemezsiniz" msgid "All objects will be removed, continue?" msgstr "Tüm nesneler kaldırılacak, devam edilsin mi?" @@ -8554,7 +8558,7 @@ msgid "The file %s has been sent to the printer's storage space and can be viewe msgstr "%s dosyası yazıcının depolama alanına gönderildi ve yazıcıda görüntülenebiliyor." msgid "The nozzle type is not set. Please set the nozzle and try again." -msgstr "Nozül tipi ayarlanmamış. Lütfen memeyi ayarlayın ve tekrar deneyin." +msgstr "Nozul tipi ayarlanmamış. Lütfen nozulu ayarlayın ve tekrar deneyin." msgid "The nozzle type is not set. Please check." msgstr "Nozül tipi ayarlanmamış. Lütfen kontrol edin." @@ -8809,7 +8813,7 @@ msgid "" msgstr "" "Önemli ölçüde farklı sıcaklıklara sahip filamentlerin kullanılması aşağıdakilere neden olabilir:\n" "• Ekstruder tıkanması\n" -"• Meme hasarı\n" +"• Nozul hasarı\n" "• Katman yapışma sorunları\n" "\n" "Bu özelliği etkinleştirmeye devam etmek istiyor musunuz?" @@ -8859,7 +8863,7 @@ msgid "Associate" msgstr "Ortak" msgid "with OrcaSlicer so that Orca can open models from" -msgstr "Orca’nın modelleri açabilmesi için OrcaSlicer ile" +msgstr "orca'nın modelleri şuradan açabilmesi için OrcaSlicer ile (ilişkilendir / eşleştir)" msgid "Current Association: " msgstr "Mevcut Bağlantı: " @@ -8895,7 +8899,7 @@ msgid "Enable dark Mode" msgstr "Karanlık modu etkinleştir" msgid "Allow only one OrcaSlicer instance" -msgstr "Yalnızca bir OrcaSlicer örneğine izin ver" +msgstr "Yalnızca bir orca slicer örneğine izin ver" msgid "On OSX there is always only one instance of app running by default. However it is allowed to run multiple instances of same app from the command line. In such case this settings will allow only one instance." msgstr "OSX’te her zaman varsayılan olarak çalışan tek bir uygulama örneği vardır. Ancak aynı uygulamanın birden fazla örneğinin komut satırından çalıştırılmasına izin verilir. Böyle bir durumda bu ayarlar yalnızca bir örneğe izin verecektir." @@ -9034,7 +9038,7 @@ msgid "If enabled, saved projects store the absolute path to imported source fil msgstr "Etkinleştirildiğinde kaydedilen projeler, içe aktarılan kaynak dosyaların (STEP/STL/...) mutlak yolunu saklar; böylece kaynak dosya projeden farklı bir klasörde tutulsa bile \"Diskten yeniden yükle\" çalışmayı sürdürür. Devre dışı bırakıldığında yalnızca dosya adı saklanır; bu da projeleri taşınabilir tutar ve mutlak yolların gömülmesini önler." msgid "Preset" -msgstr "Ön ayar" +msgstr "Ön Ayar" msgid "Remember printer configuration" msgstr "Yazıcı yapılandırmasını hatırla" @@ -9061,7 +9065,7 @@ msgid "filaments" msgstr "filamentler" msgid "Optimizes filament area maximum height by chosen filament count." -msgstr "Seçilen filaman sayısına göre filaman alanı maksimum yüksekliğini optimize eder." +msgstr "Seçilen filament sayısına göre filament alanı maksimum yüksekliğini optimize eder." # AI Translated msgid "Show shared profiles notification" @@ -9075,7 +9079,7 @@ msgid "Features" msgstr "Özellikler" msgid "Multi device management" -msgstr "Çoklu Cihaz Yönetimi" +msgstr "Çoklu cihaz yönetimi" msgid "With this option enabled, you can send a task to multiple devices at the same time and manage multiple devices." msgstr "Bu seçenek etkinleştirildiğinde, aynı anda birden fazla cihaza bir görev gönderebilir ve birden fazla cihazı yönetebilirsiniz." @@ -9155,7 +9159,7 @@ msgstr "Kaydır" # AI Translated msgid "Left Mouse Drag" -msgstr "Sol Fare Sürükleme" +msgstr "Sol fare sürükleme" # AI Translated msgid "Set the action that dragging the left mouse button should perform." @@ -9163,7 +9167,7 @@ msgstr "Sol fare düğmesiyle sürüklemenin gerçekleştireceği eylemi ayarlay # AI Translated msgid "Middle Mouse Drag" -msgstr "Orta Fare Sürükleme" +msgstr "Orta fare sürükleme" # AI Translated msgid "Set the action that dragging the middle mouse button should perform." @@ -9171,14 +9175,14 @@ msgstr "Orta fare düğmesiyle sürüklemenin gerçekleştireceği eylemi ayarla # AI Translated msgid "Right Mouse Drag" -msgstr "Sağ Fare Sürükleme" +msgstr "Sağ fare sürükleme" # AI Translated msgid "Set the action that dragging the right mouse button should perform." msgstr "Sağ fare düğmesiyle sürüklemenin gerçekleştireceği eylemi ayarlayın." msgid "Clear my choice on..." -msgstr "Seçimimi temizle..." +msgstr "Seçimimi Temizle" msgid "Unsaved projects" msgstr "Kaydedilmemiş projeler" @@ -9241,7 +9245,7 @@ msgid "Renders cast shadows on the plate, other objects, and each object onto it msgstr "Gerçekçi görünümde plakaya, diğer nesnelere ve her nesnenin kendi üzerine düşen gölgeleri işler." msgid "Anti-aliasing" -msgstr "Anti-aliasing" +msgstr "Anti-Aliasing" # AI Translated msgid "MSAA Multiplier" @@ -9321,6 +9325,21 @@ msgstr "Alt katmanları karart" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "Dilimlenmiş önizlemede katman kaydırıcısı gezdirilirken, geçerli katmanın altındaki katmanları koyulaştırarak yalnızca görüntülenen katmanın tam parlaklıkta gösterilmesini sağlar." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Karartılmış katman parlaklığı" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"\"Alt katmanları karart\" etkinleştirildiğinde karartılmış katmanların ne kadar parlak görüntüleneceği.\n" +"%99 neredeyse hiç karartmaz, %0 ise tamamen siyah gösterir. Üst sınır %99 olarak belirlenmiştir, çünkü %100 seçeneği devre dışı bırakmakla aynı olurdu." + msgid "Login region" msgstr "Giriş bölgesi" @@ -9363,7 +9382,7 @@ msgid "Allow logging into Bambu Cloud alongside Orca Cloud. When enabled, a Bamb msgstr "Orca Cloud'un yanı sıra Bambu Cloud'a giriş yapılmasına izin verir. Etkinleştirildiğinde ana sayfada bir Bambu giriş bölümü görünür." msgid "Update & sync" -msgstr "Güncelle ve senkronize et" +msgstr "Güncelle ve Senkronize Et" msgid "Check for stable updates only" msgstr "Yalnızca kararlı güncellemeleri kontrol edin" @@ -9375,7 +9394,7 @@ msgid "Filament sync mode" msgstr "Filament senkronizasyon modu" msgid "Choose whether sync updates both filament preset and color, or only color." -msgstr "Senkronizasyonun hem filaman ön ayarını hem de rengini mi, yoksa yalnızca rengi mi güncelleyeceğini seçin." +msgstr "Senkronizasyonun hem filament ön ayarını hem de rengini mi, yoksa yalnızca rengi mi güncelleyeceğini seçin." msgid "Filament & Color" msgstr "Filament ve Renk" @@ -9384,7 +9403,7 @@ msgid "Color only" msgstr "Yalnızca renk" msgid "Update built-in presets automatically." -msgstr "Yerleşik Ön Ayarları otomatik olarak güncelleyin." +msgstr "Yerleşik ön ayarları otomatik olarak güncelleyin." msgid "Use encrypted file for token storage" msgstr "Belirteç depolaması için şifrelenmiş dosyayı kullan" @@ -9394,7 +9413,7 @@ msgstr "Kimlik doğrulama belirteçlerini sistem anahtarlığı yerine şifrelen # AI Translated msgid "Bambu network plug-in" -msgstr "Bambu ağ eklentisi" +msgstr "Bambu Ağ Eklentisi" # AI Translated msgid "Enable Bambu network plug-in" @@ -9421,7 +9440,7 @@ msgid "Associate 3MF files to OrcaSlicer" msgstr ".3mf dosyalarını OrcaSlicer ile ilişkilendirin" msgid "If enabled, this sets OrcaSlicer as the default application to open 3MF files." -msgstr "Etkinleştirilirse, OrcaSlicer'ı .3mf dosyalarını açacak varsayılan uygulama olarak ayarlar" +msgstr "Etkinleştirilirse, 3MF dosyalarını açmak için OrcaSlicer'ı varsayılan uygulama olarak ayarlar." msgid "Associate DRC files to OrcaSlicer" msgstr "DRC dosyalarını OrcaSlicer ile ilişkilendirin" @@ -9433,13 +9452,13 @@ msgid "Associate STL files to OrcaSlicer" msgstr ".stl dosyalarını OrcaSlicer ile ilişkilendirin" msgid "If enabled, this sets OrcaSlicer as the default application to open STL files." -msgstr "Etkinleştirilirse OrcaSlicer'ı .stl dosyalarını açmak için varsayılan uygulama olarak ayarlar" +msgstr "Etkinleştirilirse, STL dosyalarını açmak için OrcaSlicer'ı varsayılan uygulama olarak ayarlar." msgid "Associate STEP files to OrcaSlicer" msgstr ".step/.stp dosyalarını OrcaSlicer ile ilişkilendirin" msgid "If enabled, this sets OrcaSlicer as the default application to open STEP files." -msgstr "Etkinleştirilirse, OrcaSlicer'ı .step dosyalarını açmak için varsayılan uygulama olarak ayarlar" +msgstr "Etkinleştirilirse, STEP dosyalarını açmak için OrcaSlicer'ı varsayılan uygulama olarak ayarlar." msgid "Associate web links to OrcaSlicer" msgstr "Web bağlantılarını OrcaSlicer ile ilişkilendirin" @@ -9542,10 +9561,10 @@ msgid "Product host" msgstr "Ürün ana bilgisayarı" msgid "Debug save button" -msgstr "hata ayıklama kaydet düğmesi" +msgstr "Hata ayıklama kaydetme butonu" msgid "Save debug settings" -msgstr "hata ayıklama ayarlarını kaydet" +msgstr "Hata ayıklama ayarlarını kaydet" msgid "Debug settings have been saved successfully!" msgstr "DEBUG ayarları başarıyla kaydedildi!" @@ -9593,7 +9612,7 @@ msgid "Change extruder color" msgstr "Ekstruder rengini değiştir" msgid "Unspecified" -msgstr "belirtilmemiş" +msgstr "Tanımlanmamış" msgid "Project-inside presets" msgstr "Proje içi ön ayarlar" @@ -9780,22 +9799,22 @@ msgstr "Görev iptal edildi" # AI Translated msgid "Bambu Cool Plate" -msgstr "Bambu Soğuk Plaka" +msgstr "Bambu Cool Plate" msgid "PLA Plate" msgstr "PLA Plaka" msgid "Bambu Engineering Plate" -msgstr "Bambu Mühendislik Plakası" +msgstr "Bambu Engineering Plate" msgid "Bambu Smooth PEI Plate" -msgstr "Bambu Pürüzsüz PEI Plaka" - -msgid "High temperature Plate" msgstr "Bambu Smooth PEI Plate" +msgid "High temperature Plate" +msgstr "High temperature Plate" + msgid "Bambu Textured PEI Plate" -msgstr "Bambu Dokulu PEI Plaka" +msgstr "Bambu Textured PEI Plate" msgid "Bambu Cool Plate SuperTack" msgstr "Bambu Cool Plate SuperTack" @@ -9813,7 +9832,7 @@ msgid "Multi-color with external" msgstr "Çok renkli harici" msgid "Your filament grouping method in the sliced file is not optimal." -msgstr "Dilimlenmiş dosyadaki filaman gruplama yönteminiz optimal değil." +msgstr "Dilimlenmiş dosyadaki filament gruplama yönteminiz optimal değil." # AI Translated msgid "To ensure print quality, the drying temperature will be lowered during printing." @@ -9862,7 +9881,7 @@ msgid "Nozzles and filaments of the same type share the same PA profile." msgstr "Aynı tipteki nozullar ve filamentler aynı PA profilini paylaşır." msgid "Send complete" -msgstr "gönderme tamamlandı" +msgstr "Gönderme tamamlandı" msgid "Error code" msgstr "Hata kodu" @@ -9943,10 +9962,10 @@ msgid "Errors" msgstr "Hatalar" msgid "More than one filament types have been mapped to the same external spool, which may cause printing issues. The printer won't pause during printing." -msgstr "Aynı harici makaraya birden fazla filaman türü eşlenmiştir; bu durum, yazdırma sorunlarına neden olabilir. Yazıcı yazdırma sırasında duraklamaz." +msgstr "Aynı harici makaraya birden fazla filament türü eşlenmiştir; bu durum, yazdırma sorunlarına neden olabilir. Yazıcı yazdırma sırasında duraklamaz." msgid "The filament type setting of external spool is different from the filament in the slicing file." -msgstr "Harici makaranın filaman türü ayarı, dilimleme dosyasındaki filamandan farklıdır." +msgstr "Harici makaranın filament türü ayarı, dilimleme dosyasındaki filamentden farklıdır." msgid "The printer type selected when generating G-code is not consistent with the currently selected printer. It is recommended that you use the same printer type for slicing." msgstr "G Kodu oluşturulurken seçilen yazıcı türü mevcut seçili yazıcıyla tutarlı değil. Dilimleme için aynı yazıcı tipini kullanmanız tavsiye edilir." @@ -10020,7 +10039,7 @@ msgid "Cost %dg filament and %d changes more than optimal grouping." msgstr "Maliyet %dg filament ve %d, optimum gruplandırmadan daha fazla değişir." msgid "nozzle" -msgstr "meme" +msgstr "nozul" # AI Translated #, c-format, boost-format @@ -10073,7 +10092,7 @@ msgstr "Geçerli yazıcının %s çapı(%.1fmm) dilimleme dosyasıyla (%.1fmm) e #, c-format, boost-format msgid "The current nozzle diameter (%.1fmm) doesn't match with the slicing file (%.1fmm). Please make sure the nozzle installed matches with settings in printer, then set the corresponding printer preset when slicing." -msgstr "Mevcut nozül çapı (%.1fmm) dilimleme dosyasıyla (%.1fmm) eşleşmiyor. Lütfen takılan püskürtme ucunun yazıcıdaki ayarlarla eşleştiğinden emin olun, ardından dilimleme sırasında ilgili yazıcı ön ayarını yapın." +msgstr "Mevcut nozul çapı (%.1fmm) dilimleme dosyasıyla (%.1fmm) eşleşmiyor. Lütfen takılan püskürtme ucunun yazıcıdaki ayarlarla eşleştiğinden emin olun, ardından dilimleme sırasında ilgili yazıcı ön ayarını yapın." msgid "both extruders" msgstr "her iki ekstruder" @@ -10113,33 +10132,33 @@ msgstr "[ %s ] yüksek sıcaklıktaki bir ortamda yazdırmayı gerektirir." #, c-format, boost-format msgid "The filament on %s may soften. Please unload." -msgstr "%s üzerindeki filaman yumuşayabilir. Lütfen boşaltın." +msgstr "%s üzerindeki filament yumuşayabilir. Lütfen boşaltın." #, c-format, boost-format msgid "The filament on %s is unknown and may soften. Please set filament." -msgstr "%s üzerindeki filaman bilinmiyor ve yumuşayabilir. Lütfen filamenti ayarlayın." +msgstr "%s üzerindeki filament bilinmiyor ve yumuşayabilir. Lütfen filamenti ayarlayın." msgid "Unable to automatically match to suitable filament. Please click to manually match." -msgstr "Uygun filamanla otomatik olarak eşleştirilemiyor. Manuel olarak eşleştirmek için lütfen tıklayın." +msgstr "Uygun filamentle otomatik olarak eşleştirilemiyor. Manuel olarak eşleştirmek için lütfen tıklayın." msgid "Install toolhead enhanced cooling fan to prevent filament softening." msgstr "Filament yumuşamasını önlemek için takım başlığı geliştirilmiş soğutma fanını takın." # AI Translated msgid "Smooth Cool Plate" -msgstr "Pürüzsüz Soğuk Plaka" +msgstr "Smooth Cool Plate" # AI Translated msgid "Engineering Plate" -msgstr "Mühendislik Plakası" +msgstr "Engineering Plate" # AI Translated msgid "Smooth High Temp Plate" -msgstr "Pürüzsüz Yüksek Sıcaklık Plakası" +msgstr "Smooth High Temp Plate" # AI Translated msgid "Textured PEI Plate" -msgstr "Dokulu PEI Plaka" +msgstr "Textured PEI Plate" msgid "Cool Plate (SuperTack)" msgstr "Cool Plate (SuperTack)" @@ -10148,25 +10167,25 @@ msgid "Click here if you can't connect to the printer" msgstr "Yazıcıya bağlanamıyorsanız burayı tıklayın" msgid "No login account, only printers in LAN mode are displayed." -msgstr "Oturum açma hesabı yok, yalnızca LAN modundaki yazıcılar görüntüleniyor" +msgstr "Oturum açılmadı; yalnızca LAN modundaki yazıcılar görüntüleniyor." msgid "Connecting to server..." -msgstr "Sunucuya baglanıyor" +msgstr "Sunucuya bağlanılıyor..." msgid "Synchronizing device information..." -msgstr "Cihaz bilgileri senkronize ediliyor" +msgstr "Cihaz bilgileri senkronize ediliyor..." msgid "Synchronizing device information timed out." -msgstr "Cihaz bilgilerinin senkronize edilmesi zaman aşımı" +msgstr "Cihaz bilgileri senkronizasyonu zaman aşımına uğradı." msgid "Cannot send a print job when the printer is not at FDM mode." msgstr "Yazıcı FDM modunda değilken yazdırma işi gönderilemiyor." msgid "Cannot send a print job while the printer is updating firmware." -msgstr "Yazıcı ürün yazılımını güncellerken yazdırma işi gönderilemiyor" +msgstr "Yazıcı yazılımı güncellenirken yeni bir baskı başlatılamaz." msgid "The printer is executing instructions. Please restart printing after it ends." -msgstr "Yazıcı talimatları yürütüyor. Lütfen bittikten sonra yazdırmayı yeniden başlatın" +msgstr "Yazıcı komutları yürütüyor. Lütfen işlem bittikten sonra baskıyı tekrar başlatın." msgid "AMS is setting up. Please try again later." msgstr "AMS kuruluyor. Lütfen daha sonra tekrar deneyin." @@ -10193,7 +10212,7 @@ msgid "Cannot send the print job to a printer whose firmware must be updated." msgstr "Yazdırma işi, ürün yazılımının güncellenmesi gereken bir yazıcıya gönderilemiyor." msgid "Cannot send a print job for an empty plate." -msgstr "Boş kalıp için yazdırma işi gönderilemiyor" +msgstr "Boş bir tabla için baskı işi gönderilemez." msgid "Storage needs to be inserted to record timelapse." msgstr "Hızlandırılmış çekimi kaydetmek için depolama biriminin eklenmesi gerekir." @@ -10208,7 +10227,7 @@ msgid "Set dynamic flow calibration to 'OFF' to enable custom dynamic flow value msgstr "Özel dinamik akış değerini etkinleştirmek için dinamik akış kalibrasyonunu 'KAPALI' olarak ayarlayın." msgid "This printer does not support printing all plates." -msgstr "Bu yazıcı tüm kalıpların yazdırılmasını desteklemiyor" +msgstr "Bu yazıcı tüm plakaların bastırılmasını desteklemiyor." # AI Translated #, c-format, boost-format @@ -10277,7 +10296,7 @@ msgid "Sending failed, please try again!" msgstr "Gönderme başarısız oldu, lütfen yeniden deneyin!" msgid "Slice complete" -msgstr "Dilimleme tamam." +msgstr "Dilimleme tamamlandı" msgid "View all Daily tips" msgstr "Tüm Günlük ipuçlarını görüntüleyin" @@ -10456,8 +10475,8 @@ msgid "" "No - Do not change these settings for me." msgstr "" "Bu ayarlar otomatik olarak değiştirilsin mi?\n" -"Evet - Bu ayarları otomatik olarak değiştir\n" -"Hayır - Bu ayarları benim için değiştirme" +"Evet - Ayarları otomatik olarak uygula.\n" +"Hayır - Ayarları değiştirme." msgid "" "When using soluble material for the support interface, we recommend the following settings:\n" @@ -10494,10 +10513,10 @@ msgid "Adjust" msgstr "Ayarla" msgid "Experimental feature: Retracting and cutting off the filament at a greater distance during filament changes to minimize flush. Although it can notably reduce flush, it may also elevate the risk of nozzle clogs or other printing complications." -msgstr "Deneysel özellik: Filament değişiklikleri sırasında, floşu en aza indirmek için filamanı daha büyük bir mesafeden geri çekmek ve kesmek. Flush’u önemli ölçüde azaltabilmesine rağmen, aynı zamanda nozül tıkanmaları veya diğer yazdırma komplikasyonları riskini de artırabilir." +msgstr "Deneysel özellik: Filament değişiklikleri sırasında, floşu en aza indirmek için filamenti daha büyük bir mesafeden geri çekmek ve kesmek. Flush’u önemli ölçüde azaltabilmesine rağmen, aynı zamanda nozul tıkanmaları veya diğer yazdırma komplikasyonları riskini de artırabilir." msgid "Experimental feature: Retracting and cutting off the filament at a greater distance during filament changes to minimize flush. Although it can notably reduce flush, it may also elevate the risk of nozzle clogs or other printing complications. Please use with the latest printer firmware." -msgstr "Deneysel özellik: Filament değişiklikleri sırasında, filamanın en aza indirilmesi için filamanın daha büyük bir mesafeden geri çekilmesi ve kesilmesi. Akmayı önemli ölçüde azaltabilmesine rağmen, aynı zamanda püskürtme uçları tıkanması veya diğer yazdırma komplikasyonları riskini de artırabilir. Lütfen en son yazıcı ürün yazılımını kullanın." +msgstr "Deneysel özellik: Filament değişiklikleri sırasında, filamentin en aza indirilmesi için filamentin daha büyük bir mesafeden geri çekilmesi ve kesilmesi. Akmayı önemli ölçüde azaltabilmesine rağmen, aynı zamanda püskürtme uçları tıkanması veya diğer yazdırma komplikasyonları riskini de artırabilir. Lütfen en son yazıcı ürün yazılımını kullanın." msgid "" "When recording timelapse without toolhead, it is recommended to add a \"Timelapse Wipe Tower\" \n" @@ -10581,7 +10600,7 @@ msgstr "Hassasiyet" # AI Translated msgid "Z contouring" -msgstr "Z konturlama" +msgstr "Z Konturlama" msgid "Wall generator" msgstr "Duvar Türü" @@ -10600,7 +10619,7 @@ msgstr "Alt / Üst Katmanlar" # AI Translated msgid "First layer speed" -msgstr "İlk katman hızı" +msgstr "İlk Katman Hızı" msgid "Other layers speed" msgstr "Diğer Katmanlar" @@ -10634,7 +10653,7 @@ msgid "Support ironing" msgstr "Destek Ütüleme" msgid "Tree supports" -msgstr "Ağaç destekler" +msgstr "Ağaç Destekler" msgid "Multimaterial" msgstr "Çoklu Malzeme" @@ -10731,14 +10750,14 @@ msgid "Bed temperature when the Cool Plate SuperTack is installed. A value of 0 msgstr "Cool Plate SuperTack takılıyken yatak sıcaklığı. 0 değeri, filamentin Cool Plate SuperTack üzerine baskıyı desteklemediği anlamına gelir." msgid "Cool Plate" -msgstr "Soğuk plaka" +msgstr "Cool Plate" msgid "This is the bed temperature when the Cool Plate is installed. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "Cool Plate takıldığında yatak sıcaklığı. 0 değeri, filamentin Cool Plate üzerine yazdırmayı desteklemediği anlamına gelir." # AI Translated msgid "Textured Cool Plate" -msgstr "Dokulu Soğuk Plaka" +msgstr "Textured Cool Plate" # AI Translated msgid "This is the bed temperature when the Textured Cool Plate is installed. A value of 0 means the filament does not support printing on the Textured Cool Plate." @@ -10749,7 +10768,7 @@ msgstr "Engineering Plate takıldığında yatak sıcaklığı. Değer 0, filame # AI Translated msgid "Smooth PEI Plate / High Temp Plate" -msgstr "Pürüzsüz PEI Plaka / Yüksek Sıcaklık Plakası" +msgstr "Smooth PEI Plate / High Temp Plate" msgid "This is the bed temperature when the Smooth PEI Plate/High Temperature Plate is installed. A value of 0 means the filament does not support printing on the Smooth PEI Plate/High Temp Plate." msgstr "Smooth PEI Plate / High Temp Plate takılığın da yatak sıcaklığı. 0 Değeri, filamentin Smooth PEI Plate / High Temp Plate üzerine baskı yapmayı desteklemediği anlamına gelir." @@ -10771,13 +10790,13 @@ msgstr "Minimum fan hızı" # AI Translated msgid "The part cooling fan will run at the minimum fan speed when the estimated layer time is longer than the threshold value. When the layer time is shorter than the threshold, the fan speed will be interpolated between the minimum and maximum fan speed according to layer printing time." -msgstr "Tahmini katman süresi eşik değerinden uzun olduğunda parça soğutma fanı minimum fan hızında çalışır. Katman süresi eşikten kısa olduğunda fan hızı, katman yazdırma süresine göre minimum ve maksimum fan hızı arasında enterpole edilir" +msgstr "Tahmini katman süresi eşik değerden uzun olduğunda parça soğutma fanı minimum fan hızında çalışır. Katman süresi eşik değerden kısa olduğunda fan hızı, katman baskı süresine göre minimum ve maksimum hızlar arasında kademeli olarak ayarlanır." msgid "Max fan speed threshold" msgstr "Maksimum fan hızı" msgid "The part cooling fan will run at maximum speed when the estimated layer time is shorter than the threshold value." -msgstr "Tahmini katman süresi ayar değerinden kısa olduğunda parça soğutma fanı hızı maksimum olacaktır" +msgstr "Tahmini katman süresi eşik değerden kısa olduğunda parça soğutma fanı maksimum hızda çalışır." msgid "Auxiliary part cooling fan" msgstr "Yardımcı parça soğutma fanı" @@ -10998,8 +11017,8 @@ msgstr "%1% Ön Ayar" msgid "The following preset will be deleted too:" msgid_plural "The following presets will be deleted too:" -msgstr[0] "Aşağıdaki ön ayar da silinecektir." -msgstr[1] "Aşağıdaki ön ayarlar da silinecektir." +msgstr[0] "Aşağıdaki önayar da silinecektir:" +msgstr[1] "Aşağıdaki önayarlar da silinecektir:" msgid "" "Are you sure to delete the selected preset?\n" @@ -11103,7 +11122,7 @@ msgid "Process Settings" msgstr "İşlem Ayarları" msgid "unsaved changes" -msgstr "Kaydedilmemiş Değişiklikler" +msgstr "kaydedilmemiş değişiklikler" msgid "Transfer or discard changes" msgstr "Değişiklikleri Çıkart veya Sakla" @@ -11168,7 +11187,7 @@ msgid "Click the right mouse button to display the full text." msgstr "Tam metni görüntülemek için farenin sağ tuşuna tıklayın." msgid "No changes will be saved." -msgstr "Tüm değişiklikler kaydedilmeyecek" +msgstr "Hiçbir değişiklik kaydedilmeyecek." msgid "All changes will be discarded." msgstr "Tüm değişiklikler iptal edilecek." @@ -11384,7 +11403,7 @@ msgid "view" msgstr "görüş" msgid "Current filament colors" -msgstr "Mevcut filaman renkleri" +msgstr "Mevcut filament renkleri" msgid "Matching" msgstr "Eşleştirme" @@ -11414,8 +11433,8 @@ msgid "" "The color has been selected, you can choose OK \n" " to continue or manually adjust it." msgstr "" -"Renk seçildi, Tamam'ı seçebilirsiniz \n" -" Devam etmek veya manuel olarak ayarlamak için" +"Renk seçildi; devam etmek için Tamam'ı seçebilir\n" +"veya elle ayarlayabilirsiniz." msgid "—> " msgstr "—> " @@ -11424,7 +11443,7 @@ msgid "" "Synchronizing AMS filaments will discard your modified but unsaved filament presets.\n" "Are you sure you want to continue?" msgstr "" -"AMS filamanlarının senkronize edilmesi, değiştirilmiş ancak kaydedilmemiş filaman ön ayarlarınızı siler.\n" +"AMS filamentlerinin senkronize edilmesi, değiştirilmiş ancak kaydedilmemiş filament ön ayarlarınızı siler.\n" "Devam etmek istediğinizden emin misiniz?" msgctxt "Sync_AMS" @@ -11451,10 +11470,10 @@ msgid "Overwriting" msgstr "Üzerine yazma" msgid "Reset all filament mapping" -msgstr "Tüm filaman eşlemesini sıfırla" +msgstr "Tüm filament eşlemesini sıfırla" msgid "(Recommended filament)" -msgstr "(Önerilen filaman)" +msgstr "(Önerilen filament)" msgid "Advanced Options" msgstr "Gelişmiş Seçenekler" @@ -11480,7 +11499,7 @@ msgid "Tip" msgstr "Uç" msgid "Only synchronize filament type and color, not including AMS slot information." -msgstr "AMS yuvası bilgileri hariç, yalnızca filaman tipini ve rengini senkronize edin." +msgstr "AMS yuvası bilgileri hariç, yalnızca filament tipini ve rengini senkronize edin." msgid "Replace the project filaments list sequentially based on printer filaments. And unused printer filaments will be automatically added to the end of the list." msgstr "Proje filamentleri listesini yazıcı filamentlerine göre sırayla değiştirin. Kullanılmayan yazıcı filamentleri ise otomatik olarak listenin sonuna eklenecektir." @@ -11495,7 +11514,7 @@ msgid "After being synced, this action cannot be undone." msgstr "Senkronize edildikten sonra bu işlem geri alınamaz." msgid "After being synced, the project's filament presets and colors will be replaced with the mapped filament types and colors. This action cannot be undone." -msgstr "Senkronize edildikten sonra projenin filaman ön ayarları ve renkleri, eşlenen filaman türleri ve renkleri ile değiştirilecektir. Bu eylem geri alınamaz." +msgstr "Senkronize edildikten sonra projenin filament ön ayarları ve renkleri, eşlenen filament türleri ve renkleri ile değiştirilecektir. Bu eylem geri alınamaz." msgid "Are you sure to synchronize the filaments?" msgstr "Filamentleri senkronize ettiğinizden emin misiniz?" @@ -11510,7 +11529,7 @@ msgid "Add unused filaments to filaments list." msgstr "Kullanılmayan filamentleri filament listesine ekleyin." msgid "Only synchronize filament type and color, not including slot information." -msgstr "Yuva bilgisi hariç, yalnızca filaman tipini ve rengini senkronize edin." +msgstr "Yuva bilgisi hariç, yalnızca filament tipini ve rengini senkronize edin." msgid "Ext spool" msgstr "Harici makara" @@ -11545,7 +11564,7 @@ msgid "Successfully synchronized filament color from printer." msgstr "Filament rengi yazıcıdan başarıyla senkronize edildi." msgid "Successfully synchronized color and type of filament from printer." -msgstr "Yazıcıdan filamanın rengi ve türü başarıyla senkronize edildi." +msgstr "Yazıcıdan filamentin rengi ve türü başarıyla senkronize edildi." msgctxt "FinishSyncAms" msgid "OK" @@ -11568,7 +11587,7 @@ msgid "For constant flow rate, hold %1% while dragging." msgstr "Sabit akış hızı için sürüklerken %1% basılı tutun." msgid "ms" -msgstr "Bayan" +msgstr "ms" msgid "Total ramming" msgstr "Toplam çarpma" @@ -11580,7 +11599,7 @@ msgid "Ramming line" msgstr "Çarpma hattı" msgid "Orca would re-calculate your flushing volumes everytime the filaments color changed or filaments changed. You could disable the auto-calculate in Orca Slicer > Preferences" -msgstr "Orca, filamentlerin rengi her değiştiğinde veya filamentler değiştiğinde yıkama hacimlerinizi yeniden hesaplar. Otomatik hesaplamayı Orca Dilimleyici > Tercihler'de devre dışı bırakabilirsiniz." +msgstr "Orca, filament rengi veya filament değiştirildiğinde tahliye miktarlarını her defasında yeniden hesaplar. Otomatik hesaplamayı Orca Slicer > Tercihler altından devre dışı bırakabilirsiniz" msgid "Flushing volume (mm³) for each filament pair." msgstr "Her filament çifti için yıkama hacmi (mm³)." @@ -11603,7 +11622,7 @@ msgid "Flushing volumes for filament change" msgstr "Filament değişimi için temizleme hacmi" msgid "Please choose the filament colour" -msgstr "Lütfen filaman rengini seçin" +msgstr "Lütfen filament rengini seçin" # AI Translated msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." @@ -11650,7 +11669,7 @@ msgid "parse json failed" msgstr "json ayrıştırma başarısız oldu" msgid "[Action Required] " -msgstr "[İşlem Gerekli]" +msgstr "[İşlem Gerekli] " msgid "[Action Required]" msgstr "[İşlem Gerekli]" @@ -11758,7 +11777,7 @@ msgid "Movement step set to 1mm" msgstr "Hareket adımı 1 mm'ye ayarlandı" msgid "Keyboard 1-9: set filament for object/part" -msgstr "klavye 1-9: nesne/parça için filamenti ayarlayın" +msgstr "Klavye 1-9: nesneye/parçaya filament ata" msgid "Camera view - Default" msgstr "Kamera görünümü - Varsayılan" @@ -12115,7 +12134,7 @@ msgid "Repair finished" msgstr "Onarım tamamlandı" msgid "Repair failed" -msgstr "Onarım başarısız oldu." +msgstr "Onarım başarısız oldu" msgid "Repair canceled" msgstr "Onarım iptal edildi" @@ -12137,7 +12156,7 @@ msgid "Open G-code file:" msgstr "G kodu dosyasını açın:" msgid "One object has an empty first layer and can't be printed. Please Cut the bottom or enable supports." -msgstr "Bir nesnenin başlangıç katmanı boş ve yazdırılamıyor. Lütfen alt kısmı kesin veya destekleri etkinleştirin." +msgstr "Bir nesnenin ilk katmanı boş ve yazdırılamıyor. Lütfen alt kısmı kesin veya destekleri etkinleştirin." #, boost-format msgid "The object has empty layers between %1% and %2% and can’t be printed." @@ -12148,7 +12167,7 @@ msgid "Object: %1%" msgstr "Nesne: %1%" msgid "Parts of the object at these heights may be too thin or the object may have a faulty mesh." -msgstr "Belki nesnenin bu yükseklikteki bazı kısımları çok incedir veya nesnenin ağı hatalı olabilir" +msgstr "Nesnenin bu yüksekliklerdeki kısımları çok ince olabilir veya nesne bozuk bir ağ yapısına (mesh) sahip olabilir." # AI Translated msgid "Process change extrusion role G-code" @@ -12159,7 +12178,7 @@ msgid "Filament change extrusion role G-code" msgstr "Filament ekstrüzyon rolü değişim G-code'u" msgid "No object can be printed. It may be too small." -msgstr "Hiçbir nesne yazdırılamaz. Belki çok küçük" +msgstr "Hiçbir nesne basılamıyor. Nesne çok küçük olabilir." msgid "Your print is very close to the priming regions. Make sure there is no collision." msgstr "Baskınız hazırlama bölgelerine çok yakın. Çarpışma olmadığından emin olun." @@ -12198,10 +12217,10 @@ msgid "Input shaping is only supported by Klipper, RepRapFirmware and Marlin 2." msgstr "Input shaping yalnızca Klipper, RepRapFirmware ve Marlin 2 tarafından desteklenir." msgid "Grouping error: " -msgstr "Gruplama hatası:" +msgstr "Gruplama hatası: " msgid " can not be placed in the " -msgstr "içine yerleştirilemez" +msgstr " içine yerleştirilemez " # AI Translated msgid "Group error in manual mode. Please check nozzle count or regroup." @@ -12217,7 +12236,7 @@ msgid "too many files" msgstr "çok fazla dosya" msgid "File too large" -msgstr "dosya çok büyük" +msgstr "Dosya çok büyük" msgid "unsupported method" msgstr "desteklenmeyen yöntem" @@ -12287,7 +12306,7 @@ msgid "invalid filename" msgstr "geçersiz dosya adı" msgid "Buffer too small" -msgstr "arabellek çok küçük" +msgstr "Arabellek çok küçük" msgid "internal error" msgstr "dahili hata" @@ -12296,7 +12315,7 @@ msgid "file not found" msgstr "dosya bulunamadı" msgid "Archive too large" -msgstr "arşiv çok büyük" +msgstr "Arşiv çok büyük" msgid "validation failed" msgstr "doğrulama başarısız" @@ -12320,7 +12339,7 @@ msgid " is too close to exclusion area, there may be collisions when printing." msgstr " Hariç tutma alanına çok yakın olduğundan yazdırma sırasında çarpışmalar meydana gelebilir." msgid " is too close to clumping detection area, there may be collisions when printing." -msgstr "topaklanma algılama alanına çok yakın olduğundan yazdırma sırasında çarpışmalar meydana gelebilir." +msgstr " topaklanma algılama alanına çok yakın, baskı sırasında çarpışmalar meydana gelebilir." msgid "Prime Tower" msgstr "Başbakan Kulesi" @@ -12332,7 +12351,7 @@ msgid " is too close to an exclusion area, and collisions will be caused.\n" msgstr " dışlama alanına çok yakın ve çarpışmalara neden olacak.\n" msgid " is too close to clumping detection area, and collisions will be caused.\n" -msgstr "topaklanma tespit alanına çok yakınsa çarpışmalara neden olur.\n" +msgstr " topaklanma algılama alanına çok yakın, çarpışmalar meydana gelecektir.\n" # AI Translated msgid "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." @@ -12386,7 +12405,7 @@ msgid "Variable layer height is not supported with Organic supports." msgstr "Değişken katman yüksekliği Organik desteklerle desteklenmez." msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." -msgstr "Farklı püskürtme ucu çapları ve farklı filaman çapları, ana kule etkinleştirildiğinde iyi çalışmayabilir. Oldukça deneysel olduğundan lütfen dikkatli ilerleyin." +msgstr "Farklı püskürtme ucu çapları ve farklı filament çapları, ana kule etkinleştirildiğinde iyi çalışmayabilir. Oldukça deneysel olduğundan lütfen dikkatli ilerleyin." msgid "The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)." msgstr "Temizleme Kulesi şu anda yalnızca ilgili ekstruder adreslemesiyle desteklenmektedir (use_relative_e_distances=1)." @@ -12775,7 +12794,7 @@ msgid "This is the bed temperature for layers except for the first one. A value msgstr "İlk katman dışındaki katmanlar için yatak sıcaklığı. 0 Değeri, filamentin Dokulu PEI Plaka üzerine yazdırmayı desteklemediği anlamına gelir." msgid "First layer" -msgstr "Başlangıç katmanı" +msgstr "İlk katman" msgid "First layer bed temperature" msgstr "İlk katman yatak sıcaklığı" @@ -12799,7 +12818,7 @@ msgid "This is the bed temperature of the first layer. A value of 0 means the fi msgstr "İlk katmanın yatak sıcaklığı. 0 Değeri, filamentin Dokulu PEI Plaka üzerine yazdırmayı desteklemediği anlamına gelir." msgid "Plate types supported by the printer" -msgstr "Yazıcının desteklediği yatak türleri." +msgstr "Yazıcı tarafından desteklenen plaka tipleri" msgid "Default bed type" msgstr "Varsayılan yatak türü" @@ -13111,7 +13130,7 @@ msgid "" msgstr "" "Bu faktör dış duvarlar için malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek dış duvar akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek dış duvar akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Inner wall flow ratio" msgstr "İç duvar akış oranı" @@ -13123,7 +13142,7 @@ msgid "" msgstr "" "Bu faktör iç duvarlar için malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek iç duvar akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek iç duvar akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Overhang flow ratio" msgstr "Çıkıntı akış oranı" @@ -13135,7 +13154,7 @@ msgid "" msgstr "" "Bu faktör çıkıntılar için malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek sarkma akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek sarkma akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Sparse infill flow ratio" msgstr "Seyrek dolgu akış oranı" @@ -13147,7 +13166,7 @@ msgid "" msgstr "" "Bu faktör seyrek dolgu için malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek seyrek dolgu akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek seyrek dolgu akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Internal solid infill flow ratio" msgstr "Dahili katı dolgu akış oranı" @@ -13159,7 +13178,7 @@ msgid "" msgstr "" "Bu faktör, iç katı dolgu için malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek dahili katı dolgu akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek dahili katı dolgu akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Gap fill flow ratio" msgstr "Boşluk doldurma akış oranı" @@ -13171,7 +13190,7 @@ msgid "" msgstr "" "Bu faktör boşlukları dolduracak malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek boşluk doldurma akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek boşluk doldurma akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Support flow ratio" msgstr "Destek akış oranı" @@ -13183,7 +13202,7 @@ msgid "" msgstr "" "Bu faktör destek için malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek destek akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek destek akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Support interface flow ratio" msgstr "Destek arayüzü akış oranı" @@ -13195,7 +13214,7 @@ msgid "" msgstr "" "Bu faktör, destek arayüzü için malzeme miktarını etkiler.\n" "\n" -"Kullanılan gerçek destek arayüzü akışı, bu değerin filaman akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." +"Kullanılan gerçek destek arayüzü akışı, bu değerin filament akış oranıyla ve ayarlandıysa nesnenin akış oranıyla çarpılmasıyla hesaplanır." msgid "Precise wall" msgstr "Hassas duvar" @@ -13217,7 +13236,7 @@ msgid "" "If a top surface has to be printed and it's partially covered by another layer, it won't be considered at a top layer where its width is below this value. This can be useful to not let the 'one perimeter on top' trigger on surface that should be covered only by perimeters. This value can be a mm or a % of the perimeter extrusion width.\n" "Warning: If enabled, artifacts can be created if you have some thin features on the next layer, like letters. Set this setting to 0 to remove these artifacts." msgstr "" -"Eğer bir üst yüzey basılacaksa ve kısmen başka bir katman tarafından kaplıysa layer genişliği bu değerin altında olan bir üst katman olarak değerlendirilmeyecek. Yalnızca çevrelerle kaplanması gereken yüzeyde 'bir çevre üstte' tetiklemesine izin vermemek yararlı olabilir. Bu değer mm veya a % çevre ekstrüzyon genişliğinin bir yüzdesi olabilir.\n" +"Eğer bir üst yüzey basılacaksa ve kısmen başka bir katman tarafından kaplıysa katman genişliği bu değerin altında olan bir üst katman olarak değerlendirilmeyecek. Yalnızca çevrelerle kaplanması gereken yüzeyde 'bir çevre üstte' tetiklemesine izin vermemek yararlı olabilir. Bu değer mm veya a % çevre ekstrüzyon genişliğinin bir yüzdesi olabilir.\n" "Uyarı: Etkinleştirilirse bir sonraki katmanda harfler gibi bazı ince özelliklerin olması durumunda yapay yapılar oluşturulabilir. Bu yapıları kaldırmak için bu ayarı 0 olarak ayarlayın." msgid "Only one wall on first layer" @@ -13468,12 +13487,37 @@ msgstr "Nesneye göre" msgid "Intra-layer order" msgstr "Katman içi sıra" -msgid "Print order within a single layer." -msgstr "Tek bir katmanda yazdırma sırası." +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Tek bir katman içinde nesne örneklerinin hangi sırayla ziyaret edileceği; bu da aralarında ne kadar seyahat harcanacağını belirler.\n" +"\n" +"Varsayılan: en yakın komşu zincirlemesi, 2-opt ve kesişim giderme ile iyileştirilir. İyi bir genel seçim.\n" +"Nesne listesi olarak: örnekler, herhangi bir yol optimizasyonu olmadan nesne listesindeki sırayla yazdırılır. Öngörülebilir, elle denetlenen bir sıraya ihtiyacınız olduğunda kullanın.\n" +"Hepsinin en iyisi (en kısa yol): her strateji değerlendirilir ve en kısa olanı kullanılır. Nesne örneklerinin sırası tüm baskı için bir kez belirlenir, tek tek adaların sırası ise her katman için ayrı belirlenir; bu nedenle farklı katmanlar farklı stratejiler kullanabilir. Dilimleme biraz daha yavaştır.\n" +"Yılankavi: satır satır ilerleyen yılankavi geçiş, 2-opt ile iyileştirilir. Çok sayıda küçük parçadan oluşan düzenli ızgaralar için çok uygundur.\n" +"\n" +"Aynı katmanda birden fazla filament veya araç varsa, araç değişimlerini en aza indirmek önceliklidir: nesneler önce filamente göre gruplanır ve bu ayar yalnızca her filament grubu içindeki örnekleri sıralar; bu nedenle genel sıra, tabla genelindeki en kısa yol gibi görünmeyebilir." msgid "As object list" msgstr "Nesne listesi olarak" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "Hepsinin en iyisi (en kısa yol)" + +# AI Translated +msgid "Snake" +msgstr "Yılankavi" + msgid "Slow printing down for better layer cooling" msgstr "Daha iyi katman soğutması için baskıyı yavaşlat" @@ -13668,7 +13712,7 @@ msgid "Add end G-code when finishing the printing of this filament." msgstr "Bu filament ile baskı bittiğinde çalışacak G kod." msgid "Ensure vertical shell thickness" -msgstr "Dikey kabuk kalınlığını onayla" +msgstr "Dikey kabuk kalınlığını koru" msgid "" "Add solid infill near sloping surfaces to guarantee the vertical shell thickness (top+bottom solid layers)\n" @@ -14141,10 +14185,10 @@ msgid "Minimum HRC of nozzle required to print the filament. A value of 0 means msgstr "Filamenti yazdırmak için gereken minimum HRC nozul. Sıfır, nozulun HRC'sinin kontrol edilmediği anlamına gelir." msgid "Filament map to extruder" -msgstr "Ekstrudere filaman haritası" +msgstr "Ekstrudere filament haritası" msgid "Filament map to extruder." -msgstr "Ekstrudere filaman haritası." +msgstr "Ekstrudere filament haritası." msgid "Auto For Flush" msgstr "Yıkama İçin Otomatik" @@ -14160,7 +14204,7 @@ msgid "Flush temperature" msgstr "Yıkama sıcaklığı" msgid "Temperature when flushing filament. 0 indicates the upper bound of the recommended nozzle temperature range." -msgstr "Filament yıkanırken sıcaklık. 0, önerilen meme sıcaklık aralığının üst sınırını gösterir." +msgstr "Filament yıkanırken sıcaklık. 0, önerilen nozul sıcaklık aralığının üst sınırını gösterir." # AI Translated msgid "Flush temperature used in fast purge mode." @@ -14282,7 +14326,7 @@ msgid "Speed used for unloading the filament on the wipe tower (does not affect msgstr "Filamenti silme kulesinde boşaltmak için kullanılan hız (sıkıştırmadan hemen sonra boşaltmanın ilk kısmını etkilemez)." msgid "Unloading speed at the start" -msgstr "Başlangıçta boşaltma hızı" +msgstr "Başlangıçtaki boşaltma hızı" msgid "Speed used for unloading the tip of the filament immediately after ramming." msgstr "Sıkıştırmadan hemen sonra filamentin ucunu boşaltmak için kullanılan hız." @@ -14309,7 +14353,7 @@ msgid "Stamping distance measured from the center of the cooling tube" msgstr "Soğutma tüpünün merkezinden ölçülen damgalama mesafesi" msgid "If set to non-zero value, filament is moved toward the nozzle between the individual cooling moves (\"stamping\"). This option configures how long this movement should be before the filament is retracted again." -msgstr "Sıfırdan farklı bir değere ayarlanırsa filaman bireysel soğutma hareketleri arasında (“damgalama”) nüzule doğru hareket ettirilir. Bu seçenek, filamanın tekrar geri çekilmesinden önce bu hareketin ne kadar sürmesi gerektiğini yapılandırır." +msgstr "Sıfırdan farklı bir değere ayarlanırsa filament bireysel soğutma hareketleri arasında (“damgalama”) nüzule doğru hareket ettirilir. Bu seçenek, filamentin tekrar geri çekilmesinden önce bu hareketin ne kadar sürmesi gerektiğini yapılandırır." msgid "Speed of the first cooling move" msgstr "İlk soğutma hareketi hızı" @@ -14404,7 +14448,7 @@ msgid "g/cm³" msgstr "g/cm³" msgid "Filament material type" -msgstr "Filament malzeme türü." +msgstr "Filament malzeme türü" msgid "Soluble material" msgstr "Çözünür malzeme" @@ -14416,7 +14460,7 @@ msgid "Filament ramming length" msgstr "Filament sıkıştırma uzunluğu" msgid "When changing the extruder, it is recommended to extrude a certain length of filament from the original extruder. This helps minimize nozzle oozing." -msgstr "Ekstrüderi değiştirirken, orijinal ekstrüderden belirli bir uzunlukta filamanın çıkarılması tavsiye edilir. Bu, meme sızıntısını en aza indirmeye yardımcı olur." +msgstr "Ekstrüderi değiştirirken, orijinal ekstrüderden belirli bir uzunlukta filamentin çıkarılması tavsiye edilir. Bu, nozul sızıntısını en aza indirmeye yardımcı olur." msgid "Support material" msgstr "Destek malzemesi" @@ -14542,7 +14586,7 @@ msgid "Sparse infill pattern" msgstr "Dolgu deseni" msgid "This is the line pattern for internal sparse infill." -msgstr "İç dolgu deseni." +msgstr "Bu, iç seyrek dolgu için çizgi desenidir." msgid "Zig Zag" msgstr "Zig zag" @@ -14619,7 +14663,7 @@ msgid "Acceleration of internal solid infill. If the value is expressed as a per msgstr "İç katı dolgunun hızlandırılması. Değer yüzde olarak ifade edilirse (örn. %100), varsayılan ivmeye göre hesaplanacaktır." msgid "This is the printing acceleration for the first layer. Using limited acceleration can improve build plate adhesion." -msgstr "Başlangıç katmanının hızlandırılması. Daha düşük bir değerin kullanılması baskı plakası yapışkanlığını iyileştirebilir." +msgstr "İlk katman için baskı ivmelenmesidir. Sınırlı bir ivmelenme kullanmak, baskı tablasına yapışmayı artırabilir." msgid "Enable accel_to_decel" msgstr "Accel_to_decel'i etkinleştir" @@ -14670,7 +14714,7 @@ msgid "Line width of the first layer. If expressed as a %, it will be computed o msgstr "İlk katmanın çizgi genişliği. % olarak ifade edilirse Nozul çapı üzerinden hesaplanacaktır." msgid "First layer height" -msgstr "Başlangıç katman yüksekliği" +msgstr "İlk katman yüksekliği" msgid "Height of the first layer. Making the first layer height thicker can improve build plate adhesion." msgstr "İlk katmanın yüksekliği. İlk katman yüksekliğini biraz kalın yapmak, baskı plakasının yapışmasını iyileştirebilir." @@ -14679,7 +14723,7 @@ msgid "This is the speed for the first layer except for solid infill sections." msgstr "Katı dolgu kısmı dışındaki ilk katmanın hızı." msgid "First layer infill" -msgstr "Başlangıç katman dolgusu" +msgstr "İlk katman dolgusu" msgid "This is the speed for solid infill parts of the first layer." msgstr "İlk katmanın katı dolgu kısmının hızı." @@ -14701,7 +14745,7 @@ msgid "First layer nozzle temperature" msgstr "İlk katman nozul sıcaklığı" msgid "Nozzle temperature for printing the first layer with this filament" -msgstr "Bu filamenti kullanırken ilk katmanı yazdırmak için nozul sıcaklığı." +msgstr "Bu filament ile ilk katmanı basmak için nozul sıcaklığı" msgid "Full fan speed at layer" msgstr "Maksimum fan hızı" @@ -14769,25 +14813,25 @@ msgid "Ironing flow" msgstr "Ütüleme akışı" msgid "Filament-specific override for ironing flow. This allows you to customize the ironing flow for each filament type. Too high value results in overextrusion on the surface." -msgstr "Ütüleme akışı için filamana özgü geçersiz kılma. Bu, her filaman türü için ütüleme akışını özelleştirmenize olanak tanır. Çok yüksek değer yüzeyde aşırı ekstrüzyona neden olur." +msgstr "Ütüleme akışı için filamente özgü geçersiz kılma. Bu, her filament türü için ütüleme akışını özelleştirmenize olanak tanır. Çok yüksek değer yüzeyde aşırı ekstrüzyona neden olur." msgid "Ironing line spacing" msgstr "Ütüleme çizgi aralığı" msgid "Filament-specific override for ironing line spacing. This allows you to customize the spacing between ironing lines for each filament type." -msgstr "Ütüleme hattı aralığı için filamente özel geçersiz kılma. Bu, her filaman türü için ütüleme çizgileri arasındaki boşluğu özelleştirmenize olanak tanır." +msgstr "Ütüleme hattı aralığı için filamente özel geçersiz kılma. Bu, her filament türü için ütüleme çizgileri arasındaki boşluğu özelleştirmenize olanak tanır." msgid "Ironing inset" msgstr "Ütüleme boşluğu" msgid "Filament-specific override for ironing inset. This allows you to customize the distance to keep from the edges when ironing for each filament type." -msgstr "İç parçayı ütülemek için filamente özel geçersiz kılma. Bu, her filaman türü için ütüleme sırasında kenarlardan korunacak mesafeyi özelleştirmenize olanak tanır." +msgstr "İç parçayı ütülemek için filamente özel geçersiz kılma. Bu, her filament türü için ütüleme sırasında kenarlardan korunacak mesafeyi özelleştirmenize olanak tanır." msgid "Ironing speed" msgstr "Ütüleme hızı" msgid "Filament-specific override for ironing speed. This allows you to customize the print speed of ironing lines for each filament type." -msgstr "Ütüleme hızı için filamana özgü geçersiz kılma. Bu, her filaman türü için ütüleme hatlarının baskı hızını özelleştirmenize olanak tanır." +msgstr "Ütüleme hızı için filamente özgü geçersiz kılma. Bu, her filament türü için ütüleme hatlarının baskı hızını özelleştirmenize olanak tanır." msgid "This setting makes the toolhead randomly jitter while printing walls so that the surface has a rough textured look. This setting controls the fuzzy position." msgstr "Duvara baskı yaparken rastgele titreme, böylece yüzeyin pürüzlü bir görünüme sahip olması. Bu ayar pütürlü konumu kontrol eder." @@ -14840,8 +14884,8 @@ msgid "" "Attention! The [Extrusion] and [Combined] modes works only the fuzzy_skin_thickness parameter not more than the thickness of printed loop. At the same time, the width of the extrusion for a particular layer should also not be below a certain level. It is usually equal 15-25%% of a layer height. Therefore, the maximum fuzzy skin thickness with a perimeter width of 0.4 mm and a layer height of 0.2 mm will be 0.4-(0.2*0.25)=±0.35mm! If you enter a higher parameter than this, the error Flow::spacing() will displayed, and the model will not be sliced. You can choose this number until this error is repeated." msgstr "" "Pütürlü yüzey oluşturma modu. Sadece Arachne ile çalışır!\n" -"Yer Değiştirme: Desen, nozülün orijinal yoldan yana kaydırılmasıyla oluşturulduğu klasik mod.\n" -"Ekstrüzyon: Desenin ekstrüde edilen plastik miktarına göre oluşturulduğu mod. Bu, nozül sarsıntısı olmadan pürüzsüz bir desen veren hızlı ve düz bir algoritmadır. Ancak, tüm dizilimde gevşek duvarlar oluşturmak için daha kullanışlıdır.\n" +"Yer Değiştirme: Desen, nozulun orijinal yoldan yana kaydırılmasıyla oluşturulduğu klasik mod.\n" +"Ekstrüzyon: Desenin ekstrüde edilen plastik miktarına göre oluşturulduğu mod. Bu, nozul sarsıntısı olmadan pürüzsüz bir desen veren hızlı ve düz bir algoritmadır. Ancak, tüm dizilimde gevşek duvarlar oluşturmak için daha kullanışlıdır.\n" "Birleşik: Eklem modu [Yer Değiştirme] + [Ekstrüzyon]. Duvarların görünümü [Yer Değiştirme] Moduna benzer, ancak çevreler arasında gözenek bırakmaz.\n" "\n" "Dikkat! [Ekstrüzyon] ve [Birleşik] modları yalnızca fuzzy_skin_thickness parametresini çalıştırır, yazdırılan ilmeğin kalınlığından daha fazla olmamalıdır. Aynı zamanda, belirli bir katman için ekstrüzyon genişliği de belirli bir seviyenin altında olmamalıdır. Genellikle katman yüksekliğinin %%15-25'ine eşittir. Bu nedenle, 0,4 mm çevre genişliği ve 0,2 mm katman yüksekliğine sahip maksimum pütürlü yüzey kalınlığı 0,4-(0,2*0,25)=±0,35 mm olacaktır! Bundan daha yüksek bir parametre girerseniz, Flow::spacing() hatası görüntülenir ve model dilimlenmez. Bu hata tekrarlanana kadar bu sayıyı seçebilirsiniz." @@ -15207,7 +15251,7 @@ msgid "Sparse infill rotation template" msgstr "Seyrek dolgu döndürme şablonu" msgid "Rotate the sparse infill direction per layer using a template of angles. Enter comma-separated degrees (e.g., '0,30,60,90'). Angles are applied in order by layer and repeat when the list ends. Advanced syntax is supported: '+5' rotates +5° every layer; '+5#5' rotates +5° every 5 layers. See the Wiki for details. When a template is set, the standard infill direction setting is ignored. Note: some infill patterns (e.g., Gyroid) control rotation themselves; use with care." -msgstr "Seyrek dolgu yönünü katman katman açı şablonuna göre döndürün. Virgülle ayrılmış açıları girin (örn. '0,30,60,90'). Açılar katman sırasına göre uygulanır ve liste sona erdiğinde tekrarlanır. Gelişmiş sözdizimi desteklenir: '+5' her katmanda +5° döndürür; '+5#5' her 5 katmanda +5° döndürür. Detaylar için Viki’ye bakın. Bir şablon ayarlandığında, standart dolgu yönü ayarı yok sayılır. NOT: bazı dolgu desenleri (örn. Gyroid) kendi döndürmesini kontrol eder; dikkatli kullanın" +msgstr "Açı şablonu kullanarak seyrek dolgu yönünü katman bazında döndürün. Virgülle ayrılmış açılar girin (ör. '0,30,60,90'). Açılar katman sırasına göre uygulanır ve liste bittiğinde tekrarlanır. Gelişmiş sözdizimi desteklenir: '+5' her katmanda +5° döndürür; '+5#5' her 5 katmanda bir +5° döndürür. Detaylar için Wiki'ye bakın. Bir şablon ayarlandığında, standart dolgu yönü ayarı göz ardı edilir. Not: Bazı dolgu desenleri (ör. Gyroid) dönmeyi kendisi kontrol eder; dikkatli kullanın." msgid "Solid infill rotation template" msgstr "Katı dolgu döndürme şablonu" @@ -15219,7 +15263,7 @@ msgid "Skeleton infill density" msgstr "İskelet dolgu yoğunluğu" msgid "The remaining part of the model contour after removing a certain depth from the surface is called the skeleton. This parameter is used to adjust the density of this section. When two regions have the same sparse infill settings but different skeleton densities, their skeleton areas will develop overlapping sections. Default is as same as infill density." -msgstr "üzeyden belirli bir derinlik çıkarıldıktan sonra model konturunda kalan kısma 'iskelet' denir. Bu parametre, bu bölümün yoğunluğunu ayarlamak için kullanılır. İki bölge aynı seyrek dolgu ayarlarına sahip fakat farklı iskelet yoğunluklarına sahipse, iskelet alanları üst üste binen bölümler oluşturabilir. Varsayılan değer, dolgu yoğunluğu ile aynıdır." +msgstr "Yüzeyden belirli bir derinlik çıkarıldıktan sonra model hatlarının geriye kalan kısmına iskelet adı verilir. Bu parametre, söz konusu alanın yoğunluğunu ayarlamak için kullanılır. İki bölge aynı seyrek dolgu ayarlarına ancak farklı iskelet yoğunluklarına sahip olduğunda, iskelet alanlarında çakışan kesitler oluşur. Varsayılan değer dolgu yoğunluğu ile aynıdır." msgid "Skin infill density" msgstr "Yüzey dolgu yoğunluğu" @@ -15450,7 +15494,7 @@ msgid "The distance from the boundary between filaments to generate interlocking msgstr "Hücrelerde ölçülen, birbirine kenetlenen yapıyı oluşturmak için filamentler arasındaki sınırdan mesafe. Çok az hücre yapışmanın zayıf olmasına neden olur." msgid "Interlocking boundary avoidance" -msgstr "Birbirine kenetlenen sınırdan kaçınma" +msgstr "Kenetleme sınır mesafesi koruması" msgid "The distance from the outside of a model where interlocking structures will not be generated, measured in cells." msgstr "Birbirine kenetlenen yapıların oluşturulmayacağı bir modelin dışına olan mesafe, hücrelerde ölçülür." @@ -15486,7 +15530,7 @@ msgid "This is the distance between the lines used for ironing." msgstr "Ütü çizgileri arasındaki mesafe." msgid "The distance to keep from the edges. A value of 0 sets this to half of the nozzle diameter." -msgstr "Kenarlardan korunacak mesafe. 0 değeri bunu nozül çapının yarısına ayarlar." +msgstr "Kenarlardan korunacak mesafe. 0 değeri bunu nozul çapının yarısına ayarlar." msgid "This is the print speed for ironing lines." msgstr "Ütüleme çizgilerinin baskı hızı." @@ -15564,7 +15608,7 @@ msgid "Silent Mode" msgstr "Sessiz mod" msgid "Whether the machine supports silent mode in which machine uses lower acceleration to print more quietly" -msgstr "Makinenin yazdırmak için daha düşük hızlanma kullandığı sessiz modu destekleyip desteklemediği." +msgstr "Daha sessiz baskı için ivmelenmeyi düşüren sessiz mod desteği" msgid "Emit limits to G-code" msgstr "G-kod sınırları" @@ -15837,7 +15881,7 @@ msgstr "" "RRF: X ve Y değerleri eşittir." msgid "Hz" -msgstr "Hz." +msgstr "Hz" msgid "Y" msgstr "Y" @@ -15994,7 +16038,7 @@ msgid "Nozzle volume" msgstr "Nozul hacmi" msgid "Volume of nozzle between the filament cutter and the end of the nozzle" -msgstr "Kesici ile nozulun ucu arasındaki nozul hacmi." +msgstr "Filament kesici ile nozul ucu arasındaki nozul hacmi" msgid "Cooling tube position" msgstr "Soğutma borusu konumu" @@ -16173,7 +16217,7 @@ msgid "This expands all raft layers in XY plane." msgstr "XY düzlemindeki tüm rafa katmanlarını genişlet." msgid "First layer density" -msgstr "Başlangıç katman yoğunluğu" +msgstr "İlk katman yoğunluğu" msgid "This is the density of the first raft or support layer." msgstr "İlk sal veya destek katmanının yoğunluğu." @@ -16360,7 +16404,7 @@ msgid "Deretraction speed" msgstr "İleri itme hızı" msgid "Speed for reloading filament into the nozzle. Zero means same speed of retraction." -msgstr "Filamentin nozüle yeniden yüklenme hızı. Sıfır, geri çekilme hızının aynı olduğu anlamına gelir." +msgstr "Filamentin nozule yeniden yüklenme hızı. Sıfır, geri çekilme hızının aynı olduğu anlamına gelir." # AI Translated msgid "Deretraction speed (extruder change)" @@ -16423,16 +16467,16 @@ msgstr "" "Bu miktar milimetre cinsinden veya mevcut ekstruder çapının yüzdesi olarak belirtilebilir. Bu parametrenin varsayılan değeri %10'dur." msgid "Scarf joint seam (beta)" -msgstr "Eğik birleşim dikişi (beta)" +msgstr "Atkı dikişi birleşimi (beta)" msgid "Use scarf joint to minimize seam visibility and increase seam strength." -msgstr "Dikiş görünürlüğünü en aza indirmek ve dikiş mukavemetini arttırmak için eğik birleşimini kullanın." +msgstr "Dikiş izini en aza indirmek ve dikiş mukavemetini artırmak için atkı dikişi kullanın." msgid "Conditional scarf joint" -msgstr "Koşullu eğik birleşimi" +msgstr "Koşullu atkı dikişi" msgid "Apply scarf joints only to smooth perimeters where traditional seams do not conceal the seams at sharp corners effectively." -msgstr "Eğik bağlantılarını yalnızca geleneksel dikişlerin keskin köşelerdeki dikişleri etkili bir şekilde gizleyemediği düzgün kenarlara uygulayın." +msgstr "Atkı dikişini yalnızca, geleneksel dikişlerin keskin köşelerde gizlenemediği düz çevre hatlarına uygular." msgid "Conditional angle threshold" msgstr "Koşullu açı eşiği" @@ -16441,61 +16485,61 @@ msgid "" "This option sets the threshold angle for applying a conditional scarf joint seam.\n" "If the maximum angle within the perimeter loop exceeds this value (indicating the absence of sharp corners), a scarf joint seam will be used. The default value is 155°." msgstr "" -"Bu seçenek, koşullu bir eğik eklem dikişi uygulamak için eşik açısını ayarlar.\n" -"Çevre halkası içindeki maksimum açı bu değeri aşarsa (keskin köşelerin bulunmadığını gösterir), bir eğik birleştirme dikişi kullanılacaktır. Varsayılan değer 155°'dir." +"Bu seçenek, koşullu atkı dikişinin uygulanacağı eşik açısını belirler.\n" +"Çevre döngüsü içindeki maksimum açı bu değeri aşarsa (keskin köşelerin olmadığını gösterir), atkı dikişi kullanılır. Varsayılan değer 155°'dir." msgid "Conditional overhang threshold" msgstr "Koşullu çıkıntı eşiği" #, no-c-format, no-boost-format msgid "This option determines the overhang threshold for the application of scarf joint seams. If the unsupported portion of the perimeter is less than this threshold, scarf joint seams will be applied. The default threshold is set at 40% of the external wall's width. Due to performance considerations, the degree of overhang is estimated." -msgstr "Bu seçenek, eğik bağlantı dikişlerinin uygulanması için sarkma eşiğini belirler. Çevrenin desteklenmeyen kısmı bu eşikten az ise eğik birleştirme dikişleri uygulanacaktır. Varsayılan eşik, dış duvar genişliğinin %40'ına ayarlanmıştır. Performans değerlendirmeleri nedeniyle çıkıntının derecesi tahmin edilir." +msgstr "Bu seçenek, atkı dikişlerinin uygulanacağı çıkıntı eşiğini belirler. Çevrenin desteklenmeyen kısmı bu eşikten azsa, atkı dikişi uygulanır. Varsayılan eşik değeri, dış duvar genişliğinin %40'ı olarak ayarlanmıştır. Performans değerlendirmeleri nedeniyle çıkıntı derecesi tahmini olarak hesaplanır." msgid "Scarf joint speed" -msgstr "Eğik birleşim hızı" +msgstr "Atkı dikişi hızı" msgid "This option sets the printing speed for scarf joints. It is recommended to print scarf joints at a slow speed (less than 100 mm/s). It's also advisable to enable 'Extrusion rate smoothing' if the set speed varies significantly from the speed of the outer or inner walls. If the speed specified here is higher than the speed of the outer or inner walls, the printer will default to the slower of the two speeds. When specified as a percentage (e.g., 80%), the speed is calculated based on the respective outer or inner wall speed. The default value is set to 100%." -msgstr "Bu seçenek, eğik bağlantılarının yazdırma hızını ayarlar. Eğik bağlantılarının yavaş bir hızda (100 mm/s'den az) yazdırılması tavsiye edilir. Ayarlanan hızın dış veya iç duvarların hızından önemli ölçüde farklı olması durumunda 'Ekstrüzyon hızı yumuşatma' seçeneğinin etkinleştirilmesi de tavsiye edilir. Burada belirtilen hız, dış veya iç duvarların hızından daha yüksekse, yazıcı varsayılan olarak iki hızdan daha yavaş olanı seçecektir. Yüzde olarak belirtildiğinde (örn. %80), hız, ilgili dış veya iç duvar hızına göre hesaplanır. Varsayılan değer %100 olarak ayarlanmıştır." +msgstr "Bu seçenek, atkı birleşimlerinin baskı hızını belirler. Atkı birleşimlerinin düşük hızlarda (100 mm/s altında) basılması önerilir. Belirlenen hız, dış veya iç duvar hızından belirgin şekilde farklıysa 'Akış hızı yumuşatma' özelliğinin etkinleştirilmesi tavsiye edilir. Buradaki hız dış veya iç duvar hızından daha yüksekse, yazıcı varsayılan olarak bu iki hızdan yavaş olanı kullanır. Yüzde olarak belirtildiğinde (ör. %80), hız ilgili dış veya iç duvar hızına göre hesaplanır. Varsayılan değer %100 olarak ayarlanmıştır." msgid "Scarf joint flow ratio" -msgstr "Eğik birleşimi akış oranı" +msgstr "Atkı dikişi akış oranı" msgid "This factor affects the amount of material for scarf joints." -msgstr "Bu faktör eğik birleşimlerinde kullanılacak materyal miktarını değiştirir." +msgstr "Bu faktör, atkı dikişleri için kullanılacak malzeme miktarını etkiler." msgid "Scarf start height" -msgstr "Eğik başlangıç yüksekliği" +msgstr "Atkı başlangıç yüksekliği" msgid "" "Start height of the scarf.\n" "This amount can be specified in millimeters or as a percentage of the current layer height. The default value for this parameter is 0." msgstr "" -"Eğik başlangıç yüksekliği.\n" -"Bu miktar milimetre cinsinden veya geçerli katman yüksekliğinin yüzdesi olarak belirtilebilir. Bu parametrenin varsayılan değeri 0'dır." +"Atkı başlangıç yüksekliği.\n" +"Bu değer milimetre cinsinden veya mevcut katman yüksekliğinin yüzdesi olarak belirtilebilir. Varsayılan değer 0'dır." msgid "Scarf around entire wall" -msgstr "Tüm duvarın etrafına atkıla" +msgstr "Tüm duvara atkı uygula" msgid "The scarf extends to the entire length of the wall." -msgstr "Eğik duvarın tüm uzunluğu boyunca uzanır." +msgstr "Atkı birleşimi, duvarın tüm uzunluğu boyunca uzanacak şekilde genişletilir." msgid "Scarf length" -msgstr "Eğik uzunluğu" +msgstr "Atkı dikişi uzunluğu" msgid "Length of the scarf. Setting this parameter to zero effectively disables the scarf." -msgstr "Atkının uzunluğu. Bu parametrenin 0 a ayarlanması atkıyı dolaylı yoldan devre dışı bırakır." +msgstr "Atkı birleşiminin uzunluğudur. Bu parametrenin 0 (sıfır) olarak ayarlanması atkı dikişini devre dışı bırakır." msgid "Scarf steps" -msgstr "Eğik kademesi" +msgstr "Atkı adımları" msgid "Minimum number of segments of each scarf." -msgstr "Her atkının minimum segment sayısı." +msgstr "Her bir atkının minimum segment sayısı." msgid "Scarf joint for inner walls" -msgstr "İç duvarlar için eğik birleşimi" +msgstr "İç duvarlar için atkı dikişi" msgid "Use scarf joint for inner walls as well." -msgstr "İç duvarlar için de eğik birleşimini kullanın." +msgstr "İç duvarlarda da atkı dikişi kullan." msgid "Role base wipe speed" msgstr "Otomatik temizleme hızı" @@ -16543,7 +16587,7 @@ msgid "Skirt height" msgstr "Etek yüksekliği" msgid "Number of skirt layers: usually only one" -msgstr "Etek katman sayısı. Genellikle tek katman." +msgstr "Etek katman sayısı: Genelde tek katman" msgid "Single loop after first layer" msgstr "İlk katmandan sonra tek duvar" @@ -16598,7 +16642,7 @@ msgid "" "Using a non-zero value is useful if the printer is set up to print without a prime line.\n" "Final number of loops is not taking into account while arranging or validating objects distance. Increase loop number in such case." msgstr "" -"Etek yazdırılırken mm cinsinden minimum filaman ekstrüzyon uzunluğu. Sıfır, bu özelliğin devre dışı olduğu anlamına gelir.\n" +"Etek yazdırılırken mm cinsinden minimum filament ekstrüzyon uzunluğu. Sıfır, bu özelliğin devre dışı olduğu anlamına gelir.\n" "\n" "Yazıcı ana hat olmadan yazdırmak üzere ayarlanmışsa sıfır dışında bir değer kullanmak yararlı olur.\n" "Nihai döngü sayısı, nesnelerin mesafesini düzenlerken veya doğrularken dikkate alınmaz. Böyle bir durumda döngü sayısını artırın." @@ -16656,7 +16700,7 @@ msgstr "Maksimum XY yumuşatma" #, no-c-format, no-boost-format msgid "Maximum distance to move points in XY to try to achieve a smooth spiral. If expressed as a %, it will be computed over nozzle diameter." -msgstr "Düzgün bir spiral elde etmek için XY'deki noktaları hareket ettirmek için maksimum mesafe % olarak ifade edilirse nozül çapı üzerinden hesaplanacaktır." +msgstr "Düzgün bir spiral elde etmek için XY'deki noktaları hareket ettirmek için maksimum mesafe % olarak ifade edilirse nozul çapı üzerinden hesaplanacaktır." msgid "Spiral starting flow ratio" msgstr "Spiral başlangıç akış oranı" @@ -16712,7 +16756,7 @@ msgid "Insert multiple preheat commands (e.g. M104.1). Only useful for Prusa XL. msgstr "Birden fazla ön ısıtma komutu ekleyin (örn. M104.1). Yalnızca Prusa XL için kullanışlıdır. Diğer yazıcılar için lütfen 1’e ayarlayın." msgid "G-code written at the very top of the output file, before any other content. Useful for adding metadata that printer firmware reads from the first lines of the file (e.g. estimated print time, filament usage). Supports placeholders like {print_time_sec} and {used_filament_length}." -msgstr "G kodu, çıktı dosyasının en üstünde, diğer içeriklerden önce yazılır. Yazıcı ürün yazılımının dosyanın ilk satırlarından okuduğu meta verileri (ör. tahmini yazdırma süresi, filaman kullanımı) eklemek için kullanışlıdır. {print_time_sec} ve {used_filament_length} gibi yer tutucuları destekler." +msgstr "G kodu, çıktı dosyasının en üstünde, diğer içeriklerden önce yazılır. Yazıcı ürün yazılımının dosyanın ilk satırlarından okuduğu meta verileri (ör. tahmini yazdırma süresi, filament kullanımı) eklemek için kullanışlıdır. {print_time_sec} ve {used_filament_length} gibi yer tutucuları destekler." msgid "Start G-code" msgstr "Başlangıç G Kodu" @@ -16721,7 +16765,7 @@ msgid "G-code added when starting a print." msgstr "Baskı başladığında çalışacak G Kodu." msgid "G-code added when the printer starts using this filament" -msgstr "Bu filament ile baskı başladığında çalıştırılacak G-Kod." +msgstr "Bu filament kullanılırken yazıcı başladığında eklenen G-kodu" msgid "Single Extruder Multi Material" msgstr "Tek ekstruder çoklu malzeme" @@ -17066,7 +17110,7 @@ msgid "This setting determines the maximum overhang angle that the branches of t msgstr "Bu ayar, ağaç desteğinin dallarının oluşmasına izin verilen maksimum çıkıntı açısını belirler. Açı artırılırsa, dallar daha yatay olarak basılabilir ve daha uzağa ulaşır." msgid "Preferred Branch Angle" -msgstr "Tercih Edilen Dal Açısı" +msgstr "Tercih edilen dal açısı" #. TRN PrintSettings: "Organic supports" > "Preferred Branch Angle" msgid "The preferred angle of the branches, when they do not have to avoid the model. Use a lower angle to make them more vertical and more stable. Use a higher angle for branches to merge faster." @@ -17079,7 +17123,7 @@ msgid "This setting determines the distance between neighboring tree support nod msgstr "Bu ayar, komşu ağaç destek düğümleri arasındaki mesafeyi belirler." msgid "Branch Density" -msgstr "Dal Yoğunluğu" +msgstr "Dal yoğunluğu" #. TRN PrintSettings: "Organic supports" > "Branch Density" msgid "Adjusts the density of the support structure used to generate the tips of the branches. A higher value results in better overhangs but the supports are harder to remove, thus it is recommended to enable top support interfaces instead of a high branch density value if dense interfaces are needed." @@ -17098,7 +17142,7 @@ msgid "Distance from tree branch to the outermost brim line." msgstr "Ağaç dalından en dış kenar çizgisine kadar olan mesafe." msgid "Tip Diameter" -msgstr "Uç Çapı" +msgstr "Uç çapı" #. TRN PrintSettings: "Organic supports" > "Tip Diameter" msgid "Branch tip diameter for organic supports." @@ -17112,7 +17156,7 @@ msgstr "Bu ayar, destek düğümlerinin başlangıç çapını belirler." #. TRN PrintSettings: #lmFIXME msgid "Branch Diameter Angle" -msgstr "Dal Çapı Açısı" +msgstr "Dal çapı açısı" #. TRN PrintSettings: "Organic supports" > "Branch Diameter Angle" msgid "The angle of the branches' diameter as they gradually become thicker towards the bottom. An angle of 0 will cause the branches to have uniform thickness over their length. A bit of an angle can increase stability of the organic support." @@ -17140,13 +17184,13 @@ msgid "Support Ironing Pattern" msgstr "Destek ütüleme deseni" msgid "Support Ironing flow" -msgstr "Destek ütüleme akışı" +msgstr "Destek ütüleme akış oranı" msgid "The amount of material to extrude during ironing. Relative to flow of normal support interface layer height. Too high value results in overextrusion on the surface." msgstr "Ütüleme sırasında ekstrüde edilecek malzeme miktarı. Normal destek arayüzü katman yüksekliğinin akışına göre. Çok yüksek bir değer, yüzeyde aşırı ekstrüzyona neden olur." msgid "Support Ironing line spacing" -msgstr "Destek ütüleme satır aralığı" +msgstr "Destek ütüleme çizgi aralığı" msgid "Activate temperature control" msgstr "Sıcaklık kontrolünü etkinleştirin" @@ -17194,7 +17238,7 @@ msgid "Chamber minimal temperature" msgstr "Minimum bölme sıcaklığı" msgid "Nozzle temperature after the first layer" -msgstr "İlk katmandan sonraki katmanlar için nozul sıcaklığı." +msgstr "İlk katmandan sonraki nozul sıcaklığı" msgid "Detect thin walls" msgstr "İnce duvarı algıla" @@ -17300,7 +17344,7 @@ msgid "" msgstr "" "Geri çekilirken nozulun son yol boyunca ne kadar süre hareket edeceğini açıklayın.\n" "\n" -"Silme işleminin ne kadar sürdüğüne, ekstruder/filament geri çekme ayarlarının ne kadar hızlı ve uzun olduğuna bağlı olarak, kalan filamanı geri çekmek için bir geri çekme hareketine ihtiyaç duyulabilir.\n" +"Silme işleminin ne kadar sürdüğüne, ekstruder/filament geri çekme ayarlarının ne kadar hızlı ve uzun olduğuna bağlı olarak, kalan filamenti geri çekmek için bir geri çekme hareketine ihtiyaç duyulabilir.\n" "\n" "Aşağıdaki silme ayarından önce geri çekme miktarına bir değer ayarlamak, silme işleminden önce aşırı geri çekme işlemini gerçekleştirecektir, aksi takdirde silme işleminden sonra gerçekleştirilecektir." @@ -17311,7 +17355,7 @@ msgid "Internal ribs" msgstr "İç kaburgalar" msgid "Enable internal ribs to increase the stability of the prime tower." -msgstr "Ana kulenin stabilitesini artırmak için iç kaburgaları etkinleştirin." +msgstr "Hazırlık kulesinin (prime tower) stabilitesini ve mukavemetini artırmak için kulenin içerisine dikey kaburga (takviye) duvarları ekler." msgid "Purging volumes" msgstr "Hacimlerin temizlenmesi" @@ -17384,11 +17428,11 @@ msgid "" "\n" "For the wipe tower external perimeters the internal perimeter speed is used regardless of this setting." msgstr "" -"Silme kulesinde temizleme yaparken ve silme kulesi seyrek katmanlarını yazdırırken maksimum yazdırma hızı. Temizleme sırasında seyrek dolum hızı veya filamanın maksimum hacimsel hızından hesaplanan hız daha düşükse, bunun yerine en düşük olanı kullanılacaktır.\n" +"Silme kulesinde temizleme yaparken ve silme kulesi seyrek katmanlarını yazdırırken maksimum yazdırma hızı. Temizleme sırasında seyrek dolum hızı veya filamentin maksimum hacimsel hızından hesaplanan hız daha düşükse, bunun yerine en düşük olanı kullanılacaktır.\n" "\n" -"Seyrek katmanları yazdırırken iç çevre hızı veya filamanın maksimum hacimsel hızından hesaplanan hız daha düşükse bunun yerine en düşük olanı kullanılacaktır.\n" +"Seyrek katmanları yazdırırken iç çevre hızı veya filamentin maksimum hacimsel hızından hesaplanan hız daha düşükse bunun yerine en düşük olanı kullanılacaktır.\n" "\n" -"Bu hızın arttırılması kulenin stabilitesini etkileyebileceği gibi, nozülün silme kulesi üzerinde oluşmuş olabilecek damlacıklarla çarpışma kuvvetini de arttırabilir.\n" +"Bu hızın arttırılması kulenin stabilitesini etkileyebileceği gibi, nozulun silme kulesi üzerinde oluşmuş olabilecek damlacıklarla çarpışma kuvvetini de arttırabilir.\n" "\n" "Bu parametreyi varsayılan 90 mm/sn’nin üzerine çıkarmadan önce, yazıcınızın artan hızlarda güvenilir şekilde köprü kurabildiğinden ve takım değişimi iyi kontrol edildiğinde sızıntı yaptığından emin olun.\n" "\n" @@ -17415,16 +17459,16 @@ msgid "Rib" msgstr "Kaburga" msgid "Extra rib length" -msgstr "Ekstra rib uzunluğu" +msgstr "Ek kaburga uzunluğu" msgid "Positive values can increase the size of the rib wall, while negative values can reduce the size. However, the size of the rib wall can not be smaller than that determined by the cleaning volume." -msgstr "Pozitif değerler rib duvarının boyutunu artırabilirken, negatif değerler boyutunu azaltabilir. Ancak rib duvarının boyutu temizleme hacmi tarafından belirlenen boyuttan daha küçük olamaz." +msgstr "Ek kaburga (takviye) duvarının boyutunu ayarlar. Pozitif değerler kaburga duvarını büyütürken, negatif değerler küçültür. Ancak kaburga boyutu, temizleme hacmi (cleaning volume) ile belirlenen minimum sınırın altına inemez." msgid "Rib width" -msgstr "Rib genişliği" +msgstr "Kaburga genişliği" msgid "Rib width is always less than half the prime tower side length." -msgstr "Diş genişliği her zaman ana kule yan uzunluğunun yarısından azdır." +msgstr "Kaburga genişliği, her zaman hazırlık kulesinin (prime tower) kenar uzunluğunun yarısından az olmalıdır." msgid "Fillet wall" msgstr "Kavisli duvar" @@ -17478,7 +17522,7 @@ msgid "Maximal bridging distance" msgstr "Maksimum köprüleme mesafesi" msgid "Maximal distance between supports on sparse infill sections." -msgstr "Bu nesne, filamentten tasarruf etmek ve baskı süresini azaltmak için bir filament değişiminden sonra nozulu temizlemek için kullanılacaktır. Sonuç olarak nesnelerin renkleri karıştırılacaktır. Prime tower etkinleştirilmediği sürece etkili olmayacaktır." +msgstr "Seyrek dolgu bölümlerindeki destekler arası maksimum mesafe." msgid "Wipe tower purge lines spacing" msgstr "Silme kulesi temizleme hatları aralığı" @@ -17720,7 +17764,7 @@ msgid "Temperature delta applied during pre-heating before tool change." msgstr "Takım değişiminden önce ön ısıtma sırasında uygulanan sıcaklık farkı." msgid "Detect narrow internal solid infills" -msgstr "Dar iç katı dolguyu tespit et" +msgstr "Dar iç dolguları tespit et" msgid "This option will auto-detect narrow internal solid infill areas. If enabled, the concentric pattern will be used for the area to speed up printing. Otherwise, the rectilinear pattern will be used by default." msgstr "Bu seçenek dar dahili katı dolgu alanını otomatik olarak algılayacaktır. Etkinleştirilirse, yazdırmayı hızlandırmak amacıyla alanda eşmerkezli desen kullanılacaktır. Aksi takdirde varsayılan olarak doğrusal desen kullanılır." @@ -17751,7 +17795,7 @@ msgid "Export slicing data" msgstr "Dilimleme verilerini dışa aktar" msgid "Export slicing data to a folder" -msgstr "Dilimleme verilerini bir klasöre aktarın." +msgstr "Dilimleme verilerini bir klasöre dışa aktar" msgid "Load slicing data" msgstr "Dilimleme verilerini yükle" @@ -17799,13 +17843,13 @@ msgid "mtcpp" msgstr "mtcpp" msgid "max triangle count per plate for slicing" -msgstr "dilimleme için plaka başına maksimum üçgen sayısı." +msgstr "dilimleme için tabla başına maksimum üçgen sayısı" msgid "mstpp" msgstr "mstpp" msgid "max slicing time per plate in seconds" -msgstr "saniye cinsinden plaka başına maksimum dilimleme süresi." +msgstr "tabla başına saniye cinsinden maksimum dilimleme süresi" msgid "No check" msgstr "Kontrol yok" @@ -17916,7 +17960,7 @@ msgid "Load uptodate process/machine settings when using uptodate" msgstr "Güncel olan bir baskı süreci (process) veya makine (printer) profili seçildiğinde, ona ait en güncel ayarları otomatik olarak yükle" msgid "load up-to-date process/machine settings from the specified file when using up-to-date" -msgstr "Güncellemeyi kullanırken belirtilen dosyadan güncel işlem/yazıcı ayarlarını yükle." +msgstr "güncel durumdayken belirtilen dosyadan güncel proses/makine ayarlarını yükle" msgid "Load uptodate filament settings when using uptodate" msgstr "Güncel olan bir filament profili kullanırken, onun en güncel ayarlarını yükle" @@ -18024,13 +18068,13 @@ msgid "MakerLab version to generate this 3MF." msgstr "Bu 3mf’yi oluşturmak için MakerLab sürümü." msgid "Metadata name list" -msgstr "meta veri adı listesi" +msgstr "Meta veri adı listesi" msgid "Metadata name list added into 3MF." msgstr "3mf’ye meta veri adı listesi eklendi." msgid "Metadata value list" -msgstr "meta veri değer listesi" +msgstr "Meta veri değeri listesi" msgid "Metadata value list added into 3MF." msgstr "3mf’ye meta veri değeri listesi eklendi." @@ -18087,7 +18131,7 @@ msgid "Initial extruder" msgstr "İlk ekstruder" msgid "Zero-based index of the first extruder used in the print. Same as initial_tool." -msgstr "Baskıda kullanılan ilk ekstruderin sıfır bazlı indeksi. başlangıç_aracı ile aynı." +msgstr "Baskıda kullanılan ilk ekstruderin sıfır bazlı indeksi. initial_tool ile aynı." msgid "Initial tool" msgstr "Başlangıç aracı" @@ -18135,13 +18179,13 @@ msgid "Weight per extruder" msgstr "Ekstruder başına ağırlık" msgid "Weight per extruder extruded during the entire print. Calculated from filament_density value in Filament Settings." -msgstr "Baskının tamamı boyunca ekstrüzyon yapılan ekstruder başına ağırlık. Filament Ayarlarındaki filaman yoğunluğu değerinden hesaplanır." +msgstr "Baskının tamamı boyunca ekstrüzyon yapılan ekstruder başına ağırlık. Filament Ayarlarındaki filament yoğunluğu değerinden hesaplanır." msgid "Total weight" msgstr "Toplam ağırlık" msgid "Total weight of the print. Calculated from filament_density value in Filament Settings." -msgstr "Baskının toplam ağırlığı. Filament Ayarlarındaki filaman yoğunluğu değerinden hesaplanır." +msgstr "Baskının toplam ağırlığı. Filament Ayarlarındaki filament yoğunluğu değerinden hesaplanır." msgid "Total layer count" msgstr "Toplam katman sayısı" @@ -18177,7 +18221,7 @@ msgid "Wipe tower volume" msgstr "Kule hacmini sil" msgid "Total filament volume extruded on the wipe tower." -msgstr "Silme kulesinde ekstrüzyona tabi tutulan toplam filaman hacmi." +msgstr "Silme kulesinde ekstrüzyona tabi tutulan toplam filament hacmi." msgid "Used filament" msgstr "Kullanılan" @@ -18195,7 +18239,7 @@ msgid "Filament length (meters)" msgstr "Filament uzunluğu (metre)" msgid "Total filament length used in meters. Replaced with actual value during post-processing." -msgstr "Metre cinsinden kullanılan toplam filaman uzunluğu. Son işlem sırasında gerçek değerle değiştirilir." +msgstr "Metre cinsinden kullanılan toplam filament uzunluğu. Son işlem sırasında gerçek değerle değiştirilir." msgid "Number of objects" msgstr "Nesne sayısı" @@ -18390,7 +18434,7 @@ msgid "Meshing of a model file failed or no valid shape." msgstr "Bir model dosyasının meshlenmesi başarısız oldu veya geçerli bir şekil yok." msgid "The supplied file couldn't be read because it's empty." -msgstr "Sağlanan dosya boş olduğundan okunamadı" +msgstr "Seçilen dosya boş olduğundan okunamıyor." msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Bilinmeyen dosya formatı. Giriş dosyası .stl, .obj, .amf(.xml) uzantılı olmalıdır." @@ -18537,7 +18581,7 @@ msgid "" "Within the same extruder, the name(%s) must be unique when the filament type, nozzle diameter, and nozzle flow are the same.\n" "Are you sure you want to override the historical result?" msgstr "" -"Aynı ekstruder içinde filament tipi, nozül çapı ve nozül akışı aynı olduğunda adın(%s) benzersiz olması gerekir.\n" +"Aynı ekstruder içinde filament tipi, nozul çapı ve nozul akışı aynı olduğunda adın(%s) benzersiz olması gerekir.\n" "Geçmiş sonucu geçersiz kılmak istediğinizden emin misiniz?" #, c-format, boost-format @@ -18763,7 +18807,7 @@ msgid "Nozzle Flow" msgstr "Nozul Akışı" msgid "Filament position" -msgstr "filament konumu" +msgstr "Filament konumu" msgid "Filament For Calibration" msgstr "Kalibrasyon İçin Filament" @@ -18798,7 +18842,7 @@ msgid "Sync AMS and nozzle information" msgstr "AMS ve püskürtme ucu bilgilerini senkronize edin" msgid "Calibration only supports cases where the left and right nozzle diameters are identical." -msgstr "Kalibrasyon yalnızca sol ve sağ meme çaplarının aynı olduğu durumları destekler." +msgstr "Kalibrasyon yalnızca sol ve sağ nozul çaplarının aynı olduğu durumları destekler." msgid "From k Value" msgstr "K değerinden" @@ -18853,7 +18897,7 @@ msgstr "Akış Dinamiği Kalibrasyonunu Düzenle" #, c-format, boost-format msgid "Within the same extruder, the name '%s' must be unique when the filament type, nozzle diameter, and nozzle flow are identical. Please choose a different name." -msgstr "Aynı ekstruder içinde, filaman tipi, nozül çapı ve nozül akışı aynı olduğunda '%s' adı benzersiz olmalıdır. Lütfen farklı bir ad seçin." +msgstr "Aynı ekstruder içinde, filament tipi, bozul çapı ve nozul akışı aynı olduğunda '%s' adı benzersiz olmalıdır. Lütfen farklı bir ad seçin." msgid "New Flow Dynamic Calibration" msgstr "Yeni Akış Dinamik Kalibrasyonu" @@ -18865,7 +18909,7 @@ msgid "The extruder must be selected." msgstr "Ekstruder seçilmelidir." msgid "The nozzle must be selected." -msgstr "Meme seçilmelidir." +msgstr "Nozul seçilmelidir." msgid "Network lookup" msgstr "Ağ araması" @@ -18899,6 +18943,20 @@ msgstr "" "%1% ana bilgisayar adına çözümlenen birkaç IP adresi var.\n" "Hangisinin kullanılacağını seçin." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "Nozul için otomatik ölçekleme" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Bu model, 0,4 mm nozul ve 0,2 mm katman yüksekliği esas alınarak tasarlanmıştır. \n" +"Ölçekleme seçeneği etkinleştirildiğinde (önerilir), model mevcut nozul çapınıza ve uygun bir katman yüksekliğine uyacak şekilde dinamik olarak yeniden boyutlandırılır; böylece test hem doğru hem de kolay okunur olur.\n" +"Ölçeklemeyi yalnızca referans modeli olduğu gibi yazdırmak istiyorsanız kapatın." + msgid "PA Calibration" msgstr "PA Kalibrasyonu" @@ -19036,6 +19094,14 @@ msgstr "Başlangıç hızı: " msgid "End speed: " msgstr "Bitiş hızı: " +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "Maksimum hacimsel hıza otomatik ayarlama" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Bitiş hızı filamentin maksimum hacimsel hızını aşacak olursa, bu hıza ulaşabilmek için katman yüksekliği otomatik olarak düşürülür (standart değerler korunarak ve makinenin sınırları içinde kalınarak). Minimum katman yüksekliği bile yeterli değilse, bunun yerine bitiş hızı düşürülür." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -19047,6 +19113,57 @@ msgstr "" "adım >= 0\n" "bitiş > başlangıç + adım)" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"Bitiş hızı (%.0f mm/s), filamentin maksimum hacimsel hızını (%.1f mm³/s) aşıyor; bu da dış duvarı bu çizgi genişliği ve katman yüksekliğinde yaklaşık %.0f mm/s ile sınırlıyor.\n" +" Bunun üzerindeki hızlar sınırlanacağından, kulenin üst blokları istenen hızda yazdırılmayacak.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"Bitiş hızı (%.0f mm/s), filamentin maksimum hacimsel hızını (%.1f mm³/s) varsayılan katman yüksekliğinde (%.2f mm) aşıyor.\n" +"\n" +"Kulenin istenen hıza ulaşabilmesi için katman yüksekliği %.2f mm değerine düşürüldü (bu yazıcının ön ayarlarında kullanılan bir değer)." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Bu yazıcının ön ayarlarında kullanılan en küçük katman yüksekliğinde bile (%.2f mm), bitiş hızı (%.0f mm/s) filamentin maksimum hacimsel hızını (%.1f mm³/s) aşıyor.\n" +"\n" +"Katman yüksekliği %.2f mm olarak ayarlanacak ve bitiş hızı %.0f mm/s değerine düşürülecek.\n" +"\n" +"Devam edilsin mi?" + +# AI Translated +msgid "Continue anyway?" +msgstr "Yine de devam edilsin mi?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Bunu otomatik olarak düzeltmek için \"Otomatik ayarlama\" seçeneğini etkinleştirin ya da yine de devam edilsin mi?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Bunu otomatik olarak düzeltmek için \"Nozul için otomatik ölçekleme\" ve \"Otomatik ayarlama\" seçeneklerini etkinleştirin ya da yine de devam edilsin mi?" + msgid "Start retraction length: " msgstr "Geri çekme uzunluğu başlangıcı: " @@ -19087,7 +19204,7 @@ msgstr "" "Desteklenen şekillendirici türleri için ürün yazılımı belgelerinize bakın." msgid "Frequency (Start / End): " -msgstr "Frekans (Başlangıç ​​/ Bitiş):" +msgstr "Frekans (Başlangıç / Bitiş): " msgid "Start / End" msgstr "Başlangıç / Bitiş" @@ -19126,7 +19243,7 @@ msgid "Check firmware compatibility." msgstr "Firmware uyumluluğunu kontrol edin." msgid "Frequency: " -msgstr "Sıklık:" +msgstr "Frekans: " # AI Translated msgid "Damp" @@ -19155,10 +19272,10 @@ msgid "SCV-V2" msgstr "SCV-V2" msgid "Start: " -msgstr "Başlangıç:" +msgstr "Başlat: " msgid "End: " -msgstr "Son:" +msgstr "Son: " msgid "Cornering settings" msgstr "Viraj alma ayarları" @@ -19400,7 +19517,7 @@ msgid "Subtract with" msgstr "Şununla çıkar" msgid "selected" -msgstr "Seçili" +msgstr "seçildi" msgid "Part 1" msgstr "Bölüm 1" @@ -19588,7 +19705,7 @@ msgid "Input Custom Nozzle Diameter" msgstr "Özel Nozul Çapını Girin" msgid "Can't find my nozzle diameter" -msgstr "Meme çapımı bulamıyorum" +msgstr "Nozul çapımı bulamıyorum" msgid "Printable Space" msgstr "Yazdırılabilir Alan" @@ -19644,7 +19761,7 @@ msgid "" "\tCancel: Do not create a preset; return to the creation interface." msgstr "" "Oluşturduğunuz yazıcı ön ayarının zaten aynı ada sahip bir ön ayarı var. Üzerine yazmak istiyor musunuz?\n" -"\tEvet: Aynı adı taşıyan yazıcı ön ayarının üzerine yazın; aynı ön ayar adı taşıyan filaman ve proses ön ayarları yeniden oluşturulacak ve aynı ön ayar \n" +"\tEvet: Aynı adı taşıyan yazıcı ön ayarının üzerine yazın; aynı ön ayar adı taşıyan filament ve proses ön ayarları yeniden oluşturulacak ve aynı ön ayar \n" "adı olmayan filament ve işlem ön ayarları rezerve edilecektir.\n" "\tİptal: Ön ayar oluşturmayın, oluşturma arayüzüne dönün." @@ -19682,7 +19799,7 @@ msgid "You have not yet selected the printer to replace the nozzle for; please c msgstr "Hala nozulu değiştirmek için yazıcı seçmediniz, lütfen bir seçim yapın." msgid "The entered nozzle diameter is invalid, please re-enter:\n" -msgstr "Girilen meme çapı geçersiz, lütfen tekrar girin:\n" +msgstr "Girilen nozul çapı geçersiz, lütfen tekrar girin:\n" msgid "" "The system preset does not allow creation. \n" @@ -19772,10 +19889,10 @@ msgid "add bundle structure file fail" msgstr "paket yapısı dosyası ekle başarısız" msgid "finalize fail" -msgstr "Tamamlama başarısız" +msgstr "tamamlama başarısız oldu" msgid "open zip written fail" -msgstr "ZIP dosyasını açma başarısız" +msgstr "zip dosyası açılamadı" msgid "Export successful" msgstr "Dışa aktarma başarılı" @@ -19876,7 +19993,7 @@ msgid "" "All the filament presets belong to this filament would be deleted.\n" "If you are using this filament on your printer, please reset the filament information for that slot." msgstr "" -"Bu filamente ait tüm filaman ön ayarları silinecektir.\n" +"Bu filamente ait tüm filament ön ayarları silinecektir.\n" "Yazıcınızda bu filamenti kullanıyorsanız lütfen o yuvanın filament bilgisini sıfırlayın." msgid "Delete filament" @@ -19941,14 +20058,14 @@ msgstr "Yazıcı ekstrüderlerinin sayısı ve kalibrasyon için seçilen yazıc #, c-format, boost-format msgid "The nozzle diameter of %s extruder is 0.2mm which does not support automatic Flow Dynamics calibration." -msgstr "%s ekstruderin meme çapı 0,2 mm'dir ve bu, otomatik Akış Dinamiği kalibrasyonunu desteklemez." +msgstr "%s ekstruderin nozul çapı 0,2 mm'dir ve bu, otomatik Akış Dinamiği kalibrasyonunu desteklemez." #, c-format, boost-format msgid "" "The currently selected nozzle diameter of %s extruder does not match the actual nozzle diameter.\n" "Please click the Sync button above and restart the calibration." msgstr "" -"%s ekstruderin şu anda seçili olan meme çapı, gerçek meme çapıyla eşleşmiyor.\n" +"%s ekstruderin şu anda seçili olan nozul çapı, gerçek nozul çapıyla eşleşmiyor.\n" "Lütfen yukarıdaki Senkronizasyon düğmesine tıklayın ve kalibrasyonu yeniden başlatın." msgid "" @@ -20390,7 +20507,7 @@ msgid "It has a small layer height. This results in almost negligible layer line msgstr "Küçük bir katman yüksekliğine sahiptir ve neredeyse ihmal edilebilir katman çizgileri ve yüksek baskı kalitesi sağlar. Çoğu genel yazdırma durumu için uygundur." msgid "Compared with the default profile of a 0.2 mm nozzle, it has lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in much higher print quality but a much longer print time." -msgstr "0,2 mm’lik nozülün varsayılan profiliyle karşılaştırıldığında daha düşük hız ve ivmeye sahiptir ve seyrek dolgu deseni Gyroid’dir. Böylece çok daha yüksek baskı kalitesi elde edilir, ancak çok daha uzun baskı süresi elde edilir." +msgstr "0,2 mm’lik nozulun varsayılan profiliyle karşılaştırıldığında daha düşük hız ve ivmeye sahiptir ve seyrek dolgu deseni Gyroid’dir. Böylece çok daha yüksek baskı kalitesi elde edilir, ancak çok daha uzun baskı süresi elde edilir." msgid "Compared with the default profile of a 0.2 mm nozzle, it has a slightly bigger layer height. This results in almost negligible layer lines and slightly shorter print time." msgstr "0,2 mm’lik püskürtme ucunun varsayılan profiliyle karşılaştırıldığında, biraz daha büyük katman yüksekliğine sahiptir ve neredeyse ihmal edilebilir düzeyde katman çizgileri ve biraz daha kısa yazdırma süresi sağlar." @@ -20414,7 +20531,7 @@ msgid "It has a normal layer height. This results in average layer lines and pri msgstr "Genel bir katman yüksekliğine sahiptir ve genel katman çizgileri ve baskı kalitesiyle sonuçlanır. Çoğu genel yazdırma durumu için uygundur." msgid "Compared with the default profile of a 0.4 mm nozzle, it has more wall loops and a higher sparse infill density. This results in higher print strength but more filament consumption and longer print time." -msgstr "0,4 mm’lik nozulun varsayılan profiliyle karşılaştırıldığında, daha fazla duvar döngüsüne ve daha yüksek seyrek dolgu yoğunluğuna sahiptir. Bu, baskıların daha güçlü olmasına, ancak daha fazla filaman tüketimine ve daha uzun baskı süresine neden olur." +msgstr "0,4 mm’lik nozulun varsayılan profiliyle karşılaştırıldığında, daha fazla duvar döngüsüne ve daha yüksek seyrek dolgu yoğunluğuna sahiptir. Bu, baskıların daha güçlü olmasına, ancak daha fazla filament tüketimine ve daha uzun baskı süresine neden olur." msgid "Compared with the default profile of a 0.4 mm nozzle, it has a bigger layer height. This results in more apparent layer lines and lower print quality, but slightly shorter print time." msgstr "0,4 mm’lik püskürtme ucunun varsayılan profiliyle karşılaştırıldığında, daha büyük bir katman yüksekliğine sahiptir ve daha belirgin katman çizgileri ve daha düşük baskı kalitesi sağlar, ancak biraz daha kısa yazdırma süresi sağlar." @@ -20426,13 +20543,13 @@ msgid "Compared with the default profile of a 0.4 mm nozzle, it has a smaller la msgstr "0,4 mm’lik püskürtme ucunun varsayılan profiliyle karşılaştırıldığında, daha küçük bir katman yüksekliğine sahiptir ve daha az görünür katman çizgileri ve daha yüksek baskı kalitesi sağlar, ancak daha uzun yazdırma süresi sağlar." msgid "Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height, lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in less apparent layer lines and much higher print quality but much longer print time." -msgstr "0,4 mm’lik nozülün varsayılan profiliyle karşılaştırıldığında daha küçük katman yüksekliğine, daha düşük hızlara ve ivmeye sahiptir ve seyrek dolgu deseni Gyroid’dir. Böylece daha az belirgin katman çizgileri ve çok daha yüksek baskı kalitesi elde edilir, ancak çok daha uzun yazdırma süresi elde edilir." +msgstr "0,4 mm’lik nozulun varsayılan profiliyle karşılaştırıldığında daha küçük katman yüksekliğine, daha düşük hızlara ve ivmeye sahiptir ve seyrek dolgu deseni Gyroid’dir. Böylece daha az belirgin katman çizgileri ve çok daha yüksek baskı kalitesi elde edilir, ancak çok daha uzun yazdırma süresi elde edilir." msgid "Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height. This results in almost negligible layer lines and higher print quality but longer print time." msgstr "0,4 mm’lik püskürtme ucunun varsayılan profiliyle karşılaştırıldığında, katman yüksekliği daha küçüktür ve neredeyse göz ardı edilebilir katman çizgileri ve daha yüksek baskı kalitesi sağlar, ancak daha uzun yazdırma süresi sağlar." msgid "Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height, lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in almost negligible layer lines and much higher print quality but much longer print time." -msgstr "0,4 mm’lik nozülün varsayılan profiliyle karşılaştırıldığında daha küçük katman yüksekliğine, daha düşük hızlara ve ivmeye sahiptir ve seyrek dolgu deseni Gyroid’dir. Böylece, neredeyse göz ardı edilebilecek düzeyde katman çizgileri ve çok daha yüksek baskı kalitesi elde edilirken, çok daha uzun baskı süresi elde edilir." +msgstr "0,4 mm’lik nozulun varsayılan profiliyle karşılaştırıldığında daha küçük katman yüksekliğine, daha düşük hızlara ve ivmeye sahiptir ve seyrek dolgu deseni Gyroid’dir. Böylece, neredeyse göz ardı edilebilecek düzeyde katman çizgileri ve çok daha yüksek baskı kalitesi elde edilirken, çok daha uzun baskı süresi elde edilir." msgid "Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height. This results in almost negligible layer lines and longer print time." msgstr "0,4 mm’lik püskürtme ucunun varsayılan profiliyle karşılaştırıldığında, katman yüksekliği daha küçüktür ve neredeyse göz ardı edilebilecek düzeyde katman çizgileri ve daha uzun yazdırma süresi sağlar." @@ -20441,7 +20558,7 @@ msgid "It has a big layer height. This results in apparent layer lines and ordin msgstr "Büyük bir katman yüksekliğine sahiptir ve belirgin katman çizgileri ile sıradan baskı kalitesi ve baskı süresi sağlar." msgid "Compared with the default profile of a 0.6 mm nozzle, it has more wall loops and a higher sparse infill density. This results in higher print strength but more filament consumption and longer print time." -msgstr "0,6 mm’lik nozulun varsayılan profiliyle karşılaştırıldığında, daha fazla duvar döngüsüne ve daha yüksek seyrek dolgu yoğunluğuna sahiptir. Bu, baskıların daha güçlü olmasına, ancak daha fazla filaman tüketimine ve daha uzun baskı süresine neden olur." +msgstr "0,6 mm’lik nozulun varsayılan profiliyle karşılaştırıldığında, daha fazla duvar döngüsüne ve daha yüksek seyrek dolgu yoğunluğuna sahiptir. Bu, baskıların daha güçlü olmasına, ancak daha fazla filament tüketimine ve daha uzun baskı süresine neden olur." msgid "Compared with the default profile of a 0.6 mm nozzle, it has a bigger layer height. This results in more apparent layer lines and lower print quality, but shorter print time in some cases." msgstr "0,6 mm’lik püskürtme ucunun varsayılan profiliyle karşılaştırıldığında, daha büyük bir katman yüksekliğine sahiptir ve daha belirgin katman çizgileri ve daha düşük baskı kalitesi sağlar, ancak bazı yazdırma durumlarında daha kısa yazdırma süresi sağlar." @@ -20474,16 +20591,16 @@ msgid "This is neither a commonly used filament, nor one of Bambu filaments, and msgstr "Bu ne yaygın olarak kullanılan bir filament ne de Bambu filamentlerinden biri ve markadan markaya çok değişiyor. Bu nedenle, yazdırmadan önce satıcınızdan uygun profili sormanız ve bazı parametreleri performansına göre ayarlamanız önemle tavsiye edilir." msgid "When printing this filament, there's a risk of warping and low layer adhesion strength. To get better results, please refer to this wiki: Printing Tips for High Temp / Engineering materials." -msgstr "Bu filamanı yazdırırken eğrilme ve düşük katman yapışma mukavemeti riski vardır. Daha iyi sonuçlar almak için lütfen şu wiki'ye bakın: Yüksek Sıcaklık / Mühendislik malzemeleri için Yazdırma İpuçları." +msgstr "Bu filamenti yazdırırken eğrilme ve düşük katman yapışma mukavemeti riski vardır. Daha iyi sonuçlar almak için lütfen şu wiki'ye bakın: Yüksek Sıcaklık / Mühendislik malzemeleri için Yazdırma İpuçları." msgid "When printing this filament, there's a risk of nozzle clogging, oozing, warping and low layer adhesion strength. To get better results, please refer to this wiki: Printing Tips for High Temp / Engineering materials." -msgstr "Bu filamanı yazdırırken nozulun tıkanması, sızması, eğrilmesi ve düşük katman yapışma mukavemeti riski vardır. Daha iyi sonuçlar almak için lütfen şu wiki'ye bakın: Yüksek Sıcaklık / Mühendislik malzemeleri için Yazdırma İpuçları." +msgstr "Bu filamenti yazdırırken nozulun tıkanması, sızması, eğrilmesi ve düşük katman yapışma mukavemeti riski vardır. Daha iyi sonuçlar almak için lütfen şu wiki'ye bakın: Yüksek Sıcaklık / Mühendislik malzemeleri için Yazdırma İpuçları." msgid "To get better transparent or translucent results with the corresponding filament, please refer to this wiki: Printing tips for transparent PETG." msgstr "İlgili filamentle daha iyi şeffaf veya yarı şeffaf sonuçlar elde etmek için lütfen şu wiki'ye bakın: Şeffaf PETG için yazdırma ipuçları." msgid "To make the prints get higher gloss, please dry the filament before use, and set the outer wall speed to be 40 to 60 mm/s when slicing." -msgstr "Baskıların daha parlak olmasını sağlamak için lütfen kullanmadan önce filamanı kurutun ve dilimleme sırasında dış duvar hızını 40 ila 60 mm/s olarak ayarlayın." +msgstr "Baskıların daha parlak olmasını sağlamak için lütfen kullanmadan önce filamenti kurutun ve dilimleme sırasında dış duvar hızını 40 ila 60 mm/s olarak ayarlayın." msgid "This filament is only used to print models with a low density usually, and some special parameters are required. To get better printing quality, please refer to this wiki: Instructions for printing RC model with foaming PLA (PLA Aero)." msgstr "Bu filament genellikle yalnızca düşük yoğunluklu modelleri basmak için kullanılır ve bazı özel parametreler gereklidir. Daha iyi baskı kalitesi elde etmek için lütfen bu wiki'ye bakın: RC modelini köpüklü PLA (PLA Aero) ile yazdırma talimatları." @@ -20492,7 +20609,7 @@ msgid "This filament is only used to print models with a low density usually, an msgstr "Bu filament genellikle yalnızca düşük yoğunluklu modelleri basmak için kullanılır ve bazı özel parametreler gereklidir. Daha iyi baskı kalitesi elde etmek için lütfen şu wiki'ye bakın: ASA Aero Printing Guide." msgid "This filament is too soft and not compatible with the AMS. Printing it is of many requirements, and to get better printing quality, please refer to this wiki: TPU printing guide." -msgstr "Bu filaman çok yumuşak ve AMS ile uyumlu değil. Yazdırmanın birçok gereksinimi vardır ve daha iyi yazdırma kalitesi elde etmek için lütfen şu wiki'ye bakın: TPU yazdırma kılavuzu." +msgstr "Bu filament çok yumuşak ve AMS ile uyumlu değil. Yazdırmanın birçok gereksinimi vardır ve daha iyi yazdırma kalitesi elde etmek için lütfen şu wiki'ye bakın: TPU yazdırma kılavuzu." msgid "This filament has high enough hardness (about 67D) and is compatible with the AMS. Printing it is of many requirements, and to get better printing quality, please refer to this wiki: TPU printing guide." msgstr "Bu filament yeterince yüksek sertliğe sahiptir (yaklaşık 67D) ve AMS ile uyumludur. Yazdırmanın birçok gereksinimi vardır ve daha iyi yazdırma kalitesi elde etmek için lütfen şu wiki'ye bakın: TPU yazdırma kılavuzu." @@ -20501,7 +20618,7 @@ msgid "If you are to print a kind of soft TPU, please don't slice with this prof msgstr "Bir tür yumuşak TPU yazdıracaksanız lütfen bu profille kesmeyin; bu yalnızca yeterince yüksek sertliğe sahip (55D'den az olmayan) ve AMS ile uyumlu TPU içindir. Daha iyi baskı kalitesi elde etmek için lütfen şu wiki'ye bakın: TPU yazdırma kılavuzu." msgid "This is a water-soluble support filament, and usually it is only for the support structure and not for the model body. Printing this filament is of many requirements, and to get better printing quality, please refer to this wiki: PVA Printing Guide." -msgstr "Bu suda çözünebilen bir destek filamentidir ve genellikle model gövdesi için değil yalnızca destek yapısı içindir. Bu filamanı yazdırmak birçok gereksinimi gerektirir ve daha iyi baskı kalitesi elde etmek için lütfen şu wiki'ye bakın: PVA Yazdırma Kılavuzu." +msgstr "Bu suda çözünebilen bir destek filamentidir ve genellikle model gövdesi için değil yalnızca destek yapısı içindir. Bu filamenti yazdırmak birçok gereksinimi gerektirir ve daha iyi baskı kalitesi elde etmek için lütfen şu wiki'ye bakın: PVA Yazdırma Kılavuzu." msgid "This is a non-water-soluble support filament, and usually it is only for the support structure and not for the model body. To get better printing quality, please refer to this wiki: Printing Tips for Support Filament and Support Function." msgstr "Bu suda çözünmeyen bir destek filamentidir ve genellikle model gövdesi için değil yalnızca destek yapısı içindir. Daha iyi baskı kalitesi elde etmek için lütfen şu wiki'ye bakın: Destek Filamenti ve Destek Fonksiyonu için Yazdırma İpuçları." @@ -20537,7 +20654,7 @@ msgid "High quality profile for 0.8mm nozzle, prioritizing print quality." msgstr "0,8 mm püskürtme ucu için baskı kalitesini ön planda tutan yüksek kaliteli profil." msgid "Strength profile for 0.8mm nozzle, prioritizing strength." -msgstr "0,8 mm'lik nozül için güç profili, dayanıklılığa öncelik verilir." +msgstr "0,8 mm'lik nozul için güç profili, dayanıklılığa öncelik verilir." msgid "Standard profile for 0.8mm nozzle, prioritizing speed." msgstr "Hıza öncelik veren 0,8 mm nozul için standart profil." @@ -20697,13 +20814,13 @@ msgid "Custom Mode" msgstr "Özel Mod" msgid "Generates filament grouping for the left and right nozzles based on the most filament-saving principles to minimize waste." -msgstr "Atıkları en aza indirmek için en fazla filaman tasarrufu sağlayan ilkelere dayalı olarak sol ve sağ püskürtme uçları için filaman gruplandırması oluşturur." +msgstr "Atıkları en aza indirmek için en fazla filament tasarrufu sağlayan ilkelere dayalı olarak sol ve sağ püskürtme uçları için filament gruplandırması oluşturur." msgid "Generates filament grouping for the left and right nozzles based on the printer's actual filament status, reducing the need for manual filament adjustment." -msgstr "Yazıcının gerçek filaman durumuna göre sol ve sağ püskürtme uçları için filaman gruplandırması oluşturarak manuel filaman ayarlaması ihtiyacını azaltır." +msgstr "Yazıcının gerçek filament durumuna göre sol ve sağ püskürtme uçları için filament gruplandırması oluşturarak manuel filament ayarlaması ihtiyacını azaltır." msgid "Manually assign filament to the left or right nozzle" -msgstr "Filamenti manuel olarak sol veya sağ memeye atayın" +msgstr "Filamenti manuel olarak sol veya sağ nozule atayın" msgid "Global settings" msgstr "Genel ayarlar" @@ -20738,7 +20855,7 @@ msgid "Set the physical nozzle count..." msgstr "Fiziksel nozul sayısını ayarlayın..." msgid "The filament grouping method for current plate is determined by the dropdown option at the slicing plate button." -msgstr "Geçerli plaka için filaman gruplandırma yöntemi, dilimleme plakası düğmesindeki açılır seçenekle belirlenir." +msgstr "Geçerli plaka için filament gruplandırma yöntemi, dilimleme plakası düğmesindeki açılır seçenekle belirlenir." msgid "Connected to Obico successfully!" msgstr "Obico'ya başarıyla bağlanıldı!" @@ -21435,10 +21552,10 @@ msgid "The filament model is unknown. Generic filament presets will be used." msgstr "Filament modeli bilinmiyor. Genel filament ön ayarları kullanılacaktır." msgid "The filament may not be compatible with the current machine settings. A random filament preset will be used." -msgstr "Filament mevcut makine ayarlarıyla uyumlu olmayabilir. Rastgele bir filaman ön ayarı kullanılacaktır." +msgstr "Filament mevcut makine ayarlarıyla uyumlu olmayabilir. Rastgele bir filament ön ayarı kullanılacaktır." msgid "The filament model is unknown. A random filament preset will be used." -msgstr "Filament modeli bilinmiyor. Rastgele bir filaman ön ayarı kullanılacaktır." +msgstr "Filament modeli bilinmiyor. Rastgele bir filament ön ayarı kullanılacaktır." #: resources/data/hints.ini: [hint:Precise wall] msgid "" @@ -21651,8 +21768,7 @@ msgstr "" "Baskılarınızı plakalara ayırın\n" "Çok sayıda parçası olan bir modeli baskıya hazır ayrı kalıplara bölebileceğinizi biliyor muydunuz? Bu, tüm parçaları takip etme sürecini basitleştirecektir." -#: resources/data/hints.ini: [hint:Speed up your print with Adaptive Layer -#: Height] +#: resources/data/hints.ini: [hint:Speed up your print with Adaptive Layer Height] msgid "" "Speed up your print with Adaptive Layer Height\n" "Did you know that you can print a model even faster by using the Adaptive Layer Height option? Check it out!" @@ -21725,8 +21841,7 @@ msgstr "" "Gücü artırın\n" "Modelin gücünü artırmak için daha fazla duvar halkası ve daha yüksek seyrek dolgu yoğunluğu kullanabileceğinizi biliyor muydunuz?" -#: resources/data/hints.ini: [hint:When do you need to print with the printer -#: door opened] +#: resources/data/hints.ini: [hint:When do you need to print with the printer door opened] msgid "" "When do you need to print with the printer door opened?\n" "Did you know that opening the printer door can reduce the probability of extruder/hotend clogging when printing lower temperature filament with a higher enclosure temperature? There is more info about this in the Wiki." @@ -21742,6 +21857,9 @@ msgstr "" "Eğilmeyi önleyin\n" "ABS gibi bükülmeye yatkın malzemelere baskı yaparken, ısıtma yatağı sıcaklığının uygun şekilde arttırılmasının bükülme olasılığını azaltabileceğini biliyor muydunuz?" +#~ msgid "Print order within a single layer." +#~ msgstr "Tek bir katmanda yazdırma sırası." + #~ msgid "Bottom" #~ msgstr "Alt" @@ -21785,10 +21903,10 @@ msgstr "" #~ msgstr "Daha Sonra Yeniden Başlat" #~ msgid "Select filament that installed to the left nozzle" -#~ msgstr "Sol nozüle takılan filamanı seçin" +#~ msgstr "Sol nozule takılan filamenti seçin" #~ msgid "Select filament that installed to the right nozzle" -#~ msgstr "Sağ nozüle takılan filamanı seçin" +#~ msgstr "Sağ nozule takılan filamenti seçin" #, c-format, boost-format #~ msgid "Note: the filament type(%s) does not match with the filament type(%s) in the slicing file. If you want to use this slot, you can install %s instead of %s and change slot information on the 'Device' page." @@ -21799,7 +21917,7 @@ msgstr "" #~ msgstr "Not: yuva boş veya tanımsız. Bu yuvayı kullanmak istiyorsanız 'Cihaz' sayfasından %s yükleyebilir ve yuva bilgilerini değiştirebilirsiniz." #~ msgid "Note: Only filament-loaded slots can be selected." -#~ msgstr "Not: Yalnızca filaman yüklü yuvalar seçilebilir." +#~ msgstr "Not: Yalnızca filament yüklü yuvalar seçilebilir." #~ msgid "Save the printing files initiated from Bambu Studio, Bambu Handy and MakerWorld on External Storage" #~ msgstr "Bambu Studio, Bambu Handy ve MakerWorld'den başlatılan yazdırma dosyalarını Harici Depolamaya kaydedin" @@ -21822,9 +21940,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Continue to sync filaments" #~ msgstr "Filamentleri senkronize etmeye devam edin" @@ -22127,7 +22242,7 @@ msgstr "" #~ msgstr "hafızaya alınan meme boyutu: %d" #~ msgid "The size of nozzle type in preset is not consistent with memorized nozzle. Did you change your nozzle lately?" -#~ msgstr "Ön ayardaki nozül tipinin boyutu hafızaya alınan nozül ile tutarlı değil. Son zamanlarda nozulunuzu değiştirdiniz mi?" +#~ msgstr "Ön ayardaki nozul tipinin boyutu hafızaya alınan nozul ile tutarlı değil. Son zamanlarda nozulunuzu değiştirdiniz mi?" #, c-format, boost-format #~ msgid "nozzle[%d] in preset: %.1f" @@ -22263,7 +22378,7 @@ msgstr "" #~ msgstr "Sol püskürtme ucu: %smm" #~ msgid "Right nozzle: %smm" -#~ msgstr "Sağ nozül: %smm" +#~ msgstr "Sağ nozul: %smm" #~ msgid "\"Fix Model\" feature is currently only on Windows. Please repair the model on Orca Slicer(windows) or CAD softwares." #~ msgstr "\"Modeli Onar\" özelliği şu anda yalnızca Windows'ta bulunmaktadır. Lütfen modeli Orca Slicer (windows) veya CAD yazılımlarında onarın." diff --git a/localization/i18n/uk/OrcaSlicer_uk.po b/localization/i18n/uk/OrcaSlicer_uk.po index 7b838b73b4..9204a67ec3 100644 --- a/localization/i18n/uk/OrcaSlicer_uk.po +++ b/localization/i18n/uk/OrcaSlicer_uk.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: orcaslicerua\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: 2026-07-17 16:25+0300\n" "Last-Translator: Andrij Mizyk \n" "Language-Team: Ukrainian\n" @@ -3796,6 +3796,10 @@ msgstr "Організація..." msgid "Arranging" msgstr "Організація" +# AI Translated +msgid "Arranging " +msgstr "Впорядкування " + msgid "Arranging canceled." msgstr "Організацію скасовано." @@ -8302,21 +8306,21 @@ msgstr "Каталог для заміни не вибрано" msgid "Replaced with 3D files from directory:\n" msgstr "Замінено 3D-файлами з каталогу:\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ Пропущено %1%: той самий файл.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ Пропущено %s: той самий файл.\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ Пропущено %1%: файл не існує.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ Пропущено %s: файл не існує.\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ Пропущено %1%: не вдалося замінити.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ Пропущено %s: не вдалося замінити.\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ Замінено %1%.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ Замінено %s.\n" msgid "Replaced volumes" msgstr "Замінені обʼєми" @@ -9297,6 +9301,21 @@ msgstr "Затемнювати нижні шари" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "Під час прокручування повзунка шарів у попередньому перегляді нарізки відображати шари нижче поточного затемненими, щоб лише переглядуваний шар показувався з повною яскравістю." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Яскравість затемнених шарів" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"Наскільки яскраво відображаються затемнені шари, коли увімкнено параметр «Затемнювати нижні шари».\n" +"99% — затемнення майже непомітне, 0% — шари стають чорними. Максимум обмежено 99%, оскільки 100% дорівнювало б вимкненню параметра." + msgid "Login region" msgstr "Регіон входу" @@ -13531,12 +13550,37 @@ msgstr "По обʼєктах" msgid "Intra-layer order" msgstr "Внутрішній порядок шарів" -msgid "Print order within a single layer." -msgstr "Друк замовлення в один шар" +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Порядок, у якому обходяться екземпляри обʼєктів у межах одного шару; він визначає, скільки переміщень витрачається на переходи між ними.\n" +"\n" +"Типово: побудова ланцюга методом найближчого сусіда з подальшим удосконаленням алгоритмом 2-opt та усуненням перетинів. Хороший універсальний вибір.\n" +"За порядком у списку: екземпляри друкуються в тому самому порядку, що й у списку обʼєктів, без жодної оптимізації шляху. Використовуйте, коли потрібен передбачуваний порядок, заданий вручну.\n" +"Найкращий з усіх (найкоротший шлях): оцінюються всі стратегії й застосовується та, що дає найкоротший шлях. Порядок екземплярів обʼєктів визначається один раз для всього друку, а порядок окремих острівців — для кожного шару окремо, тож різні шари можуть використовувати різні стратегії. Нарізка триває трохи довше.\n" +"Змійкою: змієподібний обхід ряд за рядом з удосконаленням алгоритмом 2-opt. Добре підходить для регулярних сіток із багатьох дрібних деталей.\n" +"\n" +"Якщо в одному шарі використовується кілька філаментів або інструментів, пріоритет має мінімізація змін інструмента: обʼєкти спочатку групуються за філаментом, і цей параметр упорядковує лише екземпляри в межах кожної групи, тож загальна послідовність може не виглядати як найкоротший шлях по пластині." msgid "As object list" msgstr "За порядком у списку" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "Найкращий з усіх (найкоротший шлях)" + +# AI Translated +msgid "Snake" +msgstr "Змійкою" + msgid "Slow printing down for better layer cooling" msgstr "Сповільнювати друк для кращого охолодження шару" @@ -19089,6 +19133,20 @@ msgstr "" "Є кілька IP-адрес, які перетворюються на ім’я хоста %1%.\n" "Будь ласка, виберіть той, який слід використовувати." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "Автомасштабування під сопло" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Ця модель розрахована на сопло 0,4 мм і висоту шару 0,2 мм. \n" +"Коли увімкнено масштабування (рекомендовано), розмір моделі динамічно підлаштовується під діаметр вашого поточного сопла та відповідну висоту шару, завдяки чому тест є точним і легко читається.\n" +"Вимикайте масштабування, лише якщо хочете надрукувати еталонну модель точно в первісному вигляді." + msgid "PA Calibration" msgstr "Калібрування ВТ (РА)" @@ -19230,6 +19288,14 @@ msgstr "Початкова швидкість: " msgid "End speed: " msgstr "Кінцева швидкість: " +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "Автопідлаштування під максимальну обʼємну швидкість" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Якщо кінцева швидкість перевищить максимальну обʼємну швидкість філаменту, автоматично зменшувати висоту шару (зберігаючи стандартні значення та не виходячи за обмеження машини), щоб її досягти. Якщо навіть мінімальної висоти шару не досить, натомість буде знижено кінцеву швидкість." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -19241,6 +19307,57 @@ msgstr "" "крок >= 0\n" "кінець > початок + крок)" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"Кінцева швидкість (%.0f мм/с) перевищує максимальну обʼємну швидкість філаменту (%.1f мм³/с), яка за такої ширини лінії та висоти шару обмежує зовнішню стінку приблизно до %.0f мм/с.\n" +" Вищі швидкості будуть обмежені, тож верхні блоки вежі не надрукуються із заданою швидкістю.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"Кінцева швидкість (%.0f мм/с) перевищує максимальну обʼємну швидкість філаменту (%.1f мм³/с) за типової висоти шару (%.2f мм).\n" +"\n" +"Висоту шару зменшено до %.2f мм (значення, яке використовують профілі цього принтера), щоб вежа могла досягти заданої швидкості." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Навіть за найменшої висоти шару, яку використовують профілі цього принтера (%.2f мм), кінцева швидкість (%.0f мм/с) перевищує максимальну обʼємну швидкість філаменту (%.1f мм³/с).\n" +"\n" +"Висоту шару буде встановлено на %.2f мм, а кінцеву швидкість знижено до %.0f мм/с.\n" +"\n" +"Продовжити?" + +# AI Translated +msgid "Continue anyway?" +msgstr "Усе одно продовжити?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Увімкнути «Автопідлаштування», щоб виправити це автоматично, чи все одно продовжити?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Увімкнути «Автомасштабування під сопло» та «Автопідлаштування», щоб виправити це автоматично, чи все одно продовжити?" + msgid "Start retraction length: " msgstr "Початкова довжина ретракту: " @@ -21862,6 +21979,9 @@ msgstr "" "Уникнення деформації\n" "Чи знаєте ви, що при друку матеріалами, схильними до деформації, такими як ABS, відповідне підвищення температури столу може зменшити ймовірність деформації?" +#~ msgid "Print order within a single layer." +#~ msgstr "Друк замовлення в один шар" + #~ msgid "Bottom" #~ msgstr "Низ" @@ -21940,9 +22060,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "℃" -#~ msgid "%" -#~ msgstr "%" - #~ msgctxt "Sync_Nozzle_AMS" #~ msgid "Cancel" #~ msgstr "Скасувати" diff --git a/localization/i18n/vi/OrcaSlicer_vi.po b/localization/i18n/vi/OrcaSlicer_vi.po index cda4617b7b..e6e7adf43d 100644 --- a/localization/i18n/vi/OrcaSlicer_vi.po +++ b/localization/i18n/vi/OrcaSlicer_vi.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: 2025-10-02 17:43+0700\n" "Last-Translator: \n" "Language-Team: hainguyen.ts13@gmail.com\n" @@ -4031,6 +4031,10 @@ msgstr "Đang sắp xếp..." msgid "Arranging" msgstr "Đang sắp xếp" +# AI Translated +msgid "Arranging " +msgstr "Đang sắp xếp " + msgid "Arranging canceled." msgstr "Hủy sắp xếp." @@ -8717,24 +8721,24 @@ msgid "Replaced with 3D files from directory:\n" msgstr "Đã thay thế bằng file 3D từ thư mục:\n" # AI Translated -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ Đã bỏ qua %1%: cùng một file.\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ Đã bỏ qua %s: cùng một file.\n" # AI Translated -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ Đã bỏ qua %1%: file không tồn tại.\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ Đã bỏ qua %s: file không tồn tại.\n" # AI Translated -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ Đã bỏ qua %1%: thay thế thất bại.\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ Đã bỏ qua %s: thay thế thất bại.\n" # AI Translated -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ Đã thay thế %1%.\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ Đã thay thế %s.\n" # AI Translated msgid "Replaced volumes" @@ -9779,6 +9783,21 @@ msgstr "Làm mờ các lớp bên dưới" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "Khi kéo thanh trượt lớp trong bản xem trước đã slice, kết xuất các lớp bên dưới lớp hiện tại ở dạng tối đi để chỉ lớp đang xem hiển thị với độ sáng đầy đủ." +# AI Translated +msgid "Dimmed layer brightness" +msgstr "Độ sáng của lớp bị làm mờ" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"Mức độ sáng khi hiển thị các lớp bị làm mờ nếu bật \"Làm mờ các lớp bên dưới\".\n" +"99% gần như không tối đi, 0% khiến chúng đen hoàn toàn. Giới hạn ở 99% vì 100% sẽ giống hệt như tắt tùy chọn này." + # AI Translated msgid "Login region" msgstr "Khu vực đăng nhập" @@ -14093,12 +14112,37 @@ msgstr "Theo đối tượng" msgid "Intra-layer order" msgstr "Thứ tự trong lớp" -msgid "Print order within a single layer." -msgstr "Thứ tự in trong một lớp đơn." +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"Thứ tự các instance của đối tượng được đi qua trong cùng một lớp, quyết định lượng di chuyển tiêu tốn khi đi giữa chúng.\n" +"\n" +"Mặc định: nối chuỗi theo láng giềng gần nhất, tinh chỉnh bằng 2-opt và loại bỏ các đoạn cắt nhau. Lựa chọn chung tốt.\n" +"Như danh sách đối tượng: các instance được in theo đúng thứ tự trong danh sách đối tượng, không tối ưu hóa đường đi. Dùng khi bạn cần một thứ tự dễ đoán và tự kiểm soát.\n" +"Tốt nhất trong tất cả (đường đi ngắn nhất): mọi chiến lược đều được đánh giá và chiến lược ngắn nhất được sử dụng. Thứ tự các instance của đối tượng được quyết định một lần cho toàn bộ bản in, còn thứ tự của từng đảo được quyết định theo từng lớp, nên các lớp khác nhau có thể dùng chiến lược khác nhau. Slice hơi chậm hơn một chút.\n" +"Ngoằn ngoèo: duyệt lần lượt từng hàng theo kiểu ngoằn ngoèo, tinh chỉnh bằng 2-opt. Rất phù hợp với các lưới đều gồm nhiều chi tiết nhỏ.\n" +"\n" +"Khi có nhiều filament hoặc đầu công cụ trong cùng một lớp, việc giảm thiểu số lần đổi đầu công cụ được ưu tiên: các đối tượng được nhóm theo filament trước, và thiết lập này chỉ sắp xếp các instance trong từng nhóm filament, nên trình tự tổng thể có thể không giống đường đi ngắn nhất trên bàn in." msgid "As object list" msgstr "Như danh sách đối tượng" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "Tốt nhất trong tất cả (đường đi ngắn nhất)" + +# AI Translated +msgid "Snake" +msgstr "Ngoằn ngoèo" + msgid "Slow printing down for better layer cooling" msgstr "Giảm tốc độ in để làm mát lớp tốt hơn" @@ -19626,6 +19670,20 @@ msgstr "" "Có nhiều địa chỉ IP phân giải thành tên máy chủ %1%.\n" "Vui lòng chọn một địa chỉ nên được sử dụng." +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "Tự động chia tỷ lệ theo đầu phun" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"Mô hình này được thiết kế cho đầu phun 0.4 mm với chiều cao lớp 0.2 mm. \n" +"Khi bật tùy chọn chia tỷ lệ (khuyến nghị), mô hình sẽ tự động thay đổi kích thước cho khớp với đường kính đầu phun hiện tại và một chiều cao lớp phù hợp, giúp bài kiểm tra vừa chính xác vừa dễ đọc.\n" +"Chỉ tắt chia tỷ lệ nếu bạn muốn in mô hình tham chiếu đúng nguyên trạng." + msgid "PA Calibration" msgstr "Hiệu chỉnh PA" @@ -19764,6 +19822,14 @@ msgstr "Tốc độ bắt đầu: " msgid "End speed: " msgstr "Tốc độ kết thúc: " +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "Tự động điều chỉnh theo tốc độ thể tích tối đa" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "Nếu tốc độ kết thúc vượt quá tốc độ thể tích tối đa của filament, tự động giảm chiều cao lớp (giữ các giá trị tiêu chuẩn và nằm trong giới hạn của máy) để đạt được tốc độ đó. Nếu ngay cả chiều cao lớp nhỏ nhất vẫn chưa đủ, thì giảm tốc độ kết thúc thay vào đó." + msgid "" "Please input valid values:\n" "start > 10\n" @@ -19775,6 +19841,57 @@ msgstr "" "bước >= 0\n" "kết thúc > bắt đầu + bước" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"Tốc độ kết thúc (%.0f mm/s) vượt quá tốc độ thể tích tối đa của filament (%.1f mm³/s), khiến thành ngoài bị giới hạn ở khoảng %.0f mm/s với độ rộng đường và chiều cao lớp hiện tại.\n" +" Các tốc độ cao hơn mức này sẽ bị cắt bớt, nên những khối phía trên của tháp sẽ không in ở tốc độ yêu cầu.\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"Tốc độ kết thúc (%.0f mm/s) vượt quá tốc độ thể tích tối đa của filament (%.1f mm³/s) ở chiều cao lớp mặc định (%.2f mm).\n" +"\n" +"Chiều cao lớp đã được giảm xuống %.2f mm (một giá trị được dùng trong các cài đặt sẵn của máy in này) để tháp có thể đạt tốc độ yêu cầu." + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"Ngay cả ở chiều cao lớp nhỏ nhất được dùng trong các cài đặt sẵn của máy in này (%.2f mm), tốc độ kết thúc (%.0f mm/s) vẫn vượt quá tốc độ thể tích tối đa của filament (%.1f mm³/s).\n" +"\n" +"Chiều cao lớp sẽ được đặt thành %.2f mm và tốc độ kết thúc giảm xuống %.0f mm/s.\n" +"\n" +"Tiếp tục?" + +# AI Translated +msgid "Continue anyway?" +msgstr "Vẫn tiếp tục?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Bật \"Tự động điều chỉnh\" để khắc phục việc này tự động, hoặc vẫn tiếp tục?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "Bật \"Tự động chia tỷ lệ theo đầu phun\" và \"Tự động điều chỉnh\" để khắc phục việc này tự động, hoặc vẫn tiếp tục?" + msgid "Start retraction length: " msgstr "Độ dài rút bắt đầu: " @@ -22585,6 +22702,9 @@ msgstr "" "Tránh cong vênh\n" "Bạn có biết rằng khi in vật liệu dễ cong vênh như ABS, tăng nhiệt độ bàn nóng một cách thích hợp có thể giảm xác suất cong vênh không?" +#~ msgid "Print order within a single layer." +#~ msgstr "Thứ tự in trong một lớp đơn." + #~ msgid "Bottom" #~ msgstr "Dưới" @@ -22627,9 +22747,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgctxt "Sync_Nozzle_AMS" #~ msgid "Cancel" #~ msgstr "Hủy" diff --git a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po index 56ab729edb..345891f250 100644 --- a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po +++ b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Slic3rPE\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: 2026-06-11 12:37-0300\n" "Last-Translator: Handle \n" "Language-Team: \n" @@ -3694,6 +3694,10 @@ msgstr "自动摆放中..." msgid "Arranging" msgstr "自动摆放" +# AI Translated +msgid "Arranging " +msgstr "自动摆放 " + msgid "Arranging canceled." msgstr "已取消自动摆放。" @@ -8024,21 +8028,21 @@ msgstr "未选择替换目录" msgid "Replaced with 3D files from directory:\n" msgstr "替换为目录中的 3D 文件:\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ 跳过 %1%:同一文件。\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ 跳过 %s:同一文件。\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ 跳过%1%:文件不存在。\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ 跳过%s:文件不存在。\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ 跳过%1%:替换失败。\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ 跳过%s:替换失败。\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ 替换了 %1%。\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ 替换了 %s。\n" msgid "Replaced volumes" msgstr "替换的卷" @@ -8978,6 +8982,21 @@ msgstr "调暗下方图层" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "在切片预览中拖动图层滑块时,将当前图层下方的图层渲染为变暗状态,以便只有正在查看的图层以完整亮度显示。" +# AI Translated +msgid "Dimmed layer brightness" +msgstr "调暗图层的亮度" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"启用“调暗下方图层”时,被调暗的图层以多高的亮度显示。\n" +"99% 表示几乎不变暗,0% 表示显示为纯黑。上限为 99%,因为 100% 与关闭该选项的效果相同。" + msgid "Login region" msgstr "登录区域" @@ -12949,12 +12968,37 @@ msgstr "逐件" msgid "Intra-layer order" msgstr "层内打印顺序" -msgid "Print order within a single layer." -msgstr "同一层内的打印顺序" +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"在同一层内访问各对象实例的顺序,它决定了在实例之间移动所花费的空驶量。\n" +"\n" +"默认:以最近邻方式串联,并通过 2-opt 和交叉消除进行优化。通常是较好的选择。\n" +"按对象列表中的顺序:不做任何路径优化,按对象列表中的顺序打印各实例。需要可预测、手动控制的顺序时使用。\n" +"全部比较(最短路径):评估所有策略并采用最短的一种。对象实例的顺序在整个打印任务中只确定一次,而各个岛的排序则逐层确定,因此不同层可能采用不同的策略。切片速度略慢。\n" +"蛇形:逐行往复的蛇形遍历,并通过 2-opt 进行优化。非常适合由大量小零件组成的规则阵列。\n" +"\n" +"当同一层中使用多种耗材丝或工具时,优先减少换料次数:对象会先按耗材丝分组,本设置仅决定每个耗材丝分组内实例的顺序,因此整体顺序看起来可能不是整个热床上的最短路径。" msgid "As object list" msgstr "按对象列表中的顺序" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "全部比较(最短路径)" + +# AI Translated +msgid "Snake" +msgstr "蛇形" + msgid "Slow printing down for better layer cooling" msgstr "降低打印速度 以得到更好的冷却" @@ -18278,6 +18322,20 @@ msgstr "" "主机名 %1% 指向了多个IP地址\n" "请在其中选择一个正在使用的地址。" +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "根据喷嘴自动缩放" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"该模型是按 0.4 mm 喷嘴和 0.2 mm 层高设计的。 \n" +"启用缩放选项后(推荐),模型会根据当前喷嘴直径和合适的层高动态调整尺寸,使测试既准确又易于读取。\n" +"只有当您希望完全按原样打印参考模型时,才关闭缩放。" + msgid "PA Calibration" msgstr "压力提前/PA校准" @@ -18412,6 +18470,14 @@ msgstr "起始速度" msgid "End speed: " msgstr "结束速度" +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "自动调整以适应最大体积流量" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "如果结束速度会超过耗材丝的最大体积流量,则自动降低层高(保持标准数值并处于机器限制范围内)以达到该速度。如果连最小层高也不够,则改为降低结束速度。" + msgid "" "Please input valid values:\n" "start > 10\n" @@ -18423,6 +18489,57 @@ msgstr "" "步进长度 >= 0\n" "结束 > 开始 + 步进长度)" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"结束速度(%.0f mm/s)超过了耗材丝的最大体积流量(%.1f mm³/s),在当前线宽和层高下,外墙被限制在约 %.0f mm/s。\n" +" 超过该值的速度会被钳制,因此塔的上部区块不会以请求的速度打印。\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"结束速度(%.0f mm/s)超过了耗材丝的最大体积流量(%.1f mm³/s)(默认层高 %.2f mm 时)。\n" +"\n" +"层高已降至 %.2f mm(该打印机配置中使用的数值),以便塔能够达到请求的速度。" + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"即使采用该打印机配置中使用的最小层高(%.2f mm),结束速度(%.0f mm/s)仍超过耗材丝的最大体积流量(%.1f mm³/s)。\n" +"\n" +"层高将设为 %.2f mm,结束速度将降至 %.0f mm/s。\n" +"\n" +"是否继续?" + +# AI Translated +msgid "Continue anyway?" +msgstr "仍要继续吗?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "启用“自动调整”可自动解决该问题,或者仍要继续?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "启用“根据喷嘴自动缩放”和“自动调整”可自动解决该问题,或者仍要继续?" + msgid "Start retraction length: " msgstr "起始回抽长度" @@ -20994,6 +21111,9 @@ msgstr "" "避免翘曲\n" "您知道吗?打印ABS这类易翘曲材料时,适当提高热床温度可以降低翘曲的概率。" +#~ msgid "Print order within a single layer." +#~ msgstr "同一层内的打印顺序" + #~ msgid "Bottom" #~ msgstr "底部" @@ -21086,9 +21206,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Renders cast shadows on the plate in realistic view." #~ msgstr "在写实渲染中渲染投射到打印板上的阴影。" diff --git a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po index 8885759c88..9b37009978 100644 --- a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po +++ b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-26 21:59-0300\n" +"POT-Creation-Date: 2026-07-29 17:40-0300\n" "PO-Revision-Date: 2025-11-28 13:48-0600\n" "Last-Translator: tntchn <15895303+tntchn@users.noreply.github.com>\n" "Language-Team: \n" @@ -3795,6 +3795,10 @@ msgstr "自動擺放中..." msgid "Arranging" msgstr "自動擺放" +# AI Translated +msgid "Arranging " +msgstr "自動擺放 " + msgid "Arranging canceled." msgstr "已取消自動擺放。" @@ -4675,7 +4679,7 @@ msgid "" "Too small max volumetric speed.\n" "Value was reset to 0.5" msgstr "" -"最大體積速度設定過小\n" +"最大體積流量設定過小\n" "重設為 0.5" #, c-format, boost-format @@ -8189,21 +8193,21 @@ msgstr "未選擇替換的目錄" msgid "Replaced with 3D files from directory:\n" msgstr "已從目錄替換為 3D 檔案:\n" -#, boost-format -msgid "✖ Skipped %1%: same file.\n" -msgstr "✖ 已跳過 %1%:相同檔案。\n" +#, c-format +msgid "✖ Skipped %s: same file.\n" +msgstr "✖ 已跳過 %s:相同檔案。\n" -#, boost-format -msgid "✖ Skipped %1%: file does not exist.\n" -msgstr "✖ 已跳過 %1%:檔案不存在。\n" +#, c-format +msgid "✖ Skipped %s: file does not exist.\n" +msgstr "✖ 已跳過 %s:檔案不存在。\n" -#, boost-format -msgid "✖ Skipped %1%: failed to replace.\n" -msgstr "✖ 已跳過 %1%:無法替換。\n" +#, c-format +msgid "✖ Skipped %s: failed to replace.\n" +msgstr "✖ 已跳過 %s:無法替換。\n" -#, boost-format -msgid "✔ Replaced %1%.\n" -msgstr "✔ 已替換 %1%。\n" +#, c-format +msgid "✔ Replaced %s.\n" +msgstr "✔ 已替換 %s。\n" msgid "Replaced volumes" msgstr "已替換體積" @@ -9151,6 +9155,21 @@ msgstr "使下方層變暗" msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness." msgstr "在切片預覽中拖曳層滑桿時,將目前層以下的各層算繪為變暗,如此只有正在檢視的層以全亮度顯示。" +# AI Translated +msgid "Dimmed layer brightness" +msgstr "變暗層的亮度" + +msgid "%" +msgstr "%" + +# AI Translated +msgid "" +"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" +"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option." +msgstr "" +"啟用「使下方層變暗」時,變暗的層以多高的亮度顯示。\n" +"99% 幾乎不會變暗,0% 會顯示為全黑。上限為 99%,因為 100% 與停用此選項的效果相同。" + msgid "Login region" msgstr "登入區域" @@ -13162,12 +13181,37 @@ msgstr "逐件" msgid "Intra-layer order" msgstr "單層順序" -msgid "Print order within a single layer." -msgstr "每一層的列印順序" +# AI Translated +msgid "" +"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n" +"\n" +"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n" +"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n" +"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n" +"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n" +"\n" +"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate." +msgstr "" +"在同一層內走訪各物件實例的順序,這會決定在實例之間移動所花費的空駛量。\n" +"\n" +"預設:以最近鄰方式串接,並以 2-opt 與交叉消除進行改善。通常是不錯的選擇。\n" +"按照物件清單排序:不做任何路徑最佳化,依照物件清單的順序列印各實例。需要可預測、手動控制的順序時使用。\n" +"全部比較(最短路徑):評估所有策略並採用最短的一種。物件實例的順序在整個列印工作中只決定一次,而個別島嶼的排序則逐層決定,因此不同層可能採用不同的策略。切片速度略慢。\n" +"蛇形:逐行往復的蛇形走訪,並以 2-opt 進行改善。非常適合由大量小零件組成的規則陣列。\n" +"\n" +"當同一層中使用多種線材或工具時,會優先減少換料次數:物件會先依線材分組,此設定僅決定每個線材群組內實例的順序,因此整體順序看起來可能不是整個列印板上的最短路徑。" msgid "As object list" msgstr "按照物件清單排序" +# AI Translated +msgid "Best of all (shortest path)" +msgstr "全部比較(最短路徑)" + +# AI Translated +msgid "Snake" +msgstr "蛇形" + msgid "Slow printing down for better layer cooling" msgstr "降低列印速度 以得到更好的冷卻" @@ -18461,6 +18505,20 @@ msgstr "" "有多個 IP 位址解析到主機名稱 %1%。\n" "請選擇一個要使用的 IP 位址。" +# AI Translated +msgid "Auto-scale for nozzle" +msgstr "依噴嘴自動縮放" + +# AI Translated +msgid "" +"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n" +"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n" +"Turn scaling off only if you wish to print the reference model exactly as-is." +msgstr "" +"此模型是以 0.4 mm 噴嘴與 0.2 mm 層高為基準設計的。 \n" +"啟用縮放選項後(建議),模型會依目前的噴嘴直徑與合適的層高動態調整尺寸,使測試既準確又容易判讀。\n" +"只有在您想完全按原樣列印參考模型時,才關閉縮放。" + msgid "PA Calibration" msgstr "PA 校正" @@ -18597,6 +18655,14 @@ msgstr "起始速度:" msgid "End speed: " msgstr "結束速度:" +# AI Translated +msgid "Auto-adjust to max volumetric speed" +msgstr "自動調整以符合最大體積流量" + +# AI Translated +msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead." +msgstr "如果結束速度會超過線材的最大體積流量,則自動降低層高(維持標準數值並處於機器限制範圍內)以達到該速度。如果連最小層高也不夠,則改為降低結束速度。" + msgid "" "Please input valid values:\n" "start > 10\n" @@ -18608,6 +18674,57 @@ msgstr "" "步距 >= 0\n" "結束 > 開始 + 步距)" +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n" +" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n" +"\n" +"%s" +msgstr "" +"結束速度(%.0f mm/s)超過線材的最大體積流量(%.1f mm³/s),在目前的線寬與層高下,外牆被限制在約 %.0f mm/s。\n" +" 超過該值的速度會被箝制,因此塔的上部區塊不會以要求的速度列印。\n" +"\n" +"%s" + +# AI Translated +#, c-format, boost-format +msgid "" +"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n" +"\n" +"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed." +msgstr "" +"結束速度(%.0f mm/s)超過線材的最大體積流量(%.1f mm³/s)(預設層高 %.2f mm 時)。\n" +"\n" +"層高已降至 %.2f mm(此印表機的設定檔中使用的數值),以便塔能夠達到要求的速度。" + +# AI Translated +#, c-format, boost-format +msgid "" +"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n" +"\n" +"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n" +"\n" +"Continue?" +msgstr "" +"即使採用此印表機的設定檔中使用的最小層高(%.2f mm),結束速度(%.0f mm/s)仍超過線材的最大體積流量(%.1f mm³/s)。\n" +"\n" +"層高將設為 %.2f mm,結束速度將降至 %.0f mm/s。\n" +"\n" +"是否繼續?" + +# AI Translated +msgid "Continue anyway?" +msgstr "仍要繼續嗎?" + +# AI Translated +msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "啟用「自動調整」可自動解決此問題,或者仍要繼續?" + +# AI Translated +msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?" +msgstr "啟用「依噴嘴自動縮放」和「自動調整」可自動解決此問題,或者仍要繼續?" + msgid "Start retraction length: " msgstr "起始回抽長度:" @@ -21206,6 +21323,9 @@ msgstr "" "避免翹曲\n" "您知道嗎?當列印容易翹曲的材料(如 ABS)時,適當提高熱床溫度可以降低翹曲的機率。" +#~ msgid "Print order within a single layer." +#~ msgstr "每一層的列印順序" + #~ msgid "Bottom" #~ msgstr "底部" @@ -21298,9 +21418,6 @@ msgstr "" #~ msgid "°C" #~ msgstr "°C" -#~ msgid "%" -#~ msgstr "%" - #~ msgid "Renders cast shadows on the plate in realistic view." #~ msgstr "在擬真檢視中於列印板上算繪投射陰影。" diff --git a/resources/profiles/Creality.json b/resources/profiles/Creality.json index 8e91974b9c..077ee827e5 100644 --- a/resources/profiles/Creality.json +++ b/resources/profiles/Creality.json @@ -1,6 +1,6 @@ { "name": "Creality", - "version": "02.03.02.75", + "version": "02.03.02.76", "force_update": "0", "description": "Creality configurations", "machine_model_list": [ diff --git a/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1 (0.4 nozzle).json b/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1 (0.4 nozzle).json index 8bf73caf41..7300c45c8d 100644 --- a/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1 (0.4 nozzle).json +++ b/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1 (0.4 nozzle).json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1 Max_CFS-C 0.4 nozzle.json b/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1 Max_CFS-C 0.4 nozzle.json index 5ff07e264b..adc86b4768 100644 --- a/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1 Max_CFS-C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1 Max_CFS-C 0.4 nozzle.json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1C 0.4 nozzle.json b/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1C 0.4 nozzle.json index fbc953f420..976756a212 100644 --- a/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1C 0.4 nozzle.json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1C_CFS-C 0.4 nozzle.json b/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1C_CFS-C 0.4 nozzle.json index bacd88b9f3..6748914ae7 100644 --- a/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1C_CFS-C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1C_CFS-C 0.4 nozzle.json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1Max (0.4 nozzle).json b/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1Max (0.4 nozzle).json index 1083550af8..f3f37caca7 100644 --- a/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1Max (0.4 nozzle).json +++ b/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1Max (0.4 nozzle).json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1_CFS-C 0.4 nozzle.json b/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1_CFS-C 0.4 nozzle.json index 3e98181430..0144a35372 100644 --- a/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1_CFS-C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.08mm SuperDetail @Creality K1_CFS-C 0.4 nozzle.json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 (0.4 nozzle).json b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 (0.4 nozzle).json index dba47d76a5..d6caa5e775 100644 --- a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 (0.4 nozzle).json +++ b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 (0.4 nozzle).json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 Max_CFS-C 0.4 nozzle.json b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 Max_CFS-C 0.4 nozzle.json index ef22dc37ab..a1896fa377 100644 --- a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 Max_CFS-C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 Max_CFS-C 0.4 nozzle.json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 SE 0.4 nozzle.json b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 SE 0.4 nozzle.json index 2ac16fb484..087d90a584 100644 --- a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 SE 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 SE 0.4 nozzle.json @@ -38,7 +38,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 SE_CFS-C 0.4 nozzle.json b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 SE_CFS-C 0.4 nozzle.json index b247bece36..62708a822a 100644 --- a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 SE_CFS-C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 SE_CFS-C 0.4 nozzle.json @@ -38,7 +38,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1C 0.4 nozzle.json b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1C 0.4 nozzle.json index b1d6201ba7..5deb17002e 100644 --- a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1C 0.4 nozzle.json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1C_CFS-C 0.4 nozzle.json b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1C_CFS-C 0.4 nozzle.json index 44dc07e070..2365a82d31 100644 --- a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1C_CFS-C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1C_CFS-C 0.4 nozzle.json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1Max (0.4 nozzle).json b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1Max (0.4 nozzle).json index 0b4ae9c777..02507c806f 100644 --- a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1Max (0.4 nozzle).json +++ b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1Max (0.4 nozzle).json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1_CFS-C 0.4 nozzle.json b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1_CFS-C 0.4 nozzle.json index 6b201d6f4d..cda928b2e7 100644 --- a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1_CFS-C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1_CFS-C 0.4 nozzle.json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.20mm Standard @Creality K1 (0.4 nozzle).json b/resources/profiles/Creality/process/0.20mm Standard @Creality K1 (0.4 nozzle).json index 42e894eecd..eaaeb4529f 100644 --- a/resources/profiles/Creality/process/0.20mm Standard @Creality K1 (0.4 nozzle).json +++ b/resources/profiles/Creality/process/0.20mm Standard @Creality K1 (0.4 nozzle).json @@ -128,7 +128,7 @@ "detect_narrow_internal_solid_infill": "1", "dont_filter_internal_bridges": "disabled", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enforce_support_layers": "0", "ensure_vertical_shell_thickness": "ensure_all", diff --git a/resources/profiles/Creality/process/0.20mm Standard @Creality K1 Max_CFS-C 0.4 nozzle.json b/resources/profiles/Creality/process/0.20mm Standard @Creality K1 Max_CFS-C 0.4 nozzle.json index f765f850c8..1a4bd4a3f3 100644 --- a/resources/profiles/Creality/process/0.20mm Standard @Creality K1 Max_CFS-C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.20mm Standard @Creality K1 Max_CFS-C 0.4 nozzle.json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.20mm Standard @Creality K1 SE 0.4.json b/resources/profiles/Creality/process/0.20mm Standard @Creality K1 SE 0.4.json index 003a8287ae..19b01a9964 100644 --- a/resources/profiles/Creality/process/0.20mm Standard @Creality K1 SE 0.4.json +++ b/resources/profiles/Creality/process/0.20mm Standard @Creality K1 SE 0.4.json @@ -124,7 +124,7 @@ "detect_narrow_internal_solid_infill": "1", "dont_filter_internal_bridges": "disabled", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enforce_support_layers": "0", "ensure_vertical_shell_thickness": "ensure_all", diff --git a/resources/profiles/Creality/process/0.20mm Standard @Creality K1 SE_CFS-C 0.4 nozzle.json b/resources/profiles/Creality/process/0.20mm Standard @Creality K1 SE_CFS-C 0.4 nozzle.json index 85de09803b..b7365760f4 100644 --- a/resources/profiles/Creality/process/0.20mm Standard @Creality K1 SE_CFS-C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.20mm Standard @Creality K1 SE_CFS-C 0.4 nozzle.json @@ -38,7 +38,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.20mm Standard @Creality K1C 0.4 nozzle.json b/resources/profiles/Creality/process/0.20mm Standard @Creality K1C 0.4 nozzle.json index c33dc038f5..aa8e7b440a 100644 --- a/resources/profiles/Creality/process/0.20mm Standard @Creality K1C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.20mm Standard @Creality K1C 0.4 nozzle.json @@ -128,7 +128,7 @@ "detect_narrow_internal_solid_infill": "1", "dont_filter_internal_bridges": "disabled", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enforce_support_layers": "0", "ensure_vertical_shell_thickness": "ensure_all", diff --git a/resources/profiles/Creality/process/0.20mm Standard @Creality K1C_CFS-C 0.4 nozzle.json b/resources/profiles/Creality/process/0.20mm Standard @Creality K1C_CFS-C 0.4 nozzle.json index 7957e09303..882703434d 100644 --- a/resources/profiles/Creality/process/0.20mm Standard @Creality K1C_CFS-C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.20mm Standard @Creality K1C_CFS-C 0.4 nozzle.json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.20mm Standard @Creality K1Max (0.4 nozzle).json b/resources/profiles/Creality/process/0.20mm Standard @Creality K1Max (0.4 nozzle).json index cea8966d46..51ada298d8 100644 --- a/resources/profiles/Creality/process/0.20mm Standard @Creality K1Max (0.4 nozzle).json +++ b/resources/profiles/Creality/process/0.20mm Standard @Creality K1Max (0.4 nozzle).json @@ -128,7 +128,7 @@ "detect_narrow_internal_solid_infill": "1", "dont_filter_internal_bridges": "disabled", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enforce_support_layers": "0", "ensure_vertical_shell_thickness": "ensure_all", diff --git a/resources/profiles/Creality/process/0.20mm Standard @Creality K1_CFS-C 0.4 nozzle.json b/resources/profiles/Creality/process/0.20mm Standard @Creality K1_CFS-C 0.4 nozzle.json index a617d8e2b4..85dd6bbf3d 100644 --- a/resources/profiles/Creality/process/0.20mm Standard @Creality K1_CFS-C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.20mm Standard @Creality K1_CFS-C 0.4 nozzle.json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.24mm Draft @Creality K1 (0.4 nozzle).json b/resources/profiles/Creality/process/0.24mm Draft @Creality K1 (0.4 nozzle).json index 051a14e1d4..ce0abbf5ac 100644 --- a/resources/profiles/Creality/process/0.24mm Draft @Creality K1 (0.4 nozzle).json +++ b/resources/profiles/Creality/process/0.24mm Draft @Creality K1 (0.4 nozzle).json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.24mm Draft @Creality K1 Max_CFS-C 0.4 nozzle.json b/resources/profiles/Creality/process/0.24mm Draft @Creality K1 Max_CFS-C 0.4 nozzle.json index 8170eb02d6..afd921a54b 100644 --- a/resources/profiles/Creality/process/0.24mm Draft @Creality K1 Max_CFS-C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.24mm Draft @Creality K1 Max_CFS-C 0.4 nozzle.json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.24mm Draft @Creality K1 SE 0.4 nozzle.json b/resources/profiles/Creality/process/0.24mm Draft @Creality K1 SE 0.4 nozzle.json index 349601c857..34a577c896 100644 --- a/resources/profiles/Creality/process/0.24mm Draft @Creality K1 SE 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.24mm Draft @Creality K1 SE 0.4 nozzle.json @@ -38,7 +38,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.24mm Draft @Creality K1 SE_CFS-C 0.4 nozzle.json b/resources/profiles/Creality/process/0.24mm Draft @Creality K1 SE_CFS-C 0.4 nozzle.json index 40ecd965b1..3522e46d5a 100644 --- a/resources/profiles/Creality/process/0.24mm Draft @Creality K1 SE_CFS-C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.24mm Draft @Creality K1 SE_CFS-C 0.4 nozzle.json @@ -38,7 +38,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.24mm Draft @Creality K1C 0.4 nozzle.json b/resources/profiles/Creality/process/0.24mm Draft @Creality K1C 0.4 nozzle.json index ef58869e10..697593d8c4 100644 --- a/resources/profiles/Creality/process/0.24mm Draft @Creality K1C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.24mm Draft @Creality K1C 0.4 nozzle.json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.24mm Draft @Creality K1C_CFS-C 0.4 nozzle.json b/resources/profiles/Creality/process/0.24mm Draft @Creality K1C_CFS-C 0.4 nozzle.json index af9f2c5b86..b3bf816290 100644 --- a/resources/profiles/Creality/process/0.24mm Draft @Creality K1C_CFS-C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.24mm Draft @Creality K1C_CFS-C 0.4 nozzle.json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.24mm Draft @Creality K1Max (0.4 nozzle).json b/resources/profiles/Creality/process/0.24mm Draft @Creality K1Max (0.4 nozzle).json index cea238f1f3..9f886804e3 100644 --- a/resources/profiles/Creality/process/0.24mm Draft @Creality K1Max (0.4 nozzle).json +++ b/resources/profiles/Creality/process/0.24mm Draft @Creality K1Max (0.4 nozzle).json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.24mm Draft @Creality K1_CFS-C 0.4 nozzle.json b/resources/profiles/Creality/process/0.24mm Draft @Creality K1_CFS-C 0.4 nozzle.json index 5f91995b41..16ebf21b9a 100644 --- a/resources/profiles/Creality/process/0.24mm Draft @Creality K1_CFS-C 0.4 nozzle.json +++ b/resources/profiles/Creality/process/0.24mm Draft @Creality K1_CFS-C 0.4 nozzle.json @@ -39,7 +39,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "1", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.30mm Standard @Creality K1 (0.6 nozzle).json b/resources/profiles/Creality/process/0.30mm Standard @Creality K1 (0.6 nozzle).json index 1259ac5186..a4bd5b2abc 100644 --- a/resources/profiles/Creality/process/0.30mm Standard @Creality K1 (0.6 nozzle).json +++ b/resources/profiles/Creality/process/0.30mm Standard @Creality K1 (0.6 nozzle).json @@ -126,7 +126,7 @@ "detect_narrow_internal_solid_infill": "1", "dont_filter_internal_bridges": "disabled", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enforce_support_layers": "0", "ensure_vertical_shell_thickness": "ensure_all", diff --git a/resources/profiles/Creality/process/0.30mm Standard @Creality K1 SE 0.6 nozzle.json b/resources/profiles/Creality/process/0.30mm Standard @Creality K1 SE 0.6 nozzle.json index 81e54598e3..d4073f4221 100644 --- a/resources/profiles/Creality/process/0.30mm Standard @Creality K1 SE 0.6 nozzle.json +++ b/resources/profiles/Creality/process/0.30mm Standard @Creality K1 SE 0.6 nozzle.json @@ -38,7 +38,7 @@ "draft_shield": "disabled", "elefant_foot_compensation": "0.15", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enable_prime_tower": "0", "enable_support": "0", diff --git a/resources/profiles/Creality/process/0.30mm Standard @Creality K1C 0.6 nozzle.json b/resources/profiles/Creality/process/0.30mm Standard @Creality K1C 0.6 nozzle.json index 71ecb52e77..3f86d9e613 100644 --- a/resources/profiles/Creality/process/0.30mm Standard @Creality K1C 0.6 nozzle.json +++ b/resources/profiles/Creality/process/0.30mm Standard @Creality K1C 0.6 nozzle.json @@ -126,7 +126,7 @@ "detect_narrow_internal_solid_infill": "1", "dont_filter_internal_bridges": "disabled", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enforce_support_layers": "0", "ensure_vertical_shell_thickness": "ensure_all", diff --git a/resources/profiles/Creality/process/0.30mm Standard @Creality K1Max (0.6 nozzle).json b/resources/profiles/Creality/process/0.30mm Standard @Creality K1Max (0.6 nozzle).json index db9e4b1539..54ac0870a4 100644 --- a/resources/profiles/Creality/process/0.30mm Standard @Creality K1Max (0.6 nozzle).json +++ b/resources/profiles/Creality/process/0.30mm Standard @Creality K1Max (0.6 nozzle).json @@ -126,7 +126,7 @@ "detect_narrow_internal_solid_infill": "1", "dont_filter_internal_bridges": "disabled", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enforce_support_layers": "0", "ensure_vertical_shell_thickness": "ensure_all", diff --git a/resources/profiles/Creality/process/0.40mm Standard @Creality K1 (0.8 nozzle).json b/resources/profiles/Creality/process/0.40mm Standard @Creality K1 (0.8 nozzle).json index 5f61b218bc..2de391b8ad 100644 --- a/resources/profiles/Creality/process/0.40mm Standard @Creality K1 (0.8 nozzle).json +++ b/resources/profiles/Creality/process/0.40mm Standard @Creality K1 (0.8 nozzle).json @@ -126,7 +126,7 @@ "detect_narrow_internal_solid_infill": "1", "dont_filter_internal_bridges": "disabled", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enforce_support_layers": "0", "ensure_vertical_shell_thickness": "ensure_all", diff --git a/resources/profiles/Creality/process/0.40mm Standard @Creality K1C 0.8 nozzle.json b/resources/profiles/Creality/process/0.40mm Standard @Creality K1C 0.8 nozzle.json index d5d5d62cda..5cd1a9cb6a 100644 --- a/resources/profiles/Creality/process/0.40mm Standard @Creality K1C 0.8 nozzle.json +++ b/resources/profiles/Creality/process/0.40mm Standard @Creality K1C 0.8 nozzle.json @@ -126,7 +126,7 @@ "detect_narrow_internal_solid_infill": "1", "dont_filter_internal_bridges": "disabled", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enforce_support_layers": "0", "ensure_vertical_shell_thickness": "ensure_all", diff --git a/resources/profiles/Creality/process/0.40mm Standard @Creality K1Max (0.8 nozzle).json b/resources/profiles/Creality/process/0.40mm Standard @Creality K1Max (0.8 nozzle).json index 793c6aa43e..c1c968cbb6 100644 --- a/resources/profiles/Creality/process/0.40mm Standard @Creality K1Max (0.8 nozzle).json +++ b/resources/profiles/Creality/process/0.40mm Standard @Creality K1Max (0.8 nozzle).json @@ -126,7 +126,7 @@ "detect_narrow_internal_solid_infill": "1", "dont_filter_internal_bridges": "disabled", "elefant_foot_compensation_layers": "1", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "enable_overhang_speed": "1", "enforce_support_layers": "0", "ensure_vertical_shell_thickness": "ensure_all", diff --git a/resources/profiles/Custom.json b/resources/profiles/Custom.json index a416f17db0..7eba013111 100644 --- a/resources/profiles/Custom.json +++ b/resources/profiles/Custom.json @@ -1,6 +1,6 @@ { "name": "Custom Printer", - "version": "02.04.00.01", + "version": "02.04.00.03", "force_update": "0", "description": "My configurations", "machine_model_list": [ diff --git a/resources/profiles/Custom/filament/Generic ABS @MyToolChanger.json b/resources/profiles/Custom/filament/Generic ABS @MyToolChanger.json index 1683513dbd..bf48e0488b 100644 --- a/resources/profiles/Custom/filament/Generic ABS @MyToolChanger.json +++ b/resources/profiles/Custom/filament/Generic ABS @MyToolChanger.json @@ -24,12 +24,6 @@ "filament_loading_speed_start": [ "50" ], - "filament_multitool_ramming": [ - "1" - ], - "filament_multitool_ramming_flow": [ - "40" - ], "filament_stamping_distance": [ "45" ], diff --git a/resources/profiles/Custom/filament/Generic ASA @MyToolChanger.json b/resources/profiles/Custom/filament/Generic ASA @MyToolChanger.json index 5cc46deb7e..ad26608bff 100644 --- a/resources/profiles/Custom/filament/Generic ASA @MyToolChanger.json +++ b/resources/profiles/Custom/filament/Generic ASA @MyToolChanger.json @@ -24,12 +24,6 @@ "filament_loading_speed_start": [ "50" ], - "filament_multitool_ramming": [ - "1" - ], - "filament_multitool_ramming_flow": [ - "40" - ], "filament_stamping_distance": [ "45" ], diff --git a/resources/profiles/Custom/filament/Generic PA @MyToolChanger.json b/resources/profiles/Custom/filament/Generic PA @MyToolChanger.json index 0c8918427d..d710282360 100644 --- a/resources/profiles/Custom/filament/Generic PA @MyToolChanger.json +++ b/resources/profiles/Custom/filament/Generic PA @MyToolChanger.json @@ -24,12 +24,6 @@ "filament_loading_speed_start": [ "50" ], - "filament_multitool_ramming": [ - "1" - ], - "filament_multitool_ramming_flow": [ - "40" - ], "filament_stamping_distance": [ "45" ], diff --git a/resources/profiles/Custom/filament/Generic PA-CF @MyToolChanger.json b/resources/profiles/Custom/filament/Generic PA-CF @MyToolChanger.json index a7d86885ef..481fd04152 100644 --- a/resources/profiles/Custom/filament/Generic PA-CF @MyToolChanger.json +++ b/resources/profiles/Custom/filament/Generic PA-CF @MyToolChanger.json @@ -24,12 +24,6 @@ "filament_loading_speed_start": [ "50" ], - "filament_multitool_ramming": [ - "1" - ], - "filament_multitool_ramming_flow": [ - "40" - ], "filament_stamping_distance": [ "45" ], diff --git a/resources/profiles/Custom/filament/Generic PC @MyToolChanger.json b/resources/profiles/Custom/filament/Generic PC @MyToolChanger.json index d80b197394..47f175c277 100644 --- a/resources/profiles/Custom/filament/Generic PC @MyToolChanger.json +++ b/resources/profiles/Custom/filament/Generic PC @MyToolChanger.json @@ -25,12 +25,6 @@ "filament_loading_speed_start": [ "50" ], - "filament_multitool_ramming": [ - "1" - ], - "filament_multitool_ramming_flow": [ - "40" - ], "filament_stamping_distance": [ "45" ], diff --git a/resources/profiles/Custom/filament/Generic PETG @MyToolChanger.json b/resources/profiles/Custom/filament/Generic PETG @MyToolChanger.json index 693551c428..95e47a32a8 100644 --- a/resources/profiles/Custom/filament/Generic PETG @MyToolChanger.json +++ b/resources/profiles/Custom/filament/Generic PETG @MyToolChanger.json @@ -25,12 +25,6 @@ "filament_loading_speed_start": [ "50" ], - "filament_multitool_ramming": [ - "1" - ], - "filament_multitool_ramming_flow": [ - "40" - ], "filament_stamping_distance": [ "45" ], diff --git a/resources/profiles/Custom/filament/Generic PLA @MyToolChanger.json b/resources/profiles/Custom/filament/Generic PLA @MyToolChanger.json index cf1db6e225..b8fe088325 100644 --- a/resources/profiles/Custom/filament/Generic PLA @MyToolChanger.json +++ b/resources/profiles/Custom/filament/Generic PLA @MyToolChanger.json @@ -25,12 +25,6 @@ "filament_loading_speed_start": [ "50" ], - "filament_multitool_ramming": [ - "1" - ], - "filament_multitool_ramming_flow": [ - "40" - ], "filament_stamping_distance": [ "45" ], diff --git a/resources/profiles/Custom/filament/Generic PLA-CF @MyToolChanger.json b/resources/profiles/Custom/filament/Generic PLA-CF @MyToolChanger.json index 6ae729d622..4a766aa3ef 100644 --- a/resources/profiles/Custom/filament/Generic PLA-CF @MyToolChanger.json +++ b/resources/profiles/Custom/filament/Generic PLA-CF @MyToolChanger.json @@ -25,12 +25,6 @@ "filament_loading_speed_start": [ "50" ], - "filament_multitool_ramming": [ - "1" - ], - "filament_multitool_ramming_flow": [ - "40" - ], "filament_stamping_distance": [ "45" ], diff --git a/resources/profiles/Custom/filament/Generic PVA @MyToolChanger.json b/resources/profiles/Custom/filament/Generic PVA @MyToolChanger.json index ccb6d16c73..6fe168abcc 100644 --- a/resources/profiles/Custom/filament/Generic PVA @MyToolChanger.json +++ b/resources/profiles/Custom/filament/Generic PVA @MyToolChanger.json @@ -25,12 +25,6 @@ "filament_loading_speed_start": [ "50" ], - "filament_multitool_ramming": [ - "1" - ], - "filament_multitool_ramming_flow": [ - "40" - ], "filament_stamping_distance": [ "45" ], diff --git a/resources/profiles/Custom/machine/fdm_klipper_common.json b/resources/profiles/Custom/machine/fdm_klipper_common.json index 36f3fe13c6..a0ee0f1a47 100644 --- a/resources/profiles/Custom/machine/fdm_klipper_common.json +++ b/resources/profiles/Custom/machine/fdm_klipper_common.json @@ -116,7 +116,7 @@ "deretraction_speed": [ "30" ], - "z_hop_types": "Normal Lift", + "z_hop_types": "Slope Lift", "silent_mode": "0", "single_extruder_multi_material": "1", "change_filament_gcode": "", diff --git a/resources/profiles/Custom/machine/fdm_repetier_common.json b/resources/profiles/Custom/machine/fdm_repetier_common.json index 1171559086..b36b716e4e 100644 --- a/resources/profiles/Custom/machine/fdm_repetier_common.json +++ b/resources/profiles/Custom/machine/fdm_repetier_common.json @@ -118,7 +118,7 @@ "deretraction_speed": [ "30" ], - "z_hop_types": "Normal Lift", + "z_hop_types": "Slope Lift", "silent_mode": "0", "single_extruder_multi_material": "1", "change_filament_gcode": "", diff --git a/resources/profiles/Custom/machine/fdm_rrf_common.json b/resources/profiles/Custom/machine/fdm_rrf_common.json index 68708490a1..2fc9df9a3d 100644 --- a/resources/profiles/Custom/machine/fdm_rrf_common.json +++ b/resources/profiles/Custom/machine/fdm_rrf_common.json @@ -116,7 +116,7 @@ "deretraction_speed": [ "30" ], - "z_hop_types": "Normal Lift", + "z_hop_types": "Slope Lift", "silent_mode": "0", "single_extruder_multi_material": "1", "change_filament_gcode": "", diff --git a/resources/profiles/Custom/machine/fdm_toolchanger_common.json b/resources/profiles/Custom/machine/fdm_toolchanger_common.json index ff702d0034..55f1b2cadb 100644 --- a/resources/profiles/Custom/machine/fdm_toolchanger_common.json +++ b/resources/profiles/Custom/machine/fdm_toolchanger_common.json @@ -6,6 +6,7 @@ "instantiation": "false", "gcode_flavor": "klipper", "single_extruder_multi_material": "0", + "wait_for_temp_on_wipe_tower": "1", "default_filament_profile": [ "Generic PLA @MyToolChanger" ], @@ -172,11 +173,11 @@ "0.4" ], "z_hop_types": [ - "Normal Lift", - "Normal Lift", - "Normal Lift", - "Normal Lift", - "Normal Lift" + "Slope Lift", + "Slope Lift", + "Slope Lift", + "Slope Lift", + "Slope Lift" ], "purge_in_prime_tower": "0", "machine_pause_gcode": "M601", diff --git a/resources/profiles/OrcaFilamentLibrary.json b/resources/profiles/OrcaFilamentLibrary.json index cd9abd8b0d..9701c6eb0d 100644 --- a/resources/profiles/OrcaFilamentLibrary.json +++ b/resources/profiles/OrcaFilamentLibrary.json @@ -1,6 +1,6 @@ { "name": "OrcaFilamentLibrary", - "version": "02.04.00.03", + "version": "02.04.00.04", "force_update": "0", "description": "Orca Filament Library", "filament_list": [ diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PET-CF @base.json b/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PET-CF @base.json index 5a4e910502..c455832b9c 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PET-CF @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PET-CF @base.json @@ -36,6 +36,9 @@ "filament_max_volumetric_speed": [ "8" ], + "filament_multitool_ramming_flow": [ + "8" + ], "filament_type": [ "PET-CF" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PETG Basic @base.json b/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PETG Basic @base.json index 9117643990..755f78cf08 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PETG Basic @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PETG Basic @base.json @@ -39,6 +39,9 @@ "filament_max_volumetric_speed": [ "8" ], + "filament_multitool_ramming_flow": [ + "8" + ], "filament_vendor": [ "Bambu Lab" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PETG Translucent @base.json b/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PETG Translucent @base.json index 69cfb1dab7..0026f408f2 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PETG Translucent @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PETG Translucent @base.json @@ -39,6 +39,9 @@ "filament_max_volumetric_speed": [ "6" ], + "filament_multitool_ramming_flow": [ + "6" + ], "filament_vendor": [ "Bambu Lab" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PLA Aero @base.json b/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PLA Aero @base.json index 889822b02f..1f11ddcc54 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PLA Aero @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu PLA Aero @base.json @@ -21,6 +21,9 @@ "filament_max_volumetric_speed": [ "6" ], + "filament_multitool_ramming_flow": [ + "6" + ], "filament_type": [ "PLA-AERO" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu Support For PLA-PETG @base.json b/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu Support For PLA-PETG @base.json index 49fdcb1e1b..1dea20d081 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu Support For PLA-PETG @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu Support For PLA-PETG @base.json @@ -27,6 +27,9 @@ "filament_max_volumetric_speed": [ "6" ], + "filament_multitool_ramming_flow": [ + "6" + ], "filament_scarf_seam_type": [ "none" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu Support for ABS @base.json b/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu Support for ABS @base.json index 3fe47727e1..bf714a0352 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu Support for ABS @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Bambu/Bambu Support for ABS @base.json @@ -21,6 +21,9 @@ "filament_max_volumetric_speed": [ "6" ], + "filament_multitool_ramming_flow": [ + "6" + ], "filament_vendor": [ "Bambu Lab" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/COEX/COEX TPU 60A @base.json b/resources/profiles/OrcaFilamentLibrary/filament/COEX/COEX TPU 60A @base.json index 00834bb4a5..a4b0ebce09 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/COEX/COEX TPU 60A @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/COEX/COEX TPU 60A @base.json @@ -36,6 +36,9 @@ "filament_max_volumetric_speed": [ "1" ], + "filament_multitool_ramming_flow": [ + "1" + ], "filament_retraction_minimum_travel": [ "3" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas ASA @base.json b/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas ASA @base.json index d6ca0d695b..b4da81db72 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas ASA @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas ASA @base.json @@ -72,15 +72,6 @@ "fan_min_speed": [ "10" ], - "filament_cooling_final_speed": [ - "0" - ], - "filament_cooling_initial_speed": [ - "0" - ], - "filament_cooling_moves": [ - "0" - ], "filament_cost": [ "599" ], @@ -99,30 +90,12 @@ "filament_is_support": [ "0" ], - "filament_loading_speed": [ - "0" - ], - "filament_loading_speed_start": [ - "0" - ], "filament_long_retractions_when_cut": [ "nil" ], "filament_max_volumetric_speed": [ "15" ], - "filament_minimal_purge_on_wipe_tower": [ - "0" - ], - "filament_multitool_ramming": [ - "0" - ], - "filament_multitool_ramming_flow": [ - "10" - ], - "filament_multitool_ramming_volume": [ - "10" - ], "filament_notes": [ "" ], @@ -165,21 +138,6 @@ "filament_soluble": [ "0" ], - "filament_stamping_distance": [ - "0" - ], - "filament_stamping_loading_speed": [ - "0" - ], - "filament_toolchange_delay": [ - "0" - ], - "filament_unloading_speed": [ - "0" - ], - "filament_unloading_speed_start": [ - "0" - ], "filament_vendor": [ "Elas" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas PETG Basic @base.json b/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas PETG Basic @base.json index 478210bb7d..8b6db5d3ad 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas PETG Basic @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas PETG Basic @base.json @@ -42,15 +42,6 @@ "fan_min_speed": [ "20" ], - "filament_cooling_final_speed": [ - "0" - ], - "filament_cooling_initial_speed": [ - "0" - ], - "filament_cooling_moves": [ - "0" - ], "filament_cost": [ "445" ], @@ -69,30 +60,12 @@ "filament_is_support": [ "0" ], - "filament_loading_speed": [ - "0" - ], - "filament_loading_speed_start": [ - "0" - ], "filament_long_retractions_when_cut": [ "1" ], "filament_max_volumetric_speed": [ "18" ], - "filament_minimal_purge_on_wipe_tower": [ - "0" - ], - "filament_multitool_ramming": [ - "0" - ], - "filament_multitool_ramming_flow": [ - "10" - ], - "filament_multitool_ramming_volume": [ - "10" - ], "filament_notes": [ "" ], @@ -135,21 +108,6 @@ "filament_soluble": [ "0" ], - "filament_stamping_distance": [ - "0" - ], - "filament_stamping_loading_speed": [ - "0" - ], - "filament_toolchange_delay": [ - "0" - ], - "filament_unloading_speed": [ - "0" - ], - "filament_unloading_speed_start": [ - "0" - ], "filament_wipe": [ "nil" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas PLA Basic @base.json b/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas PLA Basic @base.json index abfa611aa3..d3f34beb80 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas PLA Basic @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas PLA Basic @base.json @@ -71,15 +71,6 @@ "fan_min_speed": [ "60" ], - "filament_cooling_final_speed": [ - "0" - ], - "filament_cooling_initial_speed": [ - "0" - ], - "filament_cooling_moves": [ - "0" - ], "filament_cost": [ "449.5" ], @@ -98,30 +89,12 @@ "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": [ "" ], @@ -164,21 +137,6 @@ "filament_soluble": [ "0" ], - "filament_stamping_distance": [ - "0" - ], - "filament_stamping_loading_speed": [ - "0" - ], - "filament_toolchange_delay": [ - "0" - ], - "filament_unloading_speed": [ - "0" - ], - "filament_unloading_speed_start": [ - "0" - ], "filament_vendor": [ "Elas" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas PLA Pro @base.json b/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas PLA Pro @base.json index 38313d1d55..41fd91f011 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas PLA Pro @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Elas/Elas PLA Pro @base.json @@ -71,15 +71,6 @@ "fan_min_speed": [ "100" ], - "filament_cooling_final_speed": [ - "0" - ], - "filament_cooling_initial_speed": [ - "0" - ], - "filament_cooling_moves": [ - "0" - ], "filament_cost": [ "500" ], @@ -98,30 +89,12 @@ "filament_is_support": [ "0" ], - "filament_loading_speed": [ - "0" - ], - "filament_loading_speed_start": [ - "0" - ], "filament_long_retractions_when_cut": [ "nil" ], "filament_max_volumetric_speed": [ "18" ], - "filament_minimal_purge_on_wipe_tower": [ - "0" - ], - "filament_multitool_ramming": [ - "0" - ], - "filament_multitool_ramming_flow": [ - "10" - ], - "filament_multitool_ramming_volume": [ - "10" - ], "filament_notes": [ "" ], @@ -164,21 +137,6 @@ "filament_soluble": [ "0" ], - "filament_stamping_distance": [ - "0" - ], - "filament_stamping_loading_speed": [ - "0" - ], - "filament_toolchange_delay": [ - "0" - ], - "filament_unloading_speed": [ - "0" - ], - "filament_unloading_speed_start": [ - "0" - ], "filament_vendor": [ "Elas" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Elegoo/Elegoo PAHT-CF @System.json b/resources/profiles/OrcaFilamentLibrary/filament/Elegoo/Elegoo PAHT-CF @System.json index d7dd19c086..7d22d28387 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Elegoo/Elegoo PAHT-CF @System.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Elegoo/Elegoo PAHT-CF @System.json @@ -24,6 +24,9 @@ "filament_max_volumetric_speed": [ "6" ], + "filament_multitool_ramming_flow": [ + "6" + ], "nozzle_temperature": [ "290" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Elegoo/Elegoo PETG @base.json b/resources/profiles/OrcaFilamentLibrary/filament/Elegoo/Elegoo PETG @base.json index d6cd360eba..997f38ed4d 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Elegoo/Elegoo PETG @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Elegoo/Elegoo PETG @base.json @@ -35,6 +35,9 @@ "filament_max_volumetric_speed": [ "8" ], + "filament_multitool_ramming_flow": [ + "8" + ], "filament_vendor": [ "Elegoo" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Elegoo/Elegoo PLA Wood @System.json b/resources/profiles/OrcaFilamentLibrary/filament/Elegoo/Elegoo PLA Wood @System.json index abae441db5..3d6c95ed00 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Elegoo/Elegoo PLA Wood @System.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Elegoo/Elegoo PLA Wood @System.json @@ -12,6 +12,9 @@ "filament_max_volumetric_speed": [ "10" ], + "filament_multitool_ramming_flow": [ + "10" + ], "nozzle_temperature": [ "220" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Eolas Prints/Eolas Prints PLA Neon @System.json b/resources/profiles/OrcaFilamentLibrary/filament/Eolas Prints/Eolas Prints PLA Neon @System.json index b40ce2310b..dff734c96d 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Eolas Prints/Eolas Prints PLA Neon @System.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Eolas Prints/Eolas Prints PLA Neon @System.json @@ -44,5 +44,8 @@ ], "filament_max_volumetric_speed": [ "10" + ], + "filament_multitool_ramming_flow": [ + "10" ] } diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Eolas Prints/Eolas Prints PLA Silk @System.json b/resources/profiles/OrcaFilamentLibrary/filament/Eolas Prints/Eolas Prints PLA Silk @System.json index 843cf72fc5..1c3184da11 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Eolas Prints/Eolas Prints PLA Silk @System.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Eolas Prints/Eolas Prints PLA Silk @System.json @@ -44,5 +44,8 @@ ], "filament_max_volumetric_speed": [ "8" + ], + "filament_multitool_ramming_flow": [ + "8" ] } diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Generic PA-CF @System.json b/resources/profiles/OrcaFilamentLibrary/filament/Generic PA-CF @System.json index f7b9df437a..cf01ddf65b 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Generic PA-CF @System.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Generic PA-CF @System.json @@ -10,5 +10,8 @@ "filament_type": [ "PA-CF" ], + "filament_multitool_ramming_flow": [ + "8" + ], "compatible_printers": [] } diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Generic PETG HF @System.json b/resources/profiles/OrcaFilamentLibrary/filament/Generic PETG HF @System.json index e402cdf775..25cf20c304 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Generic PETG HF @System.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Generic PETG HF @System.json @@ -8,5 +8,8 @@ "filament_max_volumetric_speed": [ "20" ], + "filament_multitool_ramming_flow": [ + "20" + ], "compatible_printers": [] } diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Generic PETG-CF @System.json b/resources/profiles/OrcaFilamentLibrary/filament/Generic PETG-CF @System.json index 5ee99ffed9..30884cf5a0 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Generic PETG-CF @System.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Generic PETG-CF @System.json @@ -17,6 +17,9 @@ "filament_max_volumetric_speed": [ "11.5" ], + "filament_multitool_ramming_flow": [ + "13" + ], "overhang_fan_speed": [ "100" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Generic PLA High Speed @System.json b/resources/profiles/OrcaFilamentLibrary/filament/Generic PLA High Speed @System.json index 041ff59c44..1880ca2b21 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Generic PLA High Speed @System.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Generic PLA High Speed @System.json @@ -12,6 +12,9 @@ "filament_max_volumetric_speed": [ "18" ], + "filament_multitool_ramming_flow": [ + "25" + ], "slow_down_layer_time": [ "4" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Generic PLA Matte @System.json b/resources/profiles/OrcaFilamentLibrary/filament/Generic PLA Matte @System.json index d3a6d4813c..39c71d0d62 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Generic PLA Matte @System.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Generic PLA Matte @System.json @@ -8,6 +8,9 @@ "filament_max_volumetric_speed": [ "11" ], + "filament_multitool_ramming_flow": [ + "11" + ], "filament_retraction_length": [ "0.8" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Generic PP-CF @System.json b/resources/profiles/OrcaFilamentLibrary/filament/Generic PP-CF @System.json index 65420e9dae..a7c1bbff00 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Generic PP-CF @System.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Generic PP-CF @System.json @@ -15,6 +15,9 @@ "filament_max_volumetric_speed": [ "6" ], + "filament_multitool_ramming_flow": [ + "6" + ], "filament_type": [ "PP-CF" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Generic PP-GF @System.json b/resources/profiles/OrcaFilamentLibrary/filament/Generic PP-GF @System.json index 931ee4b7b3..cf9ea7ace2 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Generic PP-GF @System.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Generic PP-GF @System.json @@ -15,6 +15,9 @@ "filament_max_volumetric_speed": [ "6" ], + "filament_multitool_ramming_flow": [ + "6" + ], "filament_type": [ "PP-GF" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Overture/Overture Air PLA @base.json b/resources/profiles/OrcaFilamentLibrary/filament/Overture/Overture Air PLA @base.json index 39e351a24c..98d390e9b8 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Overture/Overture Air PLA @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Overture/Overture Air PLA @base.json @@ -17,6 +17,9 @@ "filament_max_volumetric_speed": [ "8" ], + "filament_multitool_ramming_flow": [ + "8" + ], "filament_vendor": [ "Overture" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/Valment/Valment PLA Silk @base.json b/resources/profiles/OrcaFilamentLibrary/filament/Valment/Valment PLA Silk @base.json index d873590f08..258f80fb15 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/Valment/Valment PLA Silk @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/Valment/Valment PLA Silk @base.json @@ -23,6 +23,9 @@ "filament_max_volumetric_speed": [ "7.5" ], + "filament_multitool_ramming_flow": [ + "7.5" + ], "filament_vendor": [ "Valment" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_abs.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_abs.json index 6d9d015c11..dea3f03264 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_abs.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_abs.json @@ -43,6 +43,12 @@ "filament_max_volumetric_speed": [ "12" ], + "filament_multitool_ramming_flow": [ + "15" + ], + "filament_multitool_ramming_volume": [ + "10" + ], "filament_type": [ "ABS" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_asa.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_asa.json index 922a5eaa7a..09a29ce792 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_asa.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_asa.json @@ -43,6 +43,12 @@ "filament_max_volumetric_speed": [ "12" ], + "filament_multitool_ramming_flow": [ + "12" + ], + "filament_multitool_ramming_volume": [ + "10" + ], "filament_type": [ "ASA" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_bvoh.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_bvoh.json index d37476f458..cd15600a52 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_bvoh.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_bvoh.json @@ -41,6 +41,15 @@ "filament_max_volumetric_speed": [ "8" ], + "filament_multitool_ramming": [ + "0" + ], + "filament_multitool_ramming_flow": [ + "6" + ], + "filament_multitool_ramming_volume": [ + "0.1" + ], "filament_type": [ "BVOH" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_common.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_common.json index ce95ca7c52..3ff7e805ae 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_common.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_common.json @@ -66,6 +66,12 @@ "filament_minimal_purge_on_wipe_tower": [ "15" ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "5" + ], "filament_retract_before_wipe": [ "nil" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_cope.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_cope.json index 80ffd173de..798f560e01 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_cope.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_cope.json @@ -41,6 +41,9 @@ "filament_max_volumetric_speed": [ "16" ], + "filament_multitool_ramming_flow": [ + "16" + ], "filament_scarf_seam_type": [ "none" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_eva.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_eva.json index bf1ff86af1..40498a05aa 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_eva.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_eva.json @@ -8,6 +8,9 @@ "filament_type": [ "EVA" ], + "filament_multitool_ramming_flow": [ + "12" + ], "supertack_plate_temp": [ "0" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_hips.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_hips.json index beaebbd0e7..f67709b4b2 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_hips.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_hips.json @@ -41,6 +41,9 @@ "filament_max_volumetric_speed": [ "8" ], + "filament_multitool_ramming_flow": [ + "8" + ], "filament_type": [ "HIPS" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pa.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pa.json index c2e4cf86df..185af32de7 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pa.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pa.json @@ -44,6 +44,9 @@ "filament_max_volumetric_speed": [ "8" ], + "filament_multitool_ramming_flow": [ + "12" + ], "filament_type": [ "PA" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_paht.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_paht.json index 058469ff71..2a1ca6d510 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_paht.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_paht.json @@ -7,6 +7,9 @@ "filament_max_volumetric_speed": [ "12" ], + "filament_multitool_ramming_flow": [ + "12" + ], "filament_type": [ "PAHT" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pc.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pc.json index 0f550063ad..d8fb7d00ae 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pc.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pc.json @@ -86,6 +86,9 @@ "filament_max_volumetric_speed": [ "12" ], + "filament_multitool_ramming_flow": [ + "16" + ], "filament_flow_ratio": [ "0.94" ] diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pctg.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pctg.json index 8ca7e39994..e656fb7715 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pctg.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pctg.json @@ -26,6 +26,9 @@ "filament_max_volumetric_speed": [ "12" ], + "filament_multitool_ramming_flow": [ + "10" + ], "filament_type": [ "PCTG" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pe.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pe.json index beb533d07f..a47543334b 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pe.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pe.json @@ -38,6 +38,9 @@ "filament_max_volumetric_speed": [ "12" ], + "filament_multitool_ramming_flow": [ + "12" + ], "filament_type": [ "PE" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pet.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pet.json index eabb12c708..8b3fef2f2b 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pet.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pet.json @@ -26,6 +26,9 @@ "filament_max_volumetric_speed": [ "10" ], + "filament_multitool_ramming_flow": [ + "15" + ], "filament_type": [ "PETG" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pha.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pha.json index f6ef3ffc0c..7719c6563d 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pha.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pha.json @@ -38,6 +38,9 @@ "filament_max_volumetric_speed": [ "6" ], + "filament_multitool_ramming_flow": [ + "6" + ], "filament_type": [ "PHA" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pla.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pla.json index ae82d44129..21b7c44365 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pla.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pla.json @@ -38,6 +38,9 @@ "filament_max_volumetric_speed": [ "12" ], + "filament_multitool_ramming_flow": [ + "20" + ], "filament_scarf_seam_type": [ "none" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pla_silk.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pla_silk.json index 3680a85602..a5fd601060 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pla_silk.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pla_silk.json @@ -9,6 +9,9 @@ "filament_flow_ratio": [ "0.98" ], + "filament_multitool_ramming_flow": [ + "10" + ], "slow_down_layer_time": [ "8" ] diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pp.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pp.json index ec9405ef9a..4df7753132 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pp.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pp.json @@ -38,6 +38,9 @@ "filament_max_volumetric_speed": [ "12" ], + "filament_multitool_ramming_flow": [ + "12" + ], "filament_type": [ "PP" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_ppa.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_ppa.json index 3eac71bc69..c250e588b0 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_ppa.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_ppa.json @@ -47,6 +47,9 @@ "filament_max_volumetric_speed": [ "8" ], + "filament_multitool_ramming_flow": [ + "8" + ], "filament_type": [ "PPA-CF" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pps.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pps.json index a6a95a804e..49e0bddefd 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pps.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pps.json @@ -43,6 +43,9 @@ "filament_max_volumetric_speed": [ "4" ], + "filament_multitool_ramming_flow": [ + "4" + ], "filament_type": [ "PPS" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pva.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pva.json index 0109726b0d..4bb30d7e11 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pva.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_pva.json @@ -40,6 +40,15 @@ "filament_max_volumetric_speed": [ "12" ], + "filament_multitool_ramming": [ + "0" + ], + "filament_multitool_ramming_flow": [ + "6" + ], + "filament_multitool_ramming_volume": [ + "0.1" + ], "filament_soluble": [ "1" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_sbs.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_sbs.json index 96626d808d..9bc4d5ce36 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_sbs.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_sbs.json @@ -11,6 +11,9 @@ "filament_max_volumetric_speed": [ "12" ], + "filament_multitool_ramming_flow": [ + "12" + ], "filament_type": [ "SBS" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_tpu.json b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_tpu.json index 30d9415ad3..d6fb38a6ba 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_tpu.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/base/fdm_filament_tpu.json @@ -43,6 +43,15 @@ "filament_max_volumetric_speed": [ "3.2" ], + "filament_multitool_ramming": [ + "0" + ], + "filament_multitool_ramming_flow": [ + "3.2" + ], + "filament_multitool_ramming_volume": [ + "0.1" + ], "filament_retraction_length": [ "0.4" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/eSUN/eSUN PLA-Marble @base.json b/resources/profiles/OrcaFilamentLibrary/filament/eSUN/eSUN PLA-Marble @base.json index 40c314585c..cbd4f84ed4 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/eSUN/eSUN PLA-Marble @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/eSUN/eSUN PLA-Marble @base.json @@ -17,6 +17,9 @@ "filament_max_volumetric_speed": [ "8" ], + "filament_multitool_ramming_flow": [ + "8" + ], "filament_vendor": [ "eSUN" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/eSUN/eSUN PLA-Matte @base.json b/resources/profiles/OrcaFilamentLibrary/filament/eSUN/eSUN PLA-Matte @base.json index 85c6049935..8d22168408 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/eSUN/eSUN PLA-Matte @base.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/eSUN/eSUN PLA-Matte @base.json @@ -17,6 +17,9 @@ "filament_max_volumetric_speed": [ "8" ], + "filament_multitool_ramming_flow": [ + "8" + ], "filament_vendor": [ "eSUN" ], diff --git a/resources/profiles/OrcaFilamentLibrary/filament/eSUN/eSUN ePLA-LW @System.json b/resources/profiles/OrcaFilamentLibrary/filament/eSUN/eSUN ePLA-LW @System.json index 138a388419..732eb3fd5b 100644 --- a/resources/profiles/OrcaFilamentLibrary/filament/eSUN/eSUN ePLA-LW @System.json +++ b/resources/profiles/OrcaFilamentLibrary/filament/eSUN/eSUN ePLA-LW @System.json @@ -21,6 +21,9 @@ "filament_max_volumetric_speed": [ "6" ], + "filament_multitool_ramming_flow": [ + "6" + ], "filament_vendor": [ "eSUN" ], diff --git a/resources/profiles/Qidi.json b/resources/profiles/Qidi.json index 9e7a290f96..08a2d6a230 100644 --- a/resources/profiles/Qidi.json +++ b/resources/profiles/Qidi.json @@ -1,6 +1,6 @@ { "name": "Qidi", - "version": "02.04.00.08", + "version": "02.04.00.10", "force_update": "0", "description": "Qidi configurations", "machine_model_list": [ @@ -47,6 +47,10 @@ { "name": "Qidi X-Smart 3", "sub_path": "machine/Qidi X-Smart 3.json" + }, + { + "name": "Qidi X-Plus 5", + "sub_path": "machine/Qidi X-Plus 5.json" } ], "process_list": [ @@ -885,6 +889,70 @@ { "name": "0.56mm Standard @Qidi XSmart3 0.8 nozzle", "sub_path": "process/0.56mm Standard @Qidi XSmart3 0.8 nozzle.json" + }, + { + "name": "0.08mm High Quality @X-Plus 5", + "sub_path": "process/0.08mm High Quality @X-Plus 5.json" + }, + { + "name": "0.12mm High Quality @X-Plus 5", + "sub_path": "process/0.12mm High Quality @X-Plus 5.json" + }, + { + "name": "0.16mm High Quality @X-Plus 5", + "sub_path": "process/0.16mm High Quality @X-Plus 5.json" + }, + { + "name": "0.16mm Standard @X-Plus 5", + "sub_path": "process/0.16mm Standard @X-Plus 5.json" + }, + { + "name": "0.20mm High Quality @X-Plus 5", + "sub_path": "process/0.20mm High Quality @X-Plus 5.json" + }, + { + "name": "0.20mm Standard @X-Plus 5", + "sub_path": "process/0.20mm Standard @X-Plus 5.json" + }, + { + "name": "0.24mm Standard @X-Plus 5", + "sub_path": "process/0.24mm Standard @X-Plus 5.json" + }, + { + "name": "0.08mm High Quality @X-Plus 5 0.2 nozzle", + "sub_path": "process/0.08mm High Quality @X-Plus 5 0.2 nozzle.json" + }, + { + "name": "0.10mm Standard @X-Plus 5 0.2 nozzle", + "sub_path": "process/0.10mm Standard @X-Plus 5 0.2 nozzle.json" + }, + { + "name": "0.12mm Balanced Quality @X-Plus 5 0.2 nozzle", + "sub_path": "process/0.12mm Balanced Quality @X-Plus 5 0.2 nozzle.json" + }, + { + "name": "0.18mm Balanced Quality @X-Plus 5 0.6 nozzle", + "sub_path": "process/0.18mm Balanced Quality @X-Plus 5 0.6 nozzle.json" + }, + { + "name": "0.24mm Balanced Quality @X-Plus 5 0.6 nozzle", + "sub_path": "process/0.24mm Balanced Quality @X-Plus 5 0.6 nozzle.json" + }, + { + "name": "0.30mm Standard @X-Plus 5 0.6 nozzle", + "sub_path": "process/0.30mm Standard @X-Plus 5 0.6 nozzle.json" + }, + { + "name": "0.24mm Balanced Quality @X-Plus 5 0.8 nozzle", + "sub_path": "process/0.24mm Balanced Quality @X-Plus 5 0.8 nozzle.json" + }, + { + "name": "0.32mm Balanced Quality @X-Plus 5 0.8 nozzle", + "sub_path": "process/0.32mm Balanced Quality @X-Plus 5 0.8 nozzle.json" + }, + { + "name": "0.40mm Standard @X-Plus 5 0.8 nozzle", + "sub_path": "process/0.40mm Standard @X-Plus 5 0.8 nozzle.json" } ], "filament_list": [ @@ -6035,6 +6103,998 @@ { "name": "Qidi Generic PLA High Speed @Qidi X-Plus 4 0.8 nozzle", "sub_path": "filament/Qidi Generic PLA High Speed @Qidi X-Plus 4 0.8 nozzle.json" + }, + { + "name": "fdm_filament_x5_common", + "sub_path": "filament/X5/fdm_filament_x5_common.json" + }, + { + "name": "Generic ABS@X-Plus 5-Series", + "sub_path": "filament/X5/Generic ABS @X-Plus 5.json" + }, + { + "name": "QIDI ASA@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI ASA @X-Plus 5.json" + }, + { + "name": "Generic PETG@X-Plus 5-Series", + "sub_path": "filament/X5/Generic PETG @X-Plus 5.json" + }, + { + "name": "Generic PLA Silk@X-Plus 5-Series", + "sub_path": "filament/X5/Generic PLA Silk @X-Plus 5.json" + }, + { + "name": "Generic PLA@X-Plus 5-Series", + "sub_path": "filament/X5/Generic PLA @X-Plus 5.json" + }, + { + "name": "Generic PLA+@X-Plus 5-Series", + "sub_path": "filament/X5/Generic PLA+ @X-Plus 5.json" + }, + { + "name": "PolyLite PLA@X-Plus 5-Series", + "sub_path": "filament/X5/PolyLite PLA @X-Plus 5.json" + }, + { + "name": "Polymaker PLA-HT@X-Plus 5-Series", + "sub_path": "filament/X5/Polymaker PLA-HT @X-Plus 5.json" + }, + { + "name": "QIDI PLA-CF@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PLA-CF @X-Plus 5.json" + }, + { + "name": "QIDI PLA-CF @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PLA-CF @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PLA-CF @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PLA-CF @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PLA-CF @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PLA-CF @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI ABS Rapido@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI ABS Rapido @X-Plus 5.json" + }, + { + "name": "QIDI ABS Rapido @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "QIDI ABS Rapido @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI ABS Rapido @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI ABS Rapido @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI ABS Rapido Metal@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI ABS Rapido Metal @X-Plus 5.json" + }, + { + "name": "QIDI ABS Rapido Metal @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "QIDI ABS Rapido Metal @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI ABS Rapido Metal @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI ABS Rapido Metal @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI ABS Odorless@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI ABS Odorless @X-Plus 5.json" + }, + { + "name": "QIDI ABS Odorless @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "QIDI ABS Odorless @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI ABS Odorless @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI ABS Odorless @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PLA Rapido@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PLA Rapido @X-Plus 5.json" + }, + { + "name": "QIDI PLA Rapido @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "QIDI PLA Rapido @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PLA Rapido @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PLA Rapido @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PLA Rapido Matte@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PLA Rapido Matte @X-Plus 5.json" + }, + { + "name": "QIDI PLA Rapido Matte @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "QIDI PLA Rapido Matte @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PLA Rapido Matte @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PLA Rapido Matte @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PLA Silk@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PLA Silk @X-Plus 5.json" + }, + { + "name": "QIDI PLA Silk @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PLA Silk @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PLA Silk @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PLA Silk @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PLA Rapido Metal@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PLA Rapido Metal @X-Plus 5.json" + }, + { + "name": "QIDI PLA Rapido Metal @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "QIDI PLA Rapido Metal @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PLA Rapido Metal @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PLA Rapido Metal @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PETG Tough@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PETG Tough @X-Plus 5.json" + }, + { + "name": "QIDI PETG Tough @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "QIDI PETG Tough @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PETG Tough @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PETG Tough @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PET-CF@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PET-CF @X-Plus 5.json" + }, + { + "name": "QIDI PET-CF @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PET-CF @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PET-CF @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PET-CF @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PET-CF @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PET-CF @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PA12-CF@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PA12-CF @X-Plus 5.json" + }, + { + "name": "QIDI PA12-CF @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PA12-CF @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PA12-CF @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PA12-CF @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PA12-CF @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PA12-CF @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PA6-CF@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PA6-CF @X-Plus 5.json" + }, + { + "name": "QIDI PA6-CF @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PA6-CF @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PA6-CF @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PA6-CF @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PA6-CF @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PA6-CF @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PAHT-CF@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PAHT-CF @X-Plus 5.json" + }, + { + "name": "QIDI PAHT-CF @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PAHT-CF @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PAHT-CF @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PAHT-CF @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PAHT-CF @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PAHT-CF @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PPS-CF@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PPS-CF @X-Plus 5.json" + }, + { + "name": "QIDI PPS-CF @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PPS-CF @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PPS-CF @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PPS-CF @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PPS-CF @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PPS-CF @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI ABS-GF@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI ABS-GF @X-Plus 5.json" + }, + { + "name": "QIDI ABS-GF @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI ABS-GF @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI ABS-GF @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI ABS-GF @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI ABS-GF @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI ABS-GF @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI UltraPA@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI UltraPA @X-Plus 5.json" + }, + { + "name": "QIDI UltraPA @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI UltraPA @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI UltraPA @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI UltraPA @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI UltraPA @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI UltraPA @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "Generic TPU 95A@X-Plus 5-Series", + "sub_path": "filament/X5/Generic TPU 95A @X-Plus 5.json" + }, + { + "name": "QIDI PC/ABS-FR@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PC-ABS-FR @X-Plus 5.json" + }, + { + "name": "QIDI PC/ABS-FR @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PC-ABS-FR @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PC/ABS-FR @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PC-ABS-FR @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PC/ABS-FR @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PC-ABS-FR @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI ASA-Aero@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI ASA-Aero @X-Plus 5.json" + }, + { + "name": "QIDI ASA-Aero @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI ASA-Aero @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "Generic ABS @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/Generic ABS @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "Generic ABS @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/Generic ABS @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "Generic ABS @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/Generic ABS @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "Generic ABS @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/Generic ABS @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI ASA @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/QIDI ASA @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "QIDI ASA @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI ASA @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI ASA @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI ASA @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI ASA @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI ASA @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "Generic PETG @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/Generic PETG @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "Generic PETG @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/Generic PETG @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "Generic PETG @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/Generic PETG @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "Generic PETG @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/Generic PETG @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "Generic PLA @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/Generic PLA @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "Generic PLA @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/Generic PLA @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "Generic PLA @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/Generic PLA @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "Generic PLA @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/Generic PLA @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "Generic PLA+ @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/Generic PLA+ @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "Generic PLA+ @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/Generic PLA+ @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "Generic PLA+ @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/Generic PLA+ @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "Generic PLA+ @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/Generic PLA+ @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "Generic PLA Silk @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/Generic PLA Silk @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "Generic PLA Silk @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/Generic PLA Silk @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "Generic TPU 95A @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/Generic TPU 95A @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "Generic TPU 95A @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/Generic TPU 95A @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "Generic TPU 95A @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/Generic TPU 95A @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI TPU 95A-HF@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI TPU 95A-HF @X-Plus 5.json" + }, + { + "name": "QIDI TPU 95A-HF @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI TPU 95A-HF @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI TPU 95A-HF @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI TPU 95A-HF @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI TPU 95A-HF @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI TPU 95A-HF @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "PolyLite PLA @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/PolyLite PLA @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "PolyLite PLA @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/PolyLite PLA @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "PolyLite PLA @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/PolyLite PLA @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "PolyLite PLA @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/PolyLite PLA @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "Polymaker PLA-HT @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "Polymaker PLA-HT @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "Polymaker PLA-HT @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "Polymaker PLA-HT @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "PolyLite ABS@X-Plus 5-Series", + "sub_path": "filament/X5/PolyLite ABS @X-Plus 5.json" + }, + { + "name": "PolyLite ABS @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/PolyLite ABS @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "PolyLite ABS @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/PolyLite ABS @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "PolyLite ABS @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/PolyLite ABS @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "PolyLite ABS @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/PolyLite ABS @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "Overture PLA@X-Plus 5-Series", + "sub_path": "filament/X5/Overture PLA @X-Plus 5.json" + }, + { + "name": "Overture PLA @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/Overture PLA @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "Overture PLA @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/Overture PLA @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "Overture PLA @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/Overture PLA @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "Overture PLA @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/Overture PLA @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "Overture ABS@X-Plus 5-Series", + "sub_path": "filament/X5/Overture ABS @X-Plus 5.json" + }, + { + "name": "Overture ABS @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/Overture ABS @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "Overture ABS @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/Overture ABS @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "Overture ABS @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/Overture ABS @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "Overture ABS @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/Overture ABS @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "Bambu PLA@X-Plus 5-Series", + "sub_path": "filament/X5/Bambu PLA @X-Plus 5.json" + }, + { + "name": "Bambu PLA @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/Bambu PLA @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "Bambu PLA @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/Bambu PLA @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "Bambu PLA @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/Bambu PLA @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "Bambu PLA @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/Bambu PLA @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "Bambu ABS@X-Plus 5-Series", + "sub_path": "filament/X5/Bambu ABS @X-Plus 5.json" + }, + { + "name": "Bambu ABS @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/Bambu ABS @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "Bambu ABS @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/Bambu ABS @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "Bambu ABS @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/Bambu ABS @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "Bambu ABS @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/Bambu ABS @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "Bambu PETG@X-Plus 5-Series", + "sub_path": "filament/X5/Bambu PETG @X-Plus 5.json" + }, + { + "name": "Bambu PETG @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/Bambu PETG @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "Bambu PETG @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/Bambu PETG @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "Bambu PETG @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/Bambu PETG @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "Bambu PETG @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/Bambu PETG @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "HATCHBOX PLA@X-Plus 5-Series", + "sub_path": "filament/X5/HATCHBOX PLA @X-Plus 5.json" + }, + { + "name": "HATCHBOX PLA @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "HATCHBOX PLA @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "HATCHBOX PLA @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "HATCHBOX PLA @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "HATCHBOX ABS@X-Plus 5-Series", + "sub_path": "filament/X5/HATCHBOX ABS @X-Plus 5.json" + }, + { + "name": "HATCHBOX ABS @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "HATCHBOX ABS @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "HATCHBOX ABS @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "HATCHBOX ABS @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "HATCHBOX PETG@X-Plus 5-Series", + "sub_path": "filament/X5/HATCHBOX PETG @X-Plus 5.json" + }, + { + "name": "HATCHBOX PETG @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "HATCHBOX PETG @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "HATCHBOX PETG @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "HATCHBOX PETG @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PAHT-GF@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PAHT-GF @X-Plus 5.json" + }, + { + "name": "QIDI PAHT-GF @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PAHT-GF @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PAHT-GF @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PAHT-GF @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PAHT-GF @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PAHT-GF @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PET-GF@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PET-GF @X-Plus 5.json" + }, + { + "name": "QIDI PET-GF @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PET-GF @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PET-GF @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PET-GF @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PET-GF @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PET-GF @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI UltraPA-CF25@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI UltraPA-CF25 @X-Plus 5.json" + }, + { + "name": "QIDI UltraPA-CF25 @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI UltraPA-CF25 @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI UltraPA-CF25 @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI UltraPA-CF25 @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI UltraPA-CF25 @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI UltraPA-CF25 @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI WOOD Rapido@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI WOOD Rapido @X-Plus 5.json" + }, + { + "name": "QIDI WOOD Rapido @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI WOOD Rapido @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI WOOD Rapido @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI WOOD Rapido @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI WOOD Rapido @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI WOOD Rapido @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "Generic PC@X-Plus 5-Series", + "sub_path": "filament/X5/Generic PC @X-Plus 5.json" + }, + { + "name": "Generic PC @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/Generic PC @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "Generic PC @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/Generic PC @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "Generic PC @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/Generic PC @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "Generic PC @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/Generic PC @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI TPU-Aero@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI TPU-Aero @X-Plus 5.json" + }, + { + "name": "QIDI TPU-Aero @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI TPU-Aero @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI TPU-Aero @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI TPU-Aero @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI Support For PET/PA@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI Support For PET-PA @X-Plus 5.json" + }, + { + "name": "QIDI Support For PET/PA @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI Support For PET-PA @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI Support For PET/PA @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI Support For PET-PA @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI Support For PET/PA @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI Support For PET-PA @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI Support For PAHT@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI Support For PAHT @X-Plus 5.json" + }, + { + "name": "QIDI Support For PAHT @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI Support For PAHT @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI Support For PAHT @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI Support For PAHT @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI Support For PAHT @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI Support For PAHT @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PLA Basic@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PLA Basic @X-Plus 5.json" + }, + { + "name": "QIDI PLA Basic @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "QIDI PLA Basic @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PLA Basic @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PLA Basic @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PLA Matte Basic@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PLA Matte Basic @X-Plus 5.json" + }, + { + "name": "QIDI PLA Matte Basic @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "QIDI PLA Matte Basic @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PLA Matte Basic @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PLA Matte Basic @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PETG Rapido@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PETG Rapido @X-Plus 5.json" + }, + { + "name": "QIDI PETG Rapido @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "QIDI PETG Rapido @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PETG Rapido @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PETG Rapido @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PETG Basic@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PETG Basic @X-Plus 5.json" + }, + { + "name": "QIDI PETG Basic @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "QIDI PETG Basic @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PETG Basic @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PETG Basic @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PETG Translucent@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PETG Translucent @X-Plus 5.json" + }, + { + "name": "QIDI PETG Translucent @Qidi X-Plus 5 0.2 nozzle", + "sub_path": "filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.2 nozzle.json" + }, + { + "name": "QIDI PETG Translucent @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PETG Translucent @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PETG Translucent @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PETG-CF@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PETG-CF @X-Plus 5.json" + }, + { + "name": "QIDI PETG-CF @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PETG-CF @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PETG-CF @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PETG-CF @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PETG-CF @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PETG-CF @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PETG-GF@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PETG-GF @X-Plus 5.json" + }, + { + "name": "QIDI PETG-GF @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PETG-GF @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PETG-GF @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PETG-GF @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PETG-GF @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PETG-GF @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PPS-GF@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PPS-GF @X-Plus 5.json" + }, + { + "name": "QIDI PPS-GF @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PPS-GF @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PPS-GF @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PPS-GF @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI PPS-GF @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI PPS-GF @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI PEBA 95A@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI PEBA 95A @X-Plus 5.json" + }, + { + "name": "QIDI PEBA 95A @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI PEBA 95A @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI PEBA 95A @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI PEBA 95A @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI ASA-CF@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI ASA-CF @X-Plus 5.json" + }, + { + "name": "QIDI ASA-CF @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI ASA-CF @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI ASA-CF @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI ASA-CF @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI ASA-CF @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI ASA-CF @Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "QIDI TPU-GF@X-Plus 5-Series", + "sub_path": "filament/X5/QIDI TPU-GF @X-Plus 5.json" + }, + { + "name": "QIDI TPU-GF @Qidi X-Plus 5 0.4 nozzle", + "sub_path": "filament/X5/QIDI TPU-GF @Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "QIDI TPU-GF @Qidi X-Plus 5 0.6 nozzle", + "sub_path": "filament/X5/QIDI TPU-GF @Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "QIDI TPU-GF @Qidi X-Plus 5 0.8 nozzle", + "sub_path": "filament/X5/QIDI TPU-GF @Qidi X-Plus 5 0.8 nozzle.json" } ], "machine_list": [ @@ -6197,6 +7257,22 @@ { "name": "Qidi Q2C 0.8 nozzle", "sub_path": "machine/Qidi Q2C 0.8 nozzle.json" + }, + { + "name": "Qidi X-Plus 5 0.4 nozzle", + "sub_path": "machine/Qidi X-Plus 5 0.4 nozzle.json" + }, + { + "name": "Qidi X-Plus 5 0.6 nozzle", + "sub_path": "machine/Qidi X-Plus 5 0.6 nozzle.json" + }, + { + "name": "Qidi X-Plus 5 0.8 nozzle", + "sub_path": "machine/Qidi X-Plus 5 0.8 nozzle.json" + }, + { + "name": "Qidi X-Plus 5 0.2 nozzle", + "sub_path": "machine/Qidi X-Plus 5 0.2 nozzle.json" } ] } diff --git a/resources/profiles/Qidi/Qidi X-Plus 5_cover.png b/resources/profiles/Qidi/Qidi X-Plus 5_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..06f5c5858df019a00fa26f45fa34f8bf8e618064 GIT binary patch literal 33441 zcmbqa)3Pwku3WZl+qP}nwr%5Ewr$(CZQHhW{{0N+BGZ+*OC?iDb!Q?JedY0O=s1=?nk>jr>0Y1jx+B`0oh@ z!WGZ$are#YqH;HF;|+`ffN{_OjD#Wri6CehY_l1+P&jb}Leoh@O#@n1^gWFj$3%i( zX0lNT>Nmf*o-z{!U7=C9lvcSB254Krp?(G+9koeb{_S~JRd>q!&5UdAF=zT~_o{+u z0WQHvH@~cMw@Z3=I*GjRDTg!yE;jgRpM&H71s-q2^LKGYKe=}wxhHLOdOi*);)c$R zlK%G-_V_(bj;0x<9mt=2w({=sGUQ7oF*7yK$4PPQS?uaWpk8H@Zkrh{S4k7M3+dQP&9Yv{2ja2zH#YRL zZe`oO>#}b0cQR!@v^#J8z@A8S_<3?<5#-wJInkY#Jl#D_IZP~v*6??7WX(-oGiM8Z zAL@T=v%GKo9>jGFX?uQ0+o50h?PoX6_PO3y>kmctcXFlZb-H`)KHtj;*!JD;hod>} zyB$CGL-2Qgm&$pU7jNecX<>GAxj*NdMRB=&-5nce&TUWPRU*`u$%1DWN#ybimkGqp zO-&2i+uN4!K?@em-90UyXGi#6JTh*jE~ZajUCvKtSxOMTmuX*iUUy%6f4^jJz8+UK zZKc?2b?k3@?)pp7S!V8BxUOAE-GgmDHy37Xg#4vVsBjQ}jf=CGcVTa zpy=iW`EJWn`YQRre-)K$$rJvpJ>1q&V| zXS8SLCruWcvM0ShdEcxx)i{q|_dmqKnK`-_A0-bOe8%<6vwdURrDSBGv(&1SZ@SvrQ?}7A$KwkZudA=e(;3X{_S@}lNAD5H*w}0KIvRSME|#9j zyWJiqk6Ulsu6rN$-QSBJ;I|z|pE20%wcQ@S->+Y{z1~m8_+RVC;eO}gL_gdduOT>p zLwjG~d+*=&yf612EM#c4>0TEew;-eW+a24UJn4+^vUx4I_|+dK6|=ZI;{jq93Z52d zvDFdBT&p2W8r{=pvB!Cjo_zGub>GLv$)It0b3o&7DSb_;C(iC}txru&403MHTZO+z zXCrdCoHK9cw(K)PTqn+tFS>Z+)f2Xi0(-+Vw@HAiI~Kilx%d>rrFj=3bBi<1#v zae5%#Q$iK@l~u$i%RDU4HKjKkI+b#Lwr(@{`_eWY;`?MLfCZ_I_mkV?U!e z$9Enphi>O{4bQ-DQE~xdd}}LJ32h4#ys3WsS7~W!?Kw$4b98YlEh{T4H&bbJ`ki05 z+;!dGk5lN*_`Pl)hb2=}*3xx!3+J2G_I-{Iz1+9!KBpPxY@SHI??d>vb`471Rf@gj z#~PY^F3-1Jcc~{Caid%T+zFu7h&PBQ&MP=p8kS{bU)^bYAEqBTtj#JIBJZ{e&%H6( zRlp%ni7=}c#l)jI5VRw~U7jC_7T9PozhiG#Ox%bk=JY{xK{HtY?)ulvz=-|#B)2^B zl|=SPfBY9AE0EI~UeoRDcJs^no>f-${G(T!$bv^zW@(iZ^SJu^cZ_zSLzzdHTf$M zCf_`b@^dN{Ajy7)&Q5;wj@>coV@@*K`)bjM6^*_zq3Pun5*-&`K^7TL_)bu1`p%T> zu9Wb~gx6~I&-(B`Mycygug0E7v(Ad~TOYd~hqd(iCDH3_mp0&e=;nN1woN}@<9yvG zs|;6pcV-`q#o5KArxopMV2b)+$%2{ z5t`U0)?&tNd(EiUCcUG$6m>_=Tv}xs(NqsqW5)h4sOioI%xM$66 z;|ZZz_`NNwH=|jRrD^l~UJDuW;~ZN^oRUmKlnGR?*&iK(UkJz@&Oj=a_kf#|6Q zF*3pk=Wl#)->Toj-x}vq*mpmKStuvC5aG9xQTQaL5J1;ZfCcl$P!^PY(|y}0>M<2y zSvofs1UDYM-mgzcEwZphWSo+y%Y9a#&*@GkB^s_d;W6us?LD!W?Xd2 zT=*tJfbC&p1%d{G3r91Dv3Non!%|3lsn|kh+HyiKpHQpA;>(FLHwDOi?5P-z3Z!ec z%Q80+G^MH;s>M_X;pjS7F;u3aRcCCqHFj3tOq|t+ov=}x*&S~P8jRO==TQJlEu#6g z_P2-~1X2Z5eABgOy1e`s*GpuFDuQ<~!L}UQ`*g;Yxzn3Tl0NFdOcwja;z$(P@d`o{ zf?JPbO3YB4MWnD-GAfvSvl=19hSeZLP#=DbYJ-IS{jp4EBa2h+fnyUaLxw8$=J25Z z$-rpTX;A(Y<~>`URyO)EgJ^?8V;WUD7H&w%GWcAGF5#StS5V8_%QcB%foVJQ zjKaT`G^>*e3u8tY+4hGvt5XZ0Y^c;zI2K~LEyE;gx5ZV}q1jJ)bu8bpeFkX;ugKNk z)xB^>TNaMNySjVof1|)S@q(6E>I9p$M#?0?Zu7nABphcOb-pohrn5S!&S)2vHEKd4?&=nYD-?&SfJqM(CJ|olV118c&S6ZQ=3Sj&~ z{o0=+y0v)|Y3dp^o_s9bZ`SZ)ZW-BeXL)}GB#<7#mVvH~NM-@P!*A6RIYqad7E zuH{vB3TRZM1zZ*f*}*TRKwZq)|3 zkfWT>zMVY{Uk zd+`rXnb-o2-AZ>=VwTzq=^pw*c^iN;b9uJ*cMx$jwrn?OGjf9Xj$4HNLY`rdJip&Y zqtohi`i#PL?B?;id0(}xe%MuH$xYRbt98}8LF<5?jdCv=4BP8&f#9kj9BjRj9Sn^? zOmw=njFn0hD#3&|>E!WBDWE|tp~UsVHjr5gBzO3_oV{BO^y7r1a(45dpP7$!fYQ3g zn-i%t7snP;6^F!_9!i@Ko0YjB=_~WIi{)ah`yM){*mE{I!Eg#S<h3o4A*R5rb*7y0Xryt7HsTOi`m`{qOQ6SFm;nxIt;kcp9OR?T@K3Awsx-v}Sz`P+c1{ z)EJqDqqTyt4A}2$?zKHT4~y=#KLiwT?E452l?5Ha@VHzg)PYVzX4RWk1JZo;Epm9Q zCZJc!4#HlZmK!lV77myq;SNw!A+s$16pWn=CCY<1KXBk^7ar0le=z76{-%BBF~~+i ztT(~xF2M*h_CcLZCcZY(U3-N13!r6>UPmQdmJatMz;I0u6&$oua2hd9sgoL-BzHE_ zsfz{?KhH=4szpxzsX<*7upj@E0G`lCRkjVY%8#W&6W69NR=GpWn!)y znodBwD_x`eL768tei5Yy-f|+{t1+S-4KOb9<+w+0l%30;FAtcrvjZ|}hH~HVa_DFD#1?78(AwH!%;M}Yy#LiZh*DXhVSD8-yCSXry5gBIV9bFs1|VzCQiifAV) zQO8q+#rTPa=Xl?I24+ej-J=r#S5A|4TD%NY0Yv~nEMU5zmJH*?U__9AclTjDUS~n- zQ&3qt)Yt%M-&R-LXoRYg8ede)+WZ38HR+ld06FqqUQShy*aYC>1nW1(RMvIfcMsl? zcKd_iUD1TALL-$HzbuP1Ef|pn4GV@42|$c`e`~8Dpd7W_$Q%L?gy9HZ3No7ZGfP4C zDzQ55r$6PygfkR`*L^dhNW+Y>$?vVq5QLN&90w96y(F}=1X%g=aB#@*DF#N(R3g>b z+nQSIJWL8Etfdg#CO)3fLA3hwSHD~~y1I07t&fCnhwJU9G3>5)RK79+?OQ{h`(AvN zF}pn66{3Ay4(%D%P1iu4h@PmZTR|X#H1eZ`l$`WK_x-5uw0UL^*cRNnj{{d3Z6|TP z-tRjdvoCS_4J^&mPJqrh+?oJGi9s{fz!t%x;8&Sw2$1>=5Q15Qyyjf$KR$1AaGf3H zN%JA>>{eF67-6Wbv&HYUI)??+lM|=(oG|*SLGf|ggTLw*w0H~*`xPjnFLt&nMpIq@ zQQi5<`83^3Pk?4akEASV86@8)#zsfMdY)#v!SYa$?QLx#K^)J|ViRUtw*~HQ z&(@XmlVVzfyiI{H+L%(q2q8KrjkzjGk;5RMQ*+C}V1cv|ppmMTH_ngSjB);va;zJ8 z&;%XGp*iIKAiGr(;55^-P;lNH-v|HK3&bp@9}_70-*14aY^hF7n}?np~VOrNuR z#gD`4f8V_GZG#1-&ax59adUL8oy}iXVu=%@Dij`C7_8NW5nH)ODX+(%PoDFW3eFOh4DdW9QfMU>4Mjjd4A_X*|y8sH3B zfG!_#Am8i>kwSGLqyz?>#++(IW>Vxwi%H43JN+?+&p6U7rhPO;l$70=Pe>XAzmzl90Q8Vp+;M+&HSitX;)kflL49eL=Sv(@9E1R2wFADVUm!j3!0nGxyE+*17LFJ%SJ~-ZPZ@HXIrr4y{V%gia zFTdaKj!AyWeCnvRM^Irw5ydIar|J3*@kmp4FMSYi#N%0pnxlThcw4VO2p}=YkOe?xhS2 zI|v!)(%8*cen*Vn!T74K#j8CpJ?ynb0oj6`NTWjw;VQ+zf}7&Rziu7*@c?LV!lc5{ zQU=tT(|W4=>xZ9L&+{WQzA(z3T*MVx@CmzGpzOCn;vn^CA{F_I5Vfs>wxAt-zMe4# zyvG0ya$E6$VN2|+fJ4zhv2!-(X?u>S5kVL=g3vaQk5=8g3TXZ4ecO2xP{XO4f&#;W z`&sRH_?0Xmy|Q?w}P4WQd} z?TBmrkD790lj5uh08I>TXQA^EVF&eBRbA}wOBMjf zh8PeLD|^VNa>o&!+IBt5d4|sW77YxI1IDB@ne%&DSyLGz6DN;_ zl|B@nXcW{=8C{gO0;UEi&2W_XEhduK7DwOpqqbg+n0K5A2_^@Yw`(bo1-|q!}Fcf)TCYUySO-=q3uim>*WF%{1<$%YDt+HI4mE!`dp!O7*+*$5Fb zHlvG+&EqMF59kThtlv6G==dUkjLi-jHD+Ng@-T74jxbE9#yh=XHg3LSXqa&DD4s&6 z?}@ZA@dx0>$695(29C7k=3`V14riSdFg{S7u?aP`mY zc(VIM&-*lg9xuW#bhNuK&Vs59E0I=Y#T!F?der4+B1#XyoVQ0_0!5XM(|!Y1l>n~c zL7Dq-z61`+96a=(qY3YKeqV}FI-2}o9$l^OSzTSVrNpP?*RDaT9`OX#7UZy`fP?lh zb*JqTZ)W#+lE`J~B5@=&UYX8dU7zGoasEi9Juq0qh^7$yuo-qFKo8$atdXgJ?Nu6N zr9-gToPdIvj4cAhoc(uTT@S&yk7MC-INb2vGbqby7BSoR)A|Keh}jYSQ?`@t_B7m{ z!OEN0K9od4xgDvwRc9gy9<#|3+6YS9xz^AoK<;FhaV=Q$Gvj5$d4xX_6&h@!_df7- zSG1<*9h3Ta9ctnPjPJRx=k;5Xwj((pcEW|tsSEBl<+MWO2qo$fYxbK3D#|P}xQ~O{ z?M0@&&xLxoBA^f~T?$ekeeX|iskWuf4W#-WX;1D^M-{CqLz!-nm3CNjyJq8qN?|5>lC;o;WAz#cZD?!-T2UT+;=1Q|+)av5h7Va_HlZtMm(<{ibK1H~Sf z4n0G2XY2FKjk+n5}Sl|bNL!x*{gguceBx`%!lx0F+>-$(bJnAg$J zA^CUc|Cjch_tU{I-S^wESNwI?HHQNi*xo#NRo5rze?jlZ|1&KA+iaoiaGUo&?CyoN z8VZemzQVp+Sd)XRoz1k0Vq4OTr6z?3?DoZOmTpPbret*c(j*CV9h=f34s@-;>sM7} z%}2=6DjeK^Vdl^^x9w=|H-`P#-J1nr3f;?}zQ+E#aG{Lm0*RF5BR%q|PN$pftkD#w z2Dd zJW#D(@cM~fu|J}9b+o&`G*+Y*6tC8Jbh11FKhNvA(&2PM<@^2sKOtW%-(cYXJ`}eU z_jmLc%JM&p`^|g)O8Q19A%MI z&h@aE;Mi4=jt=z16-cOnhh@jbN|T2w+e^+sH&$E!D&Bmsxk;!<@gJ*S0r157fv;Rv zJ#2OUZxL(|ASTfS>7i+CN*u)aX`mXS?P_ww{juxL109{XixqZf7cZ4KbJLtQS}x`J ztHQA^`Yd&MvNkjn)G$Tg!Js&SrVIn*mWDPQ0UQ{(H86$v-5LVt&+l`Y@*%yUVR779 zjrvTo90o$#ndk;%*n(Ylpi1L(1ltUU@pv~00YEb|h?A72X+?!$)!|z7dr>_XF=hs6 zhI(Pn_cCwk&2Nspq^_NJ+g<-_bB%fX9r<~Lo}c)6b!D2`x$k#8?l;bbq)yFzHha~J zOtVV2EXIfiYiSq@zG1u@W2D%eq1iAxk}(k`i-+zXY(s7fM#TOyejI%`*qSCrFnSd(OpmoWGH@fP~o*i%hy`}L}pFKS6zVXmtWh6!BeIBNr zbN}AsyK&SeIPm&jiRTuh>-lIle-y>>QOS%f5R03#a=1Q{?6|J!W-xZ9`CXd(=g#&y zM=Z-Is57e<3Sn#1cjWYlR@XS;ggeY#<_DR}?J72BhaDINJ@JaM31UbwOg|9N9R*As zE6j}Bs*2_#7}N42tL&}LWHn03R%^uVQCm?$noeL~qr+1>Q6fG$IXe#pCu&J|0OiG* zgxPE58=4Rr!9YWWKrn-EfEd*uqjM&NUPX}OrKMR$0|qRlKtSeM>C^|hGb2Am^Luuf zZnNcB)ps^h?59YVLU<>pBd^e8B*u*am5k=nHSr+E;c`}23vQ*~JL-g)^#kZRXxHlc zhu?M|$>4e8k@%6d`DW0W40!DaeoaTUktBr?@5JKs*XCFN3W+~5&HQ07|5orn>;V7b zYR>4-V0|8d;~VTD^gK>hd0y;}YkfrTeeHVR70i84)-7O>cP1hSEXM8IAQI0cdD`T; z4vJqLha1ucs-UG-N~<~0(}yYqU2v8_M}V6dlT;}p)o39NWke)%Y&pty=jM=4T8VJE zeW!0}6|!_nXnEUTCLPUxX3odbe6KxDl7QNWXi^5+R9TC=WP3B{4`ef6^1h#fX2!P^ zVq$zdRZp-W6K9lI(FDo@_|b%?{XWb8MeoxI06;hy(iS?m$)ct!VMKVEi!;Q8!p--m z8i7#8E`2>EmiU|xpI3*)vyGlLDp&LpnuRLUw9sT5OF$e{ z=OCYCBY~E(p1dz{*&wbhk77I6|FFx;>A^nRLz7Gb`5b-13RN?-o9apNe^vEWf@R1? zmXsuz7aB7`Z6$5Jo&5LOmA-ZNJ{&upSm(g3wu9d%t?Q<^p^)S2dJ@z#=*>I^rGi+W z?frhAGBSCD=J?)%&R#G-46cQf2kl^DJYEu_)63!LaM8QDF|dXiqXZ8XeI3H5j!!Lz zGIn9`pMr1OkKl?Pi3qPzRx1Bn4UnnxIWq0!t|PJUc_|ej@uRceHYS&ol7W>6GFdD- zh2++pJ$w4_(-GXa(Az-}0plM_i9(-dgFre**}kP*KG7TFBM67%aL2Qzu8B}&0YyGa zB+JwHc$x2{bN%41HEZthY{DRcY);r!DKJ2l85)%p%|SgACB1FU4(v9+MK1x0B$I!l zH&{E;+>AARg(h&q?X1{i4R#iBaOT%(cgVf%IMe%&`L_Kyl-@%Kj+o>1JOue!%KOCp zjO%;z=79_Qvi7#_GC~<=Bp;$NL%{Rd7u=kl3^+i?0u3b-vi3-9DdM0imCCX^xoWu; zmoL{IBvD{O$m8jW+P>FDGxpQA5SI;E9j{krSh6LR2=qF0O~tRujG-)}Ri+sk6Q zg`pnTz-Vz5E5V3?Hj)gA;+Q{^2YU!@>!e) zHswr4S$jW6iu0zy7Ucgy=9k<1^7Yp%nioQh-4s-UT3#nFKx-w69D&v_0KZjK7P>68 zt&Saz)P>HZP5$cS4WE>$EQ!}uf)Qm(YlMS?#{Okw9be@!mT0d(INtYu;8bs7^Ly<$ zdo<}4%JaXZr%l6RY8_LnbtB} z>aE)?*fA(ZMx@!+OOi1Z3$CqT^x7{N$`+)v4g*%HRTMQjhq30sXwqB^hT=mLzV=Jf z^ij{CDg2e7LR4aocMI z(ZOKHObJgRM>^%sCw*{yqLg5_>(lsR)P5 zyRlx)ZeGWn%F(WD#A0xufwPD_-8Le7?$5Ta2bkWdm166+w`^Tsm8le+3Q!o6$%~Jh z@nLyG_#J(SVD{xcx>sK(ldIdeGK>cqJt+Jj+=49` zIgm7>oVn-BGp`xKwN8Vrt?q}-AwmZk%N0WX_Sa)(vbc{w!bR}(XGW2ocr~GgjJ<=X z8%=12QNTJ1LEAH0u;Y)`u(OExY3&)Y$YUPIw)ymY(`}V7&%r=_ltyHsg9llR_ZC-2 zVK>`TZKG7Ia1Rm05t!AB@q}sZ4L0b%7@*$5a2(T72@mp?Dh{%CrMr#p&Eqx%3LZUw zq#yNt&D70Gp%S4CrJm*n-Gy&rm7&0BgLtM3Yqvr)%q{K_q_oY`oVJD4qN+3I_#W%W zr0xfPhW8lzU{GG*!nNqEnT9L6O`xyKIX-u{`&$&_kaRuLdXcn3)`?(i8?NtAlDH!o z9;9st&yOl_c%g>h@UjA8>LUY+XPNJ~bpv~vxg`;w>rgZ((pAdKTP@7oM{Ux~Ws+o5-> z7R&ns>t7XhdZ@pPS;H7_=Uwe8R8r7#Z$$LbglF>80gVy$+qguW&DQ(*``(iLGk+KU zzL8TqkT0ZG1^myq`efHbWSzMJI1O$_=R-n6b$7q{#$s`kNYi;k?en~|W^??*FL}Cm zE$B;aJUQ_|sg-7f*ICrk8{arAa*q~L5@J$3c@rQ>Nc-KmpTM+G)rv0lydFg99U>B~ zcp?;d660#OW>|J)cL`-W-#pAX)4f1!&ydNiL=L0$y|sS%98cxA93N%EOlW%^V$daQ z<8^DYdb}ja#Z>u%;2o#ucgOgc)D%4GpQ?AbszjKRq$SF2zVh;8h6>uqmOuO8Dzc>Dp=}c==ft&dr6Ufgu zTdvq7Iy)T)rrKt6ivCW)f5Ch|m+}zT`mhp78gQ`2vT-6vt;;OtOf*jo&xb8%P;rMB zgzR*rS1QOnFd2I*%yg(%$b|4V4|kg40YHcv0>`o$nf8%U%MzCP5ryq#H`!WA5Nbe` z661?NH7}kL4p$+t*@U*mf1mFckeMoK^*Ts=BYO0&O`kh`&(D8ICtky#VIhK)tZ1g2 zuAo&zAOn7WCvBvIT&)Xn29;}{#p&K{&P_qO0Y#7Vmst5=S^P6D3Nm3-$v6l#B(3$w z3DOm{FXd6rgNjn^>8|dH{qOF~XTC8H0{tKSzc|AgJt$9o{-XN6(=OEgU)DgwENH}t z3yRd4Wi<7*-3j{%3lkK4dI;OUu&Z!DZ?La**bor)Z>SL~8nDQ_S``z7;OLO@c=G>& z&BD90TmnceR%2jkwH9QdD`@nYf!u={x=d7u5h8+sjl@}ngTF6-8a2a! zV7?4Mk{QMFt-#bNe5UtTo5b~5BkxV}yYKtC zV`}C&0V+XRYnb-Zai>C&!`x7t(a1Z*RGnGJ2rgno^j+|<$<~y$j@1#-g`>cstXw~L z?k9V2E*xQy{!@G5Mt}(MK$PrEfh&h~F_y{PheP&I8<@8cbe&lgA9dFiF;4{>=C^}L zE;Gr=3e+}n3~XR^zOE=xB{sQRFE=pF^(3ZlE!>JL8H7=Z2_pmvq@5>J*-WZLFTuQ# zq6--jpdl{m-;V*4BY}MAp6wS zkkHZNDZ70yi&J{aI^zd0#s|{5O8_AheADkES!D&uZ6l9$fd(do13nn~6sa+1v<&h% z93wUFmQLU&OE4Bos_&Top-VP}AfIMFD_?IkjRvbI&jpu!MnEQ4WK?kEaW@kkrM(MP zyON1b(c=C14tZ3(wrrX$mDAz>Q}+kEspMR%B7>z_6KlgGMy+Sp-i2$Z z-mG+my^?V3mwI01p(Busbv+uX&~~*pQENd=yL$^2^2+yGQQ$feypT_+M1?9OoKcDr zW4QLf$-TwRcYpYHC;iHpXl)%>8QT3xn65y{Ny``-zZg^|%~3U~K#$F*c3`I7x`FDP zqa;jVVKfrZgo$J+*VQDTGu8g)ocC7XrRv>uVap_hsEj>4=@_>p$Y4T%jQ))-rRCm;_R zReKUP?OVX6c|#k*vc*5T1_5-i!YmeTMI7>4x}q2AL~)DwRwio2%GMTF(}eu;PtyMm zSmX{`I2@s}6U)SV$uf>!lhDQ9#FaK3Bo`&os;{`1ldV>9dxcBQ3g!-SZifZV{apaj zp+;z#t9A7Z$-#@fl58a&iHZYW+8PU{(CD5bdNhi@$K+wFQg%Jh zkr4XEPNUTMY!_+BD#-TY-%)Md)bQ~=fZHCu^g~(&2)W}k(P2srp;HW+x_wU=q<^PL zK{kVlX_v{uW-6f_WO?AYupF=zPJ7Z;yDL4l52>3pZ}cXH*KP(OgN*OCH}s>gsqYt(N*Z%L+!#Tp8ylhFWZ9}k%M`bY0wGL* z;>`**7_odNHhZfngU3B53o7Z@yZ1>kboTsJxI&Sf06{-|)_*%D|3(o+7GW~{M$>B= zyb?_o^8TAwEwHEm?c>Y){yIPI*#C~!Nq=!_>rSP&C{>R&!&R>V+Ig6J(&LaM_L3svBxZYPcG7X2uS3+`vU6oXquL5X|E1q^a3PEHbk&n*V$ah zfn+>XvS1vXzmwsXhdx?Be`9;qzW6d)7m^&Xg%ie>iiq39cutT2jg_GlWJ}L}k$5gC z+_8tA0t^IH9eX>If!!&TaWw1cfY%dqw`Rc*kZf_2LY*u9?oRTydBb*N$~iI$DN}yUm!S_$8RqQew^~g zxX!KfFm5$;0kyPPRo6pD083}{d;1@?lVWYZyYyXTTz@B_)o26ukTA_ZD zGnMMV?aNH zWrZfUKVMSMDBOU*PmfB2j5G(Qi4>=$`Dq9-dWk6;hzO|Bd+1_lQTjO(WE&@t2)w4) z639C<&#=-}%n~B<=oZ*~pKltUZ(HbiZN5P-Vh;&u0PFj^z14U!qAbr_;+^{z;80pn z-TAl7;$*y%pire18pi70C`e%wFV0DK-lu0|lxj(=9QLmpdc}$UI3JX&!XdGdtaJx- zlHpCp)SQ}cB8mk}p(?OmG}4ZHpbZ1ofKUqD8^^b?SA6H92ld%cXD^0azZDNoYg8k( z=VCdn?)Wc|7!n7Rx_Qp+`79quJpF$c)qq>XYz(eR@#G=dAk;GtcSyoe}q3%zdmU zQTKFy(_}_Ohr_v)LTEQDVLUzU>GtIVu6Daa6$BIoLrn>GXQY=L#5?#e&vI;8yec9A zj0vsLHgJsN8d}Y>k152;3_6b(w?@(=yKC2@El;auRS!qB(>m}5KoIvP{NJwn35g~W z=8(b$zP!GUG3P2gyULP23-h=NW}v9?V^lL57^fTT&03TK3LkQkK(`7?^|95>DBXLP zs6ry7a|Xc>8>hT%zh?kqlTSNq)nLdx-~6H+KPlF;sEp-2u7=vj_CjN)J8F2GkH0;L zUTEbP%ZlZ(YsJ;IeJ?rrt5kz9b9@48PIcYD-{ey!QdQwfYN9+xHC5oax{RqL7IpVh zs?zXh=nHJKyJ~vx2%GQ3kym|TKgBX^oQt<@&B6?pesG!q=934=mZU+QaUS=?Wn&^y zWW)ND$bZS#K*9xtH7nAvykshBAcVO@KH`IrSu^c&1$2tBK3n0)$X+W}3a1~Lq^QuZ zgfPua*aoaE)A|=a#X3vdH`Wmm>Rz|PF)IkusQsbBBvC)Ou524G-rQ5gINVYY>CFNL zT#u_ubaaZ$Su^(2*=)mFi%5*?tqg!srC{YfW=P4t{2V+0ephtF9#Xwpf?kw;LcNxN&N zkO6QX=-Usc|xmU{I&koFAM>7rxE2*kE?JcV|ep@zFYOU zv~_$2$7%#CSSTE;vYC5IDD{C3{;Y)K11`%C<3UteS_>-@k}5xO#5UQ59EdKq6_PZo zLIMq!rq)iZ?7pR>2&JXhpJB`@a{ z4GM=xb1g6dW`Ink`3Vqdv)Of&9pNA(XnRj0oZ};c#Fn zNhLxUzGJEVdz={Gn>%XO%d%TiCjF6xYUvpaMMTG)FDsASpuV6S^upRRU zj7lll`08C}D7mUYyyG(_+RXY##YQI3)jTI>ZCYhXAcUgkSYyc00)=%3Dr1wB*nZlg zL7L0(r$DN|dV8r>1kFDUo+wJOZS5n+`pXP&l;7JB^{D2_Pq&$Z64;jrcM`8Y!q- z9cGvVNX3okGMQ{aZJT)1DRg(o2&<}m8K74*N+KJQIP54eo0LVNOBLcRKMPws4%_0e z$OH2*ry3hKs58-s$m6p~DgZ%*Df25UTn{X}XQ5QW{y3&nuOzRA|01<|Q)2r8a|`Y^K8Uo^vWGbi~Ru zx0CoZRnT!gF+$ppDQpWR#x~oedwUP8k=gs51NkdJ?BBf*HjjZ%(}z+;M6?pD`X!`Q z-qU_;3<$QQ`BD(pu##Y=+YZdKQmWj~*)0CPuKpIb+hcuAq+a*k8crC5%gNdJm~;&V z+w>QW0yrF?MbR+=v>eP2eFN-i)7~+AV#P$SQ8fQ4(Mp>d;@XgfH+kpANQji^IqqVC zu6!=gXBFk(Wm}0o%0zWfgmdzs>QfvAu`HzFrLwG^uUxOI^N1LVp0bEmzw1oiEtez< z1mBHV|C$4=Dw_D}XD125v@j;-8E%7{pm8K#MEV8FJUtZr(Ue*|(#hPqb*zs7bafmU z$fBH^EVLnl*_5!b!ee^WjiqTrTD!9%815_SZCClerA&~AqRqU~(T;7MBc8yCtGFTR zNEs~dB}=}WNT4)`Xp=)4)ua+S`1?nJXryHG0Lctaf*pvWTVAoqm}5I+S<9;5=6#VG zp3sVZc2Nj6|7%3spX+0(D1n#Lx^Yphti=`4twKAXSchc=rF1O0zcln>p_P)N8dG~M z^GViK1+DZsEY$NJT9tWN($RFa!KKM{j2qJ9Qv9aC0ZXnP|J6 zpPKn?T2=b!H16<%S{l6KWcfNXd3j}eBj>iDc((l-8lJ3v+v|-3s7@)>Xp9`TcHXaw zmbpVH7iMaHHKy%Z+4)zh{OcyR_nPGz<%cQ9rGn<*o(cOG?ytq1f^wpopKr%|EAQ@V0%(?J2h8FA>P$9kiVc8~mnEX5t=0|6 zK1~xqxZ{@07H)Kn8fDyu@Xsc&mYWOvyA!E55vaUp-0n*i&`%KDni)gX+FZBC2x$!+ z$DYCk@hD;dMZw6Y6M?*wh1g9)5ISRd8S_n2TRj$y=Y7V3@EM;W>tkAzr z4Vob4{#K9yT6$$>oRdx_LaQTFw5f0g{tScAvJF(?)heKmyOV4N4|2G*?cH8U*L*bz z$9uc);GQ7Y2tdgAsWpfH@(<-8kX~$DVj{XfvDD6z%q}@nJYOjsjI3qKbTZe$_YW(K z7?N(Vbz+?U_~wA5Fs@?{AbSUaNkpaGRtQTs%q^M*b&ha&8tVGiyB=xv)hW-(Uvc%- zN2+1nxS$jYk*<-y$RY1xUY5~CDIzCcfe}paW-F!bG~mIhk4s@I&6FrJ9QL2% zE3@v^EVNAqPHe*wLod*cUU7~20n{w*8|Vv$IhnO3xKXpU#GxRMi1XR%mg+tGTJ2tZ zPW`&W(zei*dMq1r%u1}w9y%ljGMZ3Nd$mRgUP~jOakm2ni_V1uF8*E{Ns4Z1JyAOp zqYV5qf6LAO@x$AuZ|*x7I54p1SY<>3iUu zE&@XhJQ$UWO+v=>`e0bn3`iQvEy>INYw}lICNcdVhWv&_h%o(J<}ol|3G$W8#hiv~ zel%bkT{9jsg^%l=8bjiS6fOayN{?=BpMDQi$L&cpUF3h?_et`TQt#S%e>}b~Q+=dK zN4Z~krNSF0GkOE48z)k4xeqZE!JQq77b&1ALr$1Ok6@3L7nwm(${PrHlVMu`5GHk% zxnk~3PcNeN2JveHDhM_zZbErO2rr#D5!u0N36zmScQr{4+EDG*HAulm+GUC!k}MG|YiYGD|9xw)i7ifAFw~igv8F7dvB5OyVNaW*!c{WV!omuDk?+7; z#$i=)UZJ}e2|m;8<8EGJOO{&=qz=c9X0eI-Aw_R%DP2mPFZ3*m7CI8-A(ziX^A7QR z&#B33Es!gAw(pj?`{+M9gwoRkMN|Jr6vk;S>E=6C3l)Q&bW!aGhCit&uVb;?l^&fK zHL6amK;bE3x}&!9TF9#I8G#w-rrNFdff{YECftDgjO!*J)j$HWOr7Ngm8MhiPB-$U zu<#XmA|U3-1T2y^xqAN$q6V)>%JPj4egtof)9k22fl~ruLBLdSIZRZ~noaQ64FU;E z2+@2PT~8lhd0d$XCd57kul%C+twfprLadl+6#3Lh>b*Tk*_M4^-%tQ z0ER$$zf2Z>R-;0SHX=@%4-|WB+SZe00Uhuv!D1$m8s+SoozvSyfh!%+ZtbXOXfP5A zSsHH(96&5LBTKDYkJ(3tVge>6hMj7Qf5^NuyQ+qz1+#hJcd44|)WN zBfbl+ud>m-qkA2DYiOA@t-l0!0;kpjzB=f`?GWsn zf$-pZf`HS!aaKQT7All`&;pHHmOZL$g)-qPCZM`@XzeGcsOxz;*GF7x;8T>jBMn5a5O9PKwDwJHB;h-IQSSO*{JQll} zov4L&5frH>kXY*GHN$skFOJ#!@b9|6_qb?AA_AS~wKWjGP!&)KgTAxR8Vwa)J8X5V z8`Rw}$Y2G@S5{ZNA{E;#yfJ1|(_dt9BK3qJun);K=WIb25Ae6XP{7QS! zQw0SIW-VLkPSwJ;H>_(z#F^`cRZH=VXxF7m(-&A#ph-^yXhRDiP9pb^!RU-}QM%Po zpgk@lX<8B{X$@_#Hw^3oyk8g$oPOVqpb>RX6@Qj3{mhg|btV&X-R}nbsn~Nx*))Y0 zrXto7v~RK2RJQ>uL{k;241h?{`y9{*iVgQx?%TL92yz2v!}=|hu~6nQn4ww{ZV{2U z*YVpbr;F(mst75qrdb9T9W+bL&6Uwgvp84(m8}eH%Y}iU&X=C@d;0RM+Na?5Qlw-U zM_oe+8Vnwu<tI12zi~R-J{i^ zQ}{70o<0*^HRO$Y3&D0?=v*;TC}9mv#Z=VfCcK!wBI#w`2016_Zne5uslAi+IgCAM z_@-@KIh9Ej9M*^open1ujJnwVUdP@V+FoYGT-;(U{&gPIs+Y31^^rtxv91hr(E(z^n(cd_Svk9p9yjnlD=LZX;R?s&g?MvEM<6)e2NUiplFZ0$Y zOh8ObXw;GhywWh}JT9!bED4N?98XFJ>OMYL$hI%=z zm-Bk!pi^Rm#vMW*+-G*RpfrEp&@Eq2keTH$RT(p>VD`Fwp&3$|+I_mD@9u8feaKhC z&bAwt{+f1A{aV(5c;GBJU)NdZfe zvofA6Ysv@SLG4G?)ZAV@Pd{_p$!mwCB61Fu$io5l6X3ru4b3cvBxI6e9j*97RKf|R zhe}(hh7vw11L3HJ8U?vg^>P3~JoBMI3<$|U1E+aGo5%1&;Y%}ZLc9GQG-OBW`_G<> z0jNJ;WGv!y`Fo&oRQvTkf`|NL$MCHQCc-sQq>^tpv1(SjQKi=BQ1qa%ptbUA9ETGq zd43@V4C!wWyl4SMfPi)ENs1*Jk5XmuRd&Q60|lX|3@w`0R{^gpVh|8eM#rw~qUBrF zrM;_g_~5n5(vifO=o>etD^B!9;)a^4Uf&I1^HFv2J<(u&Ey z$Hak#nAPC52G$Or7iJ?arN_+-lrY&l(ZcnVV=GeGw>=jrCEj4W^Z5%=gUsVw> z3Qx!c+vLbfdx4V{4esF$C5{?nggETttI&72E%l-K;hmBCijRtL`(UQBtlR41ME$G~ zU{;f3V%@m?J3sLWdhOL$^%*S$0#KpE8>k|f70^_z2IPujk-++AGqfANEAKHBT2O1X z)jfFkSSIJdIa58Sb~c$R^u}Vj_LU}8%Wr~1q-4LyekP_>*?}>&IvryZ`lhOZ0YO0d zuwagJDQ-W z>YMWU$j$5Bm<0dKAFy#Qu@9gFEmqoB08cNVgRF*`M|D?{YG8U131dK%nNG zF9kjf*^#2Ti&0ezd?;EcC7a@vchx3UnxO@Qt+$DS2XpbD@Lnq;+n3N|BJ3LZoXA5i zYnav8HgK*9BNAv!_EE_cX-d08H7LfO7GDja7wq3Q13Rg;T^Vr1R74h= z67h3=U-!M`d4J)fQqesr^}`Fq)N0Z3!4+<_J_EQYZKHNnJJ60brB!QO&fqBZqKB=n z>pqtj6?R~eAP?K01`uR6Zln%hEHM;mp!Km7go?olX^5dg=jjtw6bRSabILho7}a55 zdn6j4SL5iUs#_?USgnZQZIOe=*(g#GiG$?3Qm}`w*XYPzav#0QD$yXtiE6_x3}c`} zDk)+%qwF1uz}7}1CcAc)b^fD#{!LWe5)9V+ZwT|A{2WTiw*$J92AukfGMwZP=k zVZui9^#entiNSGWGgEhTRbi>Uuh?KL^h$8bL`7H)S9yQKnCD06Zn*FkLbggf_Jg0L zKlVDoZ=@q+o5=J&-?VPD{#7YH>qltglH#x0Hu`|gW8M-><60612!)w*@tim#bmST} zRc*oYyFii82=MT8TsI3@^sTGaqlPM!=AaXqCQoU&I;i4qXb5>yb+2ZSlZW&sFZgs_Z7Dxq8Aam7GF6AJ1q| z9xahOXNGMkG_CgK?O-|j z{!dfh#8_$@!@}CfrLJ}338#uZ$AVc$qp?4)gp}&}zGsV1INL|YAf-c~N=t)-US3-E zBAcFmX37T|8U|tA-*q3zd5Y-V3+it2rg3+-Ow!w86t~m@Xot==bu;Y*o z8MMQ(yngr2`M1@pm;b!@&ZX=q*%5l}^j#0g^~?Yb}=J;dlnu6QY}R6;G_F#H6XRE0XR z3dN-GisP&I13UJ;t=m}QY|EzZAk#Xt2R5QSs-TW%6sk@+)-rJ@?Wl zzWa~UQ(yd&8%x|5Y<%xdx)O&SN;OeFP(0pu5dds+ZkYEcEd2um4>dZFIN;ExdiSQO zYU8D3X?dk^jR*444AcP!fh%AM#e8n%DZJh zXz)vMO$M`0%N688HPBx6Uv03yI)Bx5MYHJOEC~FmTQnowb54#l&oj^d?(GVT?`_1! z;^)rYb6$9HKzRA^36Aq>e3-A{0I=nyQD%KM z&$n0%@cV8orsRBbUsVxB>@wQgJ9A+HL!t5U3y=pZLEr{0X@(6Trq-rY2qKYm7EbF4 z0@_j^_gTduE7CqT-IVt2c}7s~8M$FvS9poAZ$@JYmOg|q_EMtcREzyfHOMbU3*VOm z)9X#r`Lj+O2FrsR*IIwDY|R|?dFZm)$x%~h_2ek$E}l$j;B28eW5(NH?F-Ftvio_V zv`n|5&yxTcS)FmV@5-obKcf8>sRVZwLmu^5__Y1Fz4_QXmIGDu z?S;mst(#`CcJ&T$*Ed!FhQi24Uxh^0RY!SHx$sKy@z+{!F$9@~9|bEehAXq@l}Uo< z%o?M^&+Tfzwg^BPOr#R`Qaq{&okBJ#pxt80;ge?(*c$yrd;lY>m?Q#*}QU(>`bvblR*1br|={eE%ySxWCZY5W|T=asP%%xY?M@W5b+ z>6QYG_pa|-)ILrkhaAyT#_&(kPIBP@>`+d*q;F~LgW}N6n1&`)^jA|@Cf$@1u^`c% zCZYiix#1{Mt`DsPaORhCO0$Da1A+9Eo`&nZt;z;EMbpuM(lK=9*ZPYS zv}yT$?uBRpQ;`ZxxD}kJg<6(eJ8PEBsUI2BjMKvUAcZnXXlCNTbDFFP!6t4UaV7y{ zytjDP%46Nz!XcY(=oH-03#R>nsZp=POW1}+w6m{(mLnSN$;R6PrXnrY&z`Yyh^2z2|63C9OVMa4p8Jeb9c#pYzR#2;1 zU~uY}k`USf)tYQ2!fpV%EnOW?QxpvQImDe_B^3y5XK7^n z$iUj4hW5r8L5|cR7Gfz9Xj>LkbOJ3}?q}h^esC`>m<;?I;K>{mLA&4O8H3Lk7?`#7 zJ$vuLxih%Be(vC!1=nKb!}fSAkaymBr#ca`K%PEz$_HH`jtT|Weg-TMhN*UfAW+E| z2W6sKNnoXFX}5)TYopn&=C2s-LqG2`9=gLuG^EA?N`v)A_``+knn_3P78-dT-_{rz%l54H zt+lc{3y2)g;&=b760rI?i`p{y{T6NJfBj4~q}g+8XMkTv1!@f6!!lxe-4=p9fj76d zc&j7qA;3eGb=fYIS(1C`fQ>3g$Y#9%N-cN(BQ zkA2a0^759H$q(&q$>C1gG1oWQGL@(V17--u-3vhJxoB~OPZCteS=-)Fd3*G~t5kABF4PgXC+Ra_(VM^*PFwwN{MXA%Q)cAcmn7=`gr)pJsWhwagnl<00Am=-{^)xh`@qn;T>+Lzk#(eD%XdL8-cr7rAL}L$sY>r&uDY{6!3R35ZAi zXDSwZUEazulu1Bunjlufov2J0EL9M0uc*{@w}c{dD*@HeVE9HQ)oH9W7i2NEx z^c8=Jd(2+rOSZMiR}N_FMDy^VI*O3a<7A>)LDuh@3PRM{1k6N?apoP9Q;*(viOOUl zgEFL9+7p8iJSMzqD!XKSFmEK!(RlfPW2=5DfS|G6f1{Qpi@^#Z=6kJXYLv?#fYJjz z7~963qD(m6-2$Mn-J8NXasgLk&V)N@%@Eee^*9CNv=v@(n-ofntk7qVcQZ&e9+&V_ zue`L6V^0m;8j+3;;oHhqZba2iN3mYReW|J0f?4eeq0mdJK~D4E&j}UnLD>yXt~`Qu zr`$@L&pdYy&+qZPS%b0I0Yzwt=J9)~ekv6QoUcDwlMz+ib^ia7>=LWFhOAX}v(1q^ zV91O|e?Ap2AHqs!`#zWhMnWDE*$%?V1g&I+4-^dr-=+;^4j>~)c*c$cp1kW`Wk6S} zGHUcM3_{h;`xolHjY7j)49XjuiM;e-FqmSJ(y?ab=<-Z%9P$ApV0Ia=`CV`9E!tdL zzBRs*OWsA(&fdd+hIyBHJ+QOw90*{Vy&snL`6xfTF)r}_nVXPF)1>$i!_Ty}eP!i& z%Z{os_7+5>!n-2uhn~z!`^cc6=P43dzG3eQ2)oewYFfVoA=n=kM)ftY0VlG>Wuu?i z4;&-h2Hy9jpsI@63rbT;AM{n)S>69M9A`|H{V3_Zd1y-JvsdpG|6lg-h&lkAKF=A* z*wo(IA3J)f>mtj-EE4jyX zI>_}Kp&FL$IuPue`dSrI4LIU9_P)!n1~5T$*2;;mo88c}W-O3))moq%K$i!nCGu_Q zAlzU<_B!^l3zo7RoxuyKe-^-Y=u2X|3LoiExW#u{)@SkPt-hZ%O)uZ=uZElL$^@JV3WsH`5zwV!-#%fC}uCcuPvXKo{r6?rL} z$^&zV?ZLI7t%!`q75Bx3Y%Bnvhhp2tUoaXJXkY-^JE7n?+9TV=nIS8WZ>&5)Gqf3e z11SoF)fgobY7X0}$ENrU;C4p^C%_Y2i}2HGaog9iuY%`w)%Pi4qe-Kv_+>d2hbp5F z-o#ts%R!*e%y*QAaAo$|V1tKi)69K&fLL=OU8%E_e!X?!qiZb7$MGY_okdw+Umt98 z#0Q76UcP);wc3Ko=bKW^d{@I27i9aa#iXph6XBM78go=Rjaq|dom4e4WfIhR(p8&s zq9{xgh6c8-czw0v1Q|yNKHA?^We_kZv#C>>idf!@wLkOcnvSK6i}S`jrm`n>@Q6w^ zHnm(B%!DnRZWD{ZqiWC;o0aF_xl3lT&uaWx!P78RHCniR$Ck*( zm8Z~ z?LeD`F)_VSeZ&4XO<(nyrvK5N$36sFUyAF`v75WAW-33Ai^T9gA*D6iD^i!ZSHVL} zGe^%MZ;&U)eBgHR5Mh_C#yYbEs*GrJV?#Yhv+#hD8!>#Iy6A&52j$$Mb`IY5>aD}9 zp+XD4*XtE-m3Ax^aI&SBoL@GfpLt$mQF3xGdq-Z1r&*YoYJ;$8+(RqckvHp6G2x3Hi)@TbWfGWGkIc_CEZ%EjSix@e8Y@pw#n>Hs8~V>$fz%d8tR#iJ_(^Y zd!zMg=mL*iuobZ0rVX(jVubQIPCKL4NH-0Nr5rApi`JAx*&Bw(XG)=pgN~_eEL03d z^&|rBpst6ly$(-+zljR$!L}O48qhZ_&@yo2kq4CXa?ksBL<>ei*0%3AXU%Mo2|+{r ztAJmB=ZLa9?l?p1hgRhKqeqX@efQog9e(lRCB<94=9}>{3(W;99FT&UmJ&pxA&lH+ z#1$(f2$kUy-5UpI2u~zs3REx}a|!cGvdzwi%9>{lcK-YYS?=$=;|^L~Tb1kCL$`}M z%|T;-dBQP-k@#cl3tsKE^1sf4^Z6Y)if&szQ<(6%&;2HSn=;Kdv9bi6m6brO$H?~4DR862)Tl99Jcq40 zahg#n4W1^6z;Q&J*uFE8O;#D_2DT9(nj7IiGi%J$3RVefjC9GtAheGgL$*Z@!|D9@An1maK{@-#!*lmp&(B^2QRXqU zDuDVkXff_nh6-Do8}!mQUKUTEtSDy3!0^?LHiNSw0x$YP+v)jBJ`wD}7H_O86_kKF zLQ2I_q0Ov5bQ7vdqof#mRC^AqDxqo*70)tYQxWDkw_1bMh!*&y!TgO?Tf%mN{M|nA z2JI7az!DYXa8x#Tkr!=BfVVW1$abGqH|HWC4}n|Hg1D2l8pDCr)e+ru_uXPCvqn39 z{1}})c|u<5yZ+e66%(`e$v7SbNk-xoD>M=hWSTK1@w4W9$vR)OPGyWb&zY3tPR<3B zzgzVdq)=cnlk@JMDV7{CH`O_8ID06jEww0x#)rqwR5j*gWf5(!JHR%n1otO{g=$!i z2Cv{ot9>M^AHRDa9jd@`Z!8!oSq6Ds34o80O{zvy|Ho>j z*9L;isv+&W9eeNfO`2)UAYaR&b^<%Z((VfdR6K<`0j^))G~q51!5zDPuN^P7GN^i=kwcx{{~zV zBE#TM(>6s7gkqfXy-N88>pl(|+L=&YdO#)~Ye`|CCenTqmv-UQV_%BJH+2lT!9x_0 z2}b`RkgE3Xg3li<6#<65QAg>)J&$)lSZFCMsbLbb$2rrC*zp#8cmOMeu!^$DDE1@& zrUjY}GE_|pQIjG^wycQ&+1?$<=v681X#K={==%BJqJdt^ExmT_nsm@tzxwrT`rD+xEwDZ5|P#KYRw99C`{FR*-s>8zhT-?jJAn;xEj%d z+zC_1lez~uNpVSpSqkPOrND$8G3Nv7yJ;~(WnG|gf@L&^ihGYXs4xa~b+V;6kmq7r z)nwVvTUT-zq$=#vzWmJRpZ&TQa^bW2zdX?=lU-pkz>vs<&wa7FvZ@KR9GZ~N(>RUB zp&={CdLth#eK7F|Jm1yI`XE}Ci%uL{1^UjgI52Z^rlNLA0k&uyhrM_8Y&pLwv>wQI z(v5|pEf58josv(;Z%&}2W+bE7wop25aFK07W9p^SGLx+3tHa^^Tow4ycr~|ao3F@}*6D04 zZRBh6(z<+@(sYBGr6c)XJDmGNODjidx_gznG|tQV8trUd&G*jSc)s7(&5X?_TXK(` zo&21XwN0}|yIU7?+m~fx^wTX$%~;Nh*zZp!42eO=%dN05T(2*7@^d@CU)N1k;PQkM zuOw5J-Hr~Wz=_T#XeaN>aT`~zUM|96KVaa63KKh{VIj7ne9Xlynhx}w*Iiaj&7ZR& zs9~cFeS<@rNCh)v50{#e(U4E_i4aVQKv|0@G$o{=aV5ZAQW&2)&+0Cjjce!fvR;fo9=OAY4~r!)njv@i*Pi)`Xx=Y< z{#jZ%v_{8{9m}7uC^X0#ac%9e84aopSfj439g-Qnxp`A~*<+a*IV#ujD)N@3F0HR0 z$?)a6bi`zGEuS|P=y3cvW9E)_Z*I{J-H;H)BS$jBk|#&l&3LoR?9KKD9bZ2xkmO2U zO}ey}@3oep(jjpPzjNs--ApUAerzp2_h^2>o-XCjc9wSOP;T3a_^2#?ahnQ-S^x_THT6;EDuQ1SeMn+LzZvZ%e9QHnO1w{g|Eo_96fR(3tA&=&Sdi% zz45}=^I#@109mW`)v%Q5mlC|2-0RQ=7R6moA%iLRU zzx|vjO~G_w@WM3fT@0b*&%K%I;QmrKL)u>zSp?qS-kIpVeM!y`VP$y`)DN$1XAFYY zgPuxAZ{v0G3ZW{bO%;TN>QC;BfgmS%_Nr8|m>f6bGtt(SCQg7uNvXQV4NH9uNvy{6 z2eBX}#JIOw90>MD``U4Pdmx8oB3L0naX@4b9%mKn-xlm|5nF|1NrE4fV5T%+LTbaH zXx;f(3kbwKEhaj7f#4_aP;XB~iw(KvTIkBN>^J|cp~9Ji+Cl+tP2(G~2E+FViO$k%OXPt6J%n-AH*v-)o3@H z2&gZptccNTT@{aP@yoq!d!bdBlH2=WK^o)Hd7MW^B*+RpYGslIDp~zr&9u=B7`z+2 zl^UyU1@%eGA80({yB~X(F=&Dl>TvP0At*0sI0svVDKAUbnSEhBaHOGd(E=z^AGJW1 z_B4yn3&jo0Ou*E)HX|AaK83-`ajQA+hE6I%Ieg~u`GZ)DI_xnHC+ebis^1^|gA5bV zY<$0@xqb`{u*Ji!*&@9egGy=YzU**NNF-jTbuBRAq2a*@1Lx|*gIl`9(V$-?t0Z7Q z7o=jvp-+I43ofo@kE*nfv`&a-j+d?J@Hx;G?6Z+&m{&+?&tvb571Iz>>!EUYOGntt zOEPBzPBpn!tB+Z48CqIvtNN#XJ-A+PKcnTTXvn$~7eN;{Y^$$Q{p>KKafy6Y(P+Xr z-=6y31PZU5*UYQ{dhf-8J%lV_U`qfO2csKVxR)(lllf-}{1+qLJcmn525VYEnq1Qa zPdE-{;FEE_Iu@m@0W>_yBA1L5^7|!kw>jQQhx&@6p%Y`bcZ#8BwG6F;5X?`31{F@> zh|%Y?wAZn(U9kA3SOQvellBqy*Q%`}>}^2W>wuOtbwt<|C{Zodj`V8vSztmrPX{7Y z#?7F;6&4=eDhwdZz)MHBNS&&#O*5XVTY0Vq*M=}x$`_Ew?_0lHDy0HULA%xhTLEXu z$ijJrZ7>ZOE#rgxSiPp?S`-t+3nZrEJRyS>C_e@&&EX)ROEBdHjcv&V!Gy4#Nv(<& zEr-6+_eMWN3;0*~;c0lOaNA^)AH+jSw*his5L)91VE`Z!N+3s!0|71Vu}-W84gB@2 z0M!_`ey*HL#c+WDCYsl9bAN~OV<5n3@8nmXJpOlD41Llq`i!rs_}kK?dAvQ>7le>f zavVODE!a>ynY=a%VyJgA9g23b1Ey{2y|l|Fn~0AfKOEOzGRQ4`B$yDo6^6%BG#xv8J)fVFv^p6QbBfdmnpi=vXij*-|8+T>@Oxv9e_O zXawzpj+t3jYwdI^%{nKbq|wG01ga*CPnHGu8Qgp3??rH={(RQBqg17r&0REvQ~uK= zvKCsbXnSGm(grI1&fZNfjA+b6Co#t(FYK~<=#XL4Adz@vLebQPWT1JeRP-kkW^83l z)#_@}<$t>8F6cHFVoO;ksL=Ml!stZPTa_f};Lje)ghG?vk}S%~kV@^meQ0Ms_O(x8 zjajE%=Px1Lqqs!-DvhUFCyB~u<&N`%e+vPVYpJAZ5i~xPfFlS^H4L{tQX2l8`+5;P zNVi-Ca9*7RTm*D@9~aC}W5(fo*6oOc6-9&GDaHXmovOB!tnFUv+&2@E8!+ZAP0<@+K6xkkWv2uJJP%oY2%s(ol$T;DL-)3RW;K8ip^bI}L-D zZhh>dj6u|F-%fK0!5!&=Jq=ehWVWa_QyXS#`>ONN__D67 ziU#~lz0GVWs^@QP_c15Zxa?WTY!H|XXhQ6fg5Uk!61hf~VKs*gDxE6y>|L1o@SSH7 zC!Mt2Iu3@5EAOD>Bl;G9z2_PtXLWCJ-iJW<7HrKgBgUXrfyeU0kzK%N)D-?VI3}Yx zZCz7ui-e>8ZvMcAljNPPov7dWHDUffw_4u)&S6+E5`6b8?w-9zEv&Q73j8gG^9?}92zX%M9*3AE)KnZD}`Ig!|>Rf zho&G{Y1Ec*O}IOI^ArLvp~_?hyL9jt4C3suX#U+2ilj6{?^V_x%?n!%ZEp2^w6Ce* zL@Lm!XwrGeQ8#@6f4GkZT6Y%C3})Tn{xA&XV}?Dc&}i6m-M2`KT0j#Tn*{|s{Blbg zgDo(wT*F!$u`S!6aAYj)DJ2d{2r4wOyS@V%b(g#yj;YNjq0St{a9fSNLH|eJSX8m} z5U%a#*caqr-jhjueoot#S!G&qI?a2Y<025Qy&YJPTd!Y(Zq^j*EfEs7r z8spSk+=U7`D)vj-7*`pMCD#+skiTb`A@?Patom;^sb$hTRu_mc33l)QgJ)p4L? zqrnPHDD(vqp|zdSqw`Q#q!_8nbL+-OMq7GG-Te#ozC4A!cJ(TK z-=F`_>6d=-pVRjC7GW%1xYA++a1qoP(r&}0zSfKyt{5u3N&fQny=I?L3uOIS`I+x# z7PST-RnC-Vn2C-1AP!<4h7`yWs%M~G9)yo)q~t;&YjUbMYbhC^&I?dqq4K72kQ28U zDN(@!;(fDtYxBr3v_!gDMtDl5F{!`^btI7qU+IJ1$}7nA6^7>n0sr+L?4EdGYzyK+ z;B=|kkH)rH2E3?ik_3yx-s{*q+OD%A*sWqJL`b;-U;_qi<5;KC&bKPo_&Yh~?tvwl zDlF~NlZHRh!dpQZB7#TF->sS~&?4_SdzRJ@uS-lf=POTl83-HLDHoEC58)>DsbfTKN?CX-cfe4#;BC-(<9ME}0#knGtp( zYZ$B$(9~m=fs^GO0(o}0K$AF8XGW-3(co@%MDt1fx@qm*3|Yn&Fw|M9mrVAmZgf3P zPy{H&D;tN}sv&P^b^g>*q?0hzqnCjD_qS=#K5E-p{KlyDIF7BGTk^vEqEdRRZGCCh z4LIXMfmx)X3oO}7@KZ5tNMBluo(v%dIu}CB$1HsYUUU}91R4r_Js|j;56-gTdLkDu zUZ#KYPyP}8SO4W-p}+n&{|4Q0#~t*kPyGVD?|tv1@A||i=zsmGpOpUi{_p>O(d1kp z=SP0@N9m`2>Zj=Z+vn;0g?H!={lSmYum8s9=-zwpp-+DDPt(u-?9bDowN(mJ*5n;j ztG^?tGfA_u6sq0}X$BE=c3j#?8+>ek2;uE`2bwjST1aD+T7+;lbVb?jr06{!1C&8KP0 zMlyowqK1m{(b?ehGCUf!&JnBN*gq#)=CHTHgS`LW$-aV{{p2TBn+W=1-m{*DqE`=jmlRcJ<2usY`%6;^1c z2qlz%+1lK+Rw;e6cK8V0*w`jb=2gMi+Md|5qN(!yg5yy$r!5D@70t5;iRQyd-O#eh zQ5&$hF3e0CJrBcJbyg~W%|aEf8}jjw{n4yde_hUFjQj^a^aTCLkNjOZXIvF?jFyq| z!$15(qEVlI`f2*~r$0@{jvc2z`6u5?Pd)Wio&euP&prPBN zH)~A<)XNHJ+d1$n@q6-fn0pRkBsq+A);3izs#GwFj&EUP;@x==Sy`Zzm{0y-k#NWq za##1zlL$M@LYc~*i+1#>cjGXG0!uE1=}s}5C&QlpVbGyFfZM+5XPyrnP8wr z_wmjrgm+3kD@mGKC*XZbx!}RQPFNp9loOtlT2c@(F7j%^JV)?owhYyQT z{P>Umxb(&0^}|x-iQjK4vq29({4h^zdi2rv(aDo1>BoNT$K-nKGKL9?szrshX*9xa zsg&$OqJ{E2CH4jaQu+vD|_5HU>yZ7YNNS)RydKBl~HP3_(ecKEN*N(qX|O? z6$C>myT(@-xX+a_Qvuhq3kZZVmdD$F8*&PDpN=r7^{|t*ln8k4c+nvmB11$ zWQGQGAy4QmNbH#lVItK)5v_LR%9UHRLGN7i*Y(8Z(>Ug0Jx>4>m^3{?&awyc)Hg8% ztwfe+b>7h4${TlmsH+MGiZjlc%1Ve>=NPMqKZ5WgVb!2aDqi1M#q;z% z5^}5ZY&NlKjm*i^*vC+y35qhNQ1*67$=H%e`*D8nor0A#jzbebOPWly$~s)5&EsnA z;0`@>_!ymk=OV4F9`aesz+XF78^{`l>&6`u4%Kjy;o}BIoOZig;E2num(&52xW#An zfzKM$k*z+T706;R2DiWm-xF4`nbpK_c`eklE`PXr^}6Mv6jFg!$$ppm%S$UF_$kuN zy`sPk#BcC*lRQ>Oj~)|65@)KsihW_5@(c{%rVbd2UUf;@Xd0Ar`&=OLy>a5)*xv9j zCmy5l4BY6lL#!Eu>X0dkxk#YkcV~^y`IA$tGpHLGjcFh9ypPIBLH+)kg05ESl!IEh z;*d~yMutOxEOP6O*I&!a>#7Y>kXjFXuUB4sQ$iiFH9?!P;f>8Ls#y$L03DiYk8$o8 z6fRL*huRH_?b`<17uck5w_jm8DAmhtQXy%BV>S`twg|Gm967#*unzhdLKBK0hDuw` z_Ur85$#6X$CYsysi&$i?%Gy|L4YEp{6DGA^q!Lt6x(xyOXgAImCDk_8Cl-XH4e=GA ztLWHhoVV0~=GuBj-Fh;s=?3InYCw_RZ))!B5}~ItA;9n0w?)Q03vVBK>UON!Qlq>& z8_DU&QQGU+N9CkwyO7$$xztpC_}E;Y{N1tR$LQ%Ve~}(}-($3#H8R)UXswz&QQ;xE z^Q5?=736l$o>}rC)Jt+5gUp|Yg1gvI4JEQGhRU;-jn}Rgz*z&6yq|Rt=-t!f-ScIu zMJ*ht(p0lHew{<4d|oU|ZQ;8E)+Fx-I9Q~Qx1;|pg2>mVWHp#eZ9#QrlyoRnGOEo` zxieWq9Ok6t)nWU-l>J3So@mStLH9HG*b)j*n;I*%{%hP}6q>S%x0aoczfp5fUER8k zGtXQ%7E|(yR*mh-#r3aevxXKOdkb`*EaWh`MLn|W{Ua-t_0&^epet9eXN^3j)s-qmGQ7M}FppYr;dHHM0_V%GN|p(N12z{J zbT+i7>0gHo$+XpAGKFMNBiRHf*CBUML^_qKMh1MW2bDjCK$nJAOiBvQL<}JhT**n7 z<5;+HTh9D%R2AieS5VF+oK6c4MP|45yM|~21`rj`Ao{D0xu}IYcqWPV52#V;cM85q z(j+T2o@l%p^Si;Q1-ucw+?GvSeYLR(6+<$iH<~qt+k>Imnq?v6MUn#{Eau> zpy!`|!MEI%8p|8H0XsWAb|yP!Q1lKX3TDbLkzb0j)}b{e>tP^ZO9X!Icxhz(q|RCx z2fU<>tyV}KC@zzNnUi*812g@L;7ip@+n!g|{` z#)Z-*Rc*u(ft?suC#okHCNn5g?hB6F+1buMPhTvEf^cFPM&FoUY|Gs-E`Q2CzmMuk`@qoT+KO-d>Z`BOE3drlg=fml&r4mL`ckMr6IN)`;&wwK7lP0fD#^8k z7eJ}CZ;3n;Z&rujv;bti6e=X@Y$;Y~G8(mRDC*>hR&deM_)VWqElidR@r%G`Au8pq z$e-ag=F*U&gJ3I6AP*iYkR!MuTj(qn^yr>HE{2&5qw;gtGk^W!i!aKmc;x6&xlSkh zwrVx=9*V+n#=_F8#HkS+8%wWYQeycJ^U2G@cPfq-&4L;2Da<&oUb&QQtdkV0EjD0t z0NeMeIK=p1MWMk;9eY?)Hu5*}_`SZe)ILvpa2@;F1&cM?jqJ>L?%A(o*X%X-R;3VT zn23VM5U=^Nv7c{wT{(fgiVGY`gNsUQR@G>%%qi2;w)9%U&l)eGHDRdd% zrxlFMtC1E9pOo(n8i=zhPcGS{DQjjfPzh+neX8)x_V~8R79;jT=}TAHD%Rm$tbbEq zilaNvEwD(HQ_cNvZEetgj~iDn(TP)M6cROM)k$#P=n9{a;AG4(^}D$b*#6qt-b(L# z-~0aM(@%ZzKbpB^ZQIWsdplNgXTOlO!<%ouDMG^sFYzdLBFl-rv}iXfmVdNh7=a-i zernDco$)#&yDCi4Plulzm%`ni35-VffURz4qjKF?fnbY*D8f=cQ8mR#(8*aWrT> zj^<;*K9YH6=4+YyMCmOURj4iP_2ps-$U*|D&~gHks2FS2>LX)`I?;BIeBX5a%4J0j zjRvMIudM9$T!lWR+>E6rk3q-=X-JlK#htQtc>TumX!QDIcl*oRyVK9axckK`=g)oP z>eZ{)bKj>7p`g57a5FCdYYPPUo72!&uU>ia`qgW9tSseLr`_fC!|P4{>`?BU-1?>9 zyFT$!DSY8>%pKckA@mV#Wc2}`XTBetA+=`b-mqYGj2o+$^;6k)-|Ho+i>mJH#OrP4?cmfBm$ zM+Yv~UB%4d?n;1BU1ikwfeeL_xN+kerRyXbn?q8m;=QLGynpW3={U_b55Mb=fAX(>_E$dp zW7FNOFes1JH1V!G?|kv-(W4*9Zs1c_uWpSW|F#dUzVX^?hp%71zWU@7PaHb;*7>8C z-g)Qfw>F|l+;h)rH|>|MT)lGS#EBEj+4^1G zxUso%1W%JA+rDi9#g!AuRg$KnDMMR#t zg4LlgvEqu#p-SFdMH^xX2IWO*88KOKmw&a-k_q zN#jDU(B$xuBZ9M)cGCdfGIO+j z{P?lgp8Ac?yq|9GaVr?{uJGbkH~MWq{QJJ|`x~ zmoC0@{C)3z^w^av*YZTVaOCWJ-g_diHftLj8!M+ypE)+!ovhs4+FHtkx0VHRoN2Lf z7W0)hOHmf;HV^JdcWBb!Arx9+0pegI-G@dEyp+mb*DQ20afm!4MR95i7R{OI#_o^2 zLFH$A*QRn9g@$5`EjD^jig|e>)HO*WSfa0f<%@!05ylCqqfQjvNQmzv0sWE>nz`eZ zm1%|&S62_Md^Jz+znPWOxePh4Q}IGARCK=^j^Bwu^U*x{?ced&p8M)o{yuB7UYCh@ z^vKcY&Yyq#gY@tJ!D@2+@x?(Cg@TVPt5`sAf+jv9NL zAgu0x>9oGheR->zkfx_U?l`xHl^aXcCw>>Rb5c| zpC>29Up%m|sOy(~c=3DvY5j>#%_09!ANr^9cJrw>`}vQ*7jc%C*}t3b;Li7z=d100 zoqKxP{l*H(-mpV=%kTfbW_-Tpq3bQ}B_Duh@bxu6CWrc0Z}HDwZ>!*6?_mBw1|aZs L^>bP0l+XkKq6c&u literal 0 HcmV?d00001 diff --git a/resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..32352a70c8 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "v4Of6ePWz1oGVLqU", + "name": "Bambu ABS @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu ABS@X-Plus 5-Series", + "chamber_temperatures": [ + "0" + ], + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..8b6bc2ebb6 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "K3KqxJ3z6lSKoCsQ", + "name": "Bambu ABS @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu ABS@X-Plus 5-Series", + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..3fa0dfca1f --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "D3OOS6ShJDdn4dlU", + "name": "Bambu ABS @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu ABS@X-Plus 5-Series", + "nozzle_temperature": [ + "250" + ], + "pressure_advance": [ + "0.014" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..833774ecff --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Bambu ABS @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "8zWM4mqGjwjy2yJb", + "name": "Bambu ABS @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu ABS@X-Plus 5-Series", + "nozzle_temperature": [ + "250" + ], + "pressure_advance": [ + "0.011" + ], + "slow_down_min_speed": [ + "10" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Bambu ABS @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/Bambu ABS @X-Plus 5.json new file mode 100644 index 0000000000..1464576f61 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Bambu ABS @X-Plus 5.json @@ -0,0 +1,105 @@ +{ + "type": "filament", + "filament_id": "GFB99", + "name": "Bambu ABS@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "chamber_temperatures": [ + "55" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "eng_plate_temp": [ + "90" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_max_speed": [ + "80" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "200" + ], + "filament_density": [ + "1.05" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_type": [ + "ABS" + ], + "filament_vendor": [ + "Bambu Lab" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "hot_plate_temp": [ + "90" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "260" + ], + "overhang_fan_speed": [ + "80" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.035" + ], + "slow_down_layer_time": [ + "4" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "textured_plate_temp": [ + "90" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..67725a5ee4 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "ed9ZVS66ll61akjK", + "name": "Bambu PETG @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu PETG@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "1" + ], + "pressure_advance": [ + "0.056" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..953359bb36 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "mPLqTb7smgIDOZTg", + "name": "Bambu PETG @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu PETG@X-Plus 5-Series", + "pressure_advance": [ + "0.056" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..77014127cd --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "A3K4JfwyqUnciD2e", + "name": "Bambu PETG @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu PETG@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..3e95da1618 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Bambu PETG @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "4qjG4MYXmLPJ5Qjm", + "name": "Bambu PETG @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu PETG@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Bambu PETG @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/Bambu PETG @X-Plus 5.json new file mode 100644 index 0000000000..0a4d2ce22c --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Bambu PETG @X-Plus 5.json @@ -0,0 +1,102 @@ +{ + "type": "filament", + "filament_id": "GFG99", + "name": "Bambu PETG@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "40" + ], + "fan_min_speed": [ + "10" + ], + "filament_adhesiveness_category": [ + "300" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "13" + ], + "filament_type": [ + "PETG" + ], + "filament_vendor": [ + "Bambu Lab" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "nozzle_temperature_initial_layer": [ + "240" + ], + "nozzle_temperature_range_high": [ + "270" + ], + "nozzle_temperature_range_low": [ + "220" + ], + "nozzle_temperature": [ + "250" + ], + "overhang_fan_speed": [ + "90" + ], + "overhang_fan_threshold": [ + "10%" + ], + "pressure_advance": [ + "0.056" + ], + "slow_down_layer_time": [ + "8" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "supertack_plate_temp": [ + "60" + ], + "temperature_vitrification": [ + "70" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "textured_cool_plate_temp_initial_layer": [ + "60" + ], + "textured_cool_plate_temp": [ + "60" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..8cebbd7581 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "cI5eJwzwoecS97SU", + "name": "Bambu PLA @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu PLA@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.034" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..3e7d24cf85 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "UP5ST3BYA3nWaT5i", + "name": "Bambu PLA @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu PLA@X-Plus 5-Series", + "pressure_advance": [ + "0.034" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..e3e192d1e8 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "jSFJn0WmV76aBwPt", + "name": "Bambu PLA @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu PLA@X-Plus 5-Series", + "pressure_advance": [ + "0.016" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..2390355042 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Bambu PLA @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "MYCn1SS32p63RzX0", + "name": "Bambu PLA @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu PLA@X-Plus 5-Series", + "pressure_advance": [ + "0.008" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Bambu PLA @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/Bambu PLA @X-Plus 5.json new file mode 100644 index 0000000000..7660c8174d --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Bambu PLA @X-Plus 5.json @@ -0,0 +1,54 @@ +{ + "type": "filament", + "filament_id": "GFL99", + "name": "Bambu PLA@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "filament_adhesiveness_category": [ + "100" + ], + "filament_type": [ + "PLA" + ], + "filament_vendor": [ + "Bambu Lab" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_initial_layer": [ + "210" + ], + "nozzle_temperature": [ + "210" + ], + "overhang_fan_threshold": [ + "50%" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [], + "close_additional_fan_first_x_layers": [ + "1" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..c12bcc6687 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "xxRxeoAbiYJcH1P4", + "name": "Generic ABS @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic ABS@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..7807bc8420 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "MM6yfNPfpCtbsm2M", + "name": "Generic ABS @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic ABS@X-Plus 5-Series", + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..6de2b02613 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "BIiPt2AExUkASm2F", + "name": "Generic ABS @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic ABS@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "24.5" + ], + "pressure_advance": [ + "0.014" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..6e7bda8441 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic ABS @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "VzKqGnik79qlJ1bA", + "name": "Generic ABS @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic ABS@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "24.5" + ], + "pressure_advance": [ + "0.011" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic ABS @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/Generic ABS @X-Plus 5.json new file mode 100644 index 0000000000..4bb0cbe387 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic ABS @X-Plus 5.json @@ -0,0 +1,108 @@ +{ + "type": "filament", + "filament_id": "QD_4_0_11", + "name": "Generic ABS@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "eng_plate_temp": [ + "90" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "80" + ], + "fan_min_speed": [ + "10" + ], + "filament_adhesiveness_category": [ + "200" + ], + "filament_density": [ + "1.04" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "17" + ], + "filament_type": [ + "ABS" + ], + "filament_vendor": [ + "Generic" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "hot_plate_temp": [ + "90" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "250" + ], + "overhang_fan_speed": [ + "80" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.021" + ], + "slow_down_layer_time": [ + "4" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "textured_plate_temp": [ + "90" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..da5c50af1a --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,23 @@ +{ + "type": "filament", + "setting_id": "ERbh7DQQfK7A623W", + "name": "Generic PC @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PC@X-Plus 5-Series", + "filament_flow_ratio": [ + "0.94" + ], + "filament_max_volumetric_speed": [ + "1" + ], + "pressure_advance": [ + "0.04" + ], + "chamber_temperatures": [ + "0" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..487d8dd31d --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "MK8OyxUEziAeEbXk", + "name": "Generic PC @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PC@X-Plus 5-Series", + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "10" + ], + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..90829d6463 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "EQIfBmyVNumOKVWU", + "name": "Generic PC @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PC@X-Plus 5-Series", + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "10" + ], + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..514715f8a2 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PC @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "FsTuQT5hxmfjHyVZ", + "name": "Generic PC @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PC@X-Plus 5-Series", + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "10" + ], + "pressure_advance": [ + "0.008" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PC @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/Generic PC @X-Plus 5.json new file mode 100644 index 0000000000..360f0ee803 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PC @X-Plus 5.json @@ -0,0 +1,108 @@ +{ + "type": "filament", + "filament_id": "QD_4_0_23", + "name": "Generic PC@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "65" + ], + "chamber_temperatures": [ + "60" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "0" + ], + "cool_plate_temp": [ + "0" + ], + "eng_plate_temp_initial_layer": [ + "110" + ], + "eng_plate_temp": [ + "110" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "10" + ], + "filament_adhesiveness_category": [ + "500" + ], + "filament_density": [ + "1.04" + ], + "filament_max_volumetric_speed": [ + "10" + ], + "filament_type": [ + "PC" + ], + "filament_vendor": [ + "Generic" + ], + "hot_plate_temp_initial_layer": [ + "110" + ], + "hot_plate_temp": [ + "110" + ], + "nozzle_temperature_initial_layer": [ + "270" + ], + "nozzle_temperature_range_high": [ + "290" + ], + "nozzle_temperature_range_low": [ + "260" + ], + "nozzle_temperature": [ + "280" + ], + "overhang_fan_speed": [ + "60" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.021" + ], + "slow_down_layer_time": [ + "2" + ], + "supertack_plate_temp_initial_layer": [ + "0" + ], + "supertack_plate_temp": [ + "0" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "110" + ], + "textured_plate_temp": [ + "110" + ], + "textured_cool_plate_temp_initial_layer": [ + "0" + ], + "textured_cool_plate_temp": [ + "0" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..2b4e220a54 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "KaxkabCgu6EWZBzj", + "name": "Generic PETG @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PETG@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "1" + ], + "pressure_advance": [ + "0.056" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..4da60c3c48 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "ckqzES7LsTgYKKhb", + "name": "Generic PETG @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PETG@X-Plus 5-Series", + "pressure_advance": [ + "0.056" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..6f1b9667ab --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "1ID4LaQVZN4WjJ4v", + "name": "Generic PETG @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PETG@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..764e313efe --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PETG @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "yzkFoRA3R01K3lCa", + "name": "Generic PETG @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PETG@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PETG @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/Generic PETG @X-Plus 5.json new file mode 100644 index 0000000000..ab1b23bb60 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PETG @X-Plus 5.json @@ -0,0 +1,105 @@ +{ + "type": "filament", + "filament_id": "QD_4_0_41", + "name": "Generic PETG@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "90" + ], + "fan_min_speed": [ + "40" + ], + "filament_adhesiveness_category": [ + "300" + ], + "filament_density": [ + "1.27" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_type": [ + "PETG" + ], + "filament_vendor": [ + "Generic" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "nozzle_temperature_initial_layer": [ + "245" + ], + "nozzle_temperature_range_high": [ + "270" + ], + "nozzle_temperature_range_low": [ + "220" + ], + "nozzle_temperature": [ + "250" + ], + "overhang_fan_speed": [ + "90" + ], + "overhang_fan_threshold": [ + "10%" + ], + "pressure_advance": [ + "0.056" + ], + "slow_down_layer_time": [ + "12" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "supertack_plate_temp": [ + "60" + ], + "temperature_vitrification": [ + "70" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "textured_cool_plate_temp_initial_layer": [ + "60" + ], + "textured_cool_plate_temp": [ + "60" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..218b407d21 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "m5zUk3OpAayCbBwF", + "name": "Generic PLA @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PLA@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.034" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..c8dd22aba5 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "5Eorr9nKVhLbnYAZ", + "name": "Generic PLA @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PLA@X-Plus 5-Series", + "pressure_advance": [ + "0.034" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..ee352a5667 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "nqOawjrkU2lp3P0K", + "name": "Generic PLA @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PLA@X-Plus 5-Series", + "pressure_advance": [ + "0.016" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..14a7fa59c1 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PLA @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "nA20S71nTMCso0Bn", + "name": "Generic PLA @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PLA@X-Plus 5-Series", + "pressure_advance": [ + "0.008" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PLA @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/Generic PLA @X-Plus 5.json new file mode 100644 index 0000000000..e3939b7796 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PLA @X-Plus 5.json @@ -0,0 +1,66 @@ +{ + "type": "filament", + "filament_id": "QD_4_0_1", + "name": "Generic PLA@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "additional_cooling_fan_speed": [ + "100" + ], + "cool_plate_temp_initial_layer": [ + "45" + ], + "cool_plate_temp": [ + "45" + ], + "filament_adhesiveness_category": [ + "100" + ], + "filament_density": [ + "1.2" + ], + "filament_max_volumetric_speed": [ + "14" + ], + "filament_type": [ + "PLA" + ], + "filament_vendor": [ + "Generic" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature": [ + "220" + ], + "overhang_fan_threshold": [ + "50%" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [], + "close_additional_fan_first_x_layers": [ + "1" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PLA Silk @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PLA Silk @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..f701cf5b50 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PLA Silk @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "42feLKkUTBQTPNDm", + "name": "Generic PLA Silk @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PLA Silk@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PLA Silk @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PLA Silk @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..b898df762a --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PLA Silk @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "uyCmwBkoRNNRbG5R", + "name": "Generic PLA Silk @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PLA Silk@X-Plus 5-Series", + "pressure_advance": [ + "0.014" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PLA Silk @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/Generic PLA Silk @X-Plus 5.json new file mode 100644 index 0000000000..1c0d325a37 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PLA Silk @X-Plus 5.json @@ -0,0 +1,90 @@ +{ + "type": "filament", + "filament_id": "QD_4_0_4", + "name": "Generic PLA Silk@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "additional_cooling_fan_speed": [ + "100" + ], + "filament_adhesiveness_category": [ + "100" + ], + "filament_density": [ + "1.2" + ], + "filament_max_volumetric_speed": [ + "7.5" + ], + "filament_retraction_length": [ + "0.5" + ], + "filament_type": [ + "PLA" + ], + "filament_vendor": [ + "Generic" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature": [ + "220" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pressure_advance": [ + "0.032" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "cool_plate_temp_initial_layer": [ + "45" + ], + "cool_plate_temp": [ + "45" + ], + "eng_plate_temp_initial_layer": [ + "55" + ], + "eng_plate_temp": [ + "55" + ], + "hot_plate_temp_initial_layer": [ + "55" + ], + "hot_plate_temp": [ + "55" + ], + "textured_plate_temp_initial_layer": [ + "55" + ], + "textured_plate_temp": [ + "55" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [], + "close_additional_fan_first_x_layers": [ + "1" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..a7a736a95a --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "aD9SNuHAOxVFczNM", + "name": "Generic PLA+ @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PLA+@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.034" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..e10196f45c --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "QDAKF2VaO4MkiYZ7", + "name": "Generic PLA+ @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PLA+@X-Plus 5-Series", + "pressure_advance": [ + "0.034" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..62c8ce9de1 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "kNONALYQIZ8hkU2f", + "name": "Generic PLA+ @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PLA+@X-Plus 5-Series", + "pressure_advance": [ + "0.016" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..78599cb326 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PLA+ @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "ehm8mY40hPq6Bjby", + "name": "Generic PLA+ @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PLA+@X-Plus 5-Series", + "pressure_advance": [ + "0.008" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic PLA+ @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/Generic PLA+ @X-Plus 5.json new file mode 100644 index 0000000000..e1d40b179f --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic PLA+ @X-Plus 5.json @@ -0,0 +1,60 @@ +{ + "type": "filament", + "filament_id": "GFL99", + "name": "Generic PLA+@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "additional_cooling_fan_speed": [ + "100" + ], + "filament_adhesiveness_category": [ + "100" + ], + "filament_density": [ + "1.2" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_type": [ + "PLA" + ], + "filament_vendor": [ + "Generic" + ], + "nozzle_temperature_initial_layer": [ + "230" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature": [ + "230" + ], + "overhang_fan_threshold": [ + "50%" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [], + "close_additional_fan_first_x_layers": [ + "1" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic TPU 95A @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic TPU 95A @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..525652742c --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic TPU 95A @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "blCxzXDeplxz7FrS", + "name": "Generic TPU 95A @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic TPU 95A@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic TPU 95A @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic TPU 95A @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..f17a6e91e5 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic TPU 95A @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "mXwJpelMKlY7SQR8", + "name": "Generic TPU 95A @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic TPU 95A@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic TPU 95A @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/Generic TPU 95A @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..072983e488 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic TPU 95A @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "o9NLhClfpsJFEE3P", + "name": "Generic TPU 95A @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic TPU 95A@X-Plus 5-Series", + "nozzle_temperature": [ + "220" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Generic TPU 95A @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/Generic TPU 95A @X-Plus 5.json new file mode 100644 index 0000000000..d5f56d408b --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Generic TPU 95A @X-Plus 5.json @@ -0,0 +1,81 @@ +{ + "type": "filament", + "filament_id": "QD_4_0_50", + "name": "Generic TPU 95A@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "cool_plate_temp_initial_layer": [ + "30" + ], + "cool_plate_temp": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "35" + ], + "eng_plate_temp": [ + "35" + ], + "filament_adhesiveness_category": [ + "600" + ], + "filament_density": [ + "1.21" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "4" + ], + "filament_type": [ + "TPU" + ], + "filament_vendor": [ + "Generic" + ], + "hot_plate_temp_initial_layer": [ + "35" + ], + "hot_plate_temp": [ + "35" + ], + "nozzle_temperature_initial_layer": [ + "230" + ], + "nozzle_temperature_range_high": [ + "250" + ], + "nozzle_temperature_range_low": [ + "200" + ], + "nozzle_temperature": [ + "230" + ], + "pressure_advance": [ + "0.1" + ], + "supertack_plate_temp_initial_layer": [ + "30" + ], + "supertack_plate_temp": [ + "30" + ], + "temperature_vitrification": [ + "30" + ], + "textured_plate_temp_initial_layer": [ + "35" + ], + "textured_plate_temp": [ + "35" + ], + "textured_cool_plate_temp_initial_layer": [ + "30" + ], + "textured_cool_plate_temp": [ + "30" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..2346539b73 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "uarx8NrJerlKsoA8", + "name": "HATCHBOX ABS @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "HATCHBOX ABS@X-Plus 5-Series", + "chamber_temperatures": [ + "0" + ], + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..4566ece152 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "T52l6W0u1uoiXrAx", + "name": "HATCHBOX ABS @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "HATCHBOX ABS@X-Plus 5-Series", + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..bb16d32b06 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "krTIEBmeK9q2R60M", + "name": "HATCHBOX ABS @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "HATCHBOX ABS@X-Plus 5-Series", + "nozzle_temperature": [ + "250" + ], + "pressure_advance": [ + "0.014" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..19b4ce995f --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/HATCHBOX ABS @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "B99z7PiwClkWtyqv", + "name": "HATCHBOX ABS @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "HATCHBOX ABS@X-Plus 5-Series", + "nozzle_temperature": [ + "250" + ], + "pressure_advance": [ + "0.011" + ], + "slow_down_min_speed": [ + "10" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/HATCHBOX ABS @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/HATCHBOX ABS @X-Plus 5.json new file mode 100644 index 0000000000..3f5987240c --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/HATCHBOX ABS @X-Plus 5.json @@ -0,0 +1,105 @@ +{ + "type": "filament", + "filament_id": "GFB99", + "name": "HATCHBOX ABS@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "chamber_temperatures": [ + "55" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "eng_plate_temp": [ + "90" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_max_speed": [ + "80" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "200" + ], + "filament_density": [ + "1.05" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_type": [ + "ABS" + ], + "filament_vendor": [ + "HATCHBOX" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "hot_plate_temp": [ + "90" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "260" + ], + "overhang_fan_speed": [ + "80" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.035" + ], + "slow_down_layer_time": [ + "4" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "textured_plate_temp": [ + "90" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..dc87553374 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "2y03Jbrd8epf06MW", + "name": "HATCHBOX PETG @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "HATCHBOX PETG@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "1" + ], + "pressure_advance": [ + "0.056" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..21441a8d3e --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "KHbEUzPhVICXYhTs", + "name": "HATCHBOX PETG @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "HATCHBOX PETG@X-Plus 5-Series", + "pressure_advance": [ + "0.056" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..85219cea79 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "3HPxSQqEM8XGZqgU", + "name": "HATCHBOX PETG @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "HATCHBOX PETG@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..c6b4b699cd --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/HATCHBOX PETG @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "eZnTfUmPGkeoEP87", + "name": "HATCHBOX PETG @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "HATCHBOX PETG@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/HATCHBOX PETG @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/HATCHBOX PETG @X-Plus 5.json new file mode 100644 index 0000000000..5f794e561c --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/HATCHBOX PETG @X-Plus 5.json @@ -0,0 +1,102 @@ +{ + "type": "filament", + "filament_id": "GFG99", + "name": "HATCHBOX PETG@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "40" + ], + "fan_min_speed": [ + "10" + ], + "filament_adhesiveness_category": [ + "300" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "13" + ], + "filament_type": [ + "PETG" + ], + "filament_vendor": [ + "HATCHBOX" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "nozzle_temperature_initial_layer": [ + "240" + ], + "nozzle_temperature_range_high": [ + "270" + ], + "nozzle_temperature_range_low": [ + "220" + ], + "nozzle_temperature": [ + "250" + ], + "overhang_fan_speed": [ + "90" + ], + "overhang_fan_threshold": [ + "10%" + ], + "pressure_advance": [ + "0.056" + ], + "slow_down_layer_time": [ + "8" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "supertack_plate_temp": [ + "60" + ], + "temperature_vitrification": [ + "70" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "textured_cool_plate_temp_initial_layer": [ + "60" + ], + "textured_cool_plate_temp": [ + "60" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..a1838c2041 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "Sn0LAKII01kQONZS", + "name": "HATCHBOX PLA @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "HATCHBOX PLA@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.034" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..82e54e389e --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "HWmejqWfehK4LG6C", + "name": "HATCHBOX PLA @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "HATCHBOX PLA@X-Plus 5-Series", + "pressure_advance": [ + "0.034" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..d6ac4c9a7e --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "zjIVoA34wN8AT6cp", + "name": "HATCHBOX PLA @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "HATCHBOX PLA@X-Plus 5-Series", + "pressure_advance": [ + "0.016" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..5b89e541e3 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/HATCHBOX PLA @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "sTjweBRTvE0P6YtE", + "name": "HATCHBOX PLA @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "HATCHBOX PLA@X-Plus 5-Series", + "pressure_advance": [ + "0.008" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/HATCHBOX PLA @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/HATCHBOX PLA @X-Plus 5.json new file mode 100644 index 0000000000..094e540793 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/HATCHBOX PLA @X-Plus 5.json @@ -0,0 +1,54 @@ +{ + "type": "filament", + "filament_id": "GFL99", + "name": "HATCHBOX PLA@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "filament_adhesiveness_category": [ + "100" + ], + "filament_type": [ + "PLA" + ], + "filament_vendor": [ + "HATCHBOX" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_initial_layer": [ + "210" + ], + "nozzle_temperature": [ + "210" + ], + "overhang_fan_threshold": [ + "50%" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [], + "close_additional_fan_first_x_layers": [ + "1" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..7194b54b7f --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "tLj2E2dWAdLKpC4K", + "name": "Overture ABS @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Overture ABS@X-Plus 5-Series", + "chamber_temperatures": [ + "0" + ], + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.054" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..5e50aa5dbc --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "1IkBG0ywAkk3VhOd", + "name": "Overture ABS @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Overture ABS@X-Plus 5-Series", + "pressure_advance": [ + "0.033" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..9bacef9d3a --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "4SXA27uTG5kcbnAq", + "name": "Overture ABS @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Overture ABS@X-Plus 5-Series", + "pressure_advance": [ + "0.02" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..a53148ed26 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Overture ABS @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "AzC8XjbkzsxEPDMG", + "name": "Overture ABS @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Overture ABS@X-Plus 5-Series", + "pressure_advance": [ + "0.01" + ], + "slow_down_min_speed": [ + "10" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Overture ABS @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/Overture ABS @X-Plus 5.json new file mode 100644 index 0000000000..ea12b78ead --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Overture ABS @X-Plus 5.json @@ -0,0 +1,108 @@ +{ + "type": "filament", + "filament_id": "GFB99", + "name": "Overture ABS@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "chamber_temperatures": [ + "60" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "eng_plate_temp": [ + "90" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_max_speed": [ + "80" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "200" + ], + "filament_density": [ + "1.12" + ], + "filament_flow_ratio": [ + "0.96" + ], + "filament_max_volumetric_speed": [ + "17" + ], + "filament_type": [ + "ABS" + ], + "filament_vendor": [ + "Overture" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "hot_plate_temp": [ + "90" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "255" + ], + "overhang_fan_speed": [ + "80" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.033" + ], + "slow_down_layer_time": [ + "6" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "textured_plate_temp": [ + "90" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..f209b21a6e --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "2TAd2Dlk6KPvvmMg", + "name": "Overture PLA @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Overture PLA@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.062" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..a625953f60 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "1rKASIobH0DqQUeH", + "name": "Overture PLA @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Overture PLA@X-Plus 5-Series", + "pressure_advance": [ + "0.037" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..5a3dfdee8f --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "UWQ7bLf74AxEPDdc", + "name": "Overture PLA @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Overture PLA@X-Plus 5-Series", + "pressure_advance": [ + "0.019" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..86d8605933 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Overture PLA @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "bIg1NW0EwTlmRNAF", + "name": "Overture PLA @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Overture PLA@X-Plus 5-Series", + "pressure_advance": [ + "0.012" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Overture PLA @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/Overture PLA @X-Plus 5.json new file mode 100644 index 0000000000..571eb2bbeb --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Overture PLA @X-Plus 5.json @@ -0,0 +1,66 @@ +{ + "type": "filament", + "filament_id": "GFL99", + "name": "Overture PLA@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "filament_adhesiveness_category": [ + "100" + ], + "filament_density": [ + "1.2" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "11" + ], + "filament_type": [ + "PLA" + ], + "filament_vendor": [ + "Overture" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_initial_layer": [ + "210" + ], + "nozzle_temperature": [ + "210" + ], + "overhang_fan_threshold": [ + "50%" + ], + "slow_down_layer_time": [ + "10" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [], + "close_additional_fan_first_x_layers": [ + "1" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..0618d3c36f --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "AJYooe7fIzg43McT", + "name": "PolyLite ABS @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "PolyLite ABS@X-Plus 5-Series", + "chamber_temperatures": [ + "0" + ], + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.054" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..36e012b0d6 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "S0uCyMruXw5waEYf", + "name": "PolyLite ABS @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "PolyLite ABS@X-Plus 5-Series", + "pressure_advance": [ + "0.033" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..1bf7cdf030 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "oYlfF3MMF5DEeJpK", + "name": "PolyLite ABS @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "PolyLite ABS@X-Plus 5-Series", + "pressure_advance": [ + "0.02" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..9d1f541dfc --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/PolyLite ABS @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "hHXz74Ps9x4T7kZl", + "name": "PolyLite ABS @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "PolyLite ABS@X-Plus 5-Series", + "pressure_advance": [ + "0.01" + ], + "slow_down_min_speed": [ + "10" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/PolyLite ABS @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/PolyLite ABS @X-Plus 5.json new file mode 100644 index 0000000000..48b6caa32b --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/PolyLite ABS @X-Plus 5.json @@ -0,0 +1,108 @@ +{ + "type": "filament", + "filament_id": "GFB99", + "name": "PolyLite ABS@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "chamber_temperatures": [ + "60" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "eng_plate_temp": [ + "90" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_max_speed": [ + "80" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "200" + ], + "filament_density": [ + "1.12" + ], + "filament_flow_ratio": [ + "0.96" + ], + "filament_max_volumetric_speed": [ + "17" + ], + "filament_type": [ + "ABS" + ], + "filament_vendor": [ + "Polymaker" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "hot_plate_temp": [ + "90" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "255" + ], + "overhang_fan_speed": [ + "80" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.033" + ], + "slow_down_layer_time": [ + "6" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "textured_plate_temp": [ + "90" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..f823b38e67 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "kKfybaeH6Llb3Vdc", + "name": "PolyLite PLA @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "PolyLite PLA@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.062" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..b7f3ef07f6 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "hzEsCxIKwuV2ubrz", + "name": "PolyLite PLA @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "PolyLite PLA@X-Plus 5-Series", + "pressure_advance": [ + "0.037" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..8b98d3842a --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "PODs7XKIgMiJZI5x", + "name": "PolyLite PLA @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "PolyLite PLA@X-Plus 5-Series", + "pressure_advance": [ + "0.019" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..f4b6b8c2ee --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/PolyLite PLA @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "LQ1rP7NSTjw2moHk", + "name": "PolyLite PLA @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "PolyLite PLA@X-Plus 5-Series", + "pressure_advance": [ + "0.012" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/PolyLite PLA @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/PolyLite PLA @X-Plus 5.json new file mode 100644 index 0000000000..5b37f7ae8a --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/PolyLite PLA @X-Plus 5.json @@ -0,0 +1,66 @@ +{ + "type": "filament", + "filament_id": "GFL99", + "name": "PolyLite PLA@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "filament_adhesiveness_category": [ + "100" + ], + "filament_density": [ + "1.2" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "11" + ], + "filament_type": [ + "PLA" + ], + "filament_vendor": [ + "Polymaker" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_initial_layer": [ + "210" + ], + "nozzle_temperature": [ + "210" + ], + "overhang_fan_threshold": [ + "50%" + ], + "slow_down_layer_time": [ + "10" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [], + "close_additional_fan_first_x_layers": [ + "1" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..78389ceeb5 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "p9cDXBgbjwjOX5me", + "name": "Polymaker PLA-HT @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Polymaker PLA-HT@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.062" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..9f77b41119 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "TpI2jqmcVygyTO8N", + "name": "Polymaker PLA-HT @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Polymaker PLA-HT@X-Plus 5-Series", + "pressure_advance": [ + "0.037" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..3c46385369 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "69AgpjCCTxF5ffW1", + "name": "Polymaker PLA-HT @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Polymaker PLA-HT@X-Plus 5-Series", + "pressure_advance": [ + "0.019" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..788db83504 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "tcoQNICpWYGdE24e", + "name": "Polymaker PLA-HT @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Polymaker PLA-HT@X-Plus 5-Series", + "pressure_advance": [ + "0.012" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @X-Plus 5.json new file mode 100644 index 0000000000..f3c54e81f1 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/Polymaker PLA-HT @X-Plus 5.json @@ -0,0 +1,66 @@ +{ + "type": "filament", + "filament_id": "GFL99", + "name": "Polymaker PLA-HT@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "filament_adhesiveness_category": [ + "100" + ], + "filament_density": [ + "1.2" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "11" + ], + "filament_type": [ + "PLA" + ], + "filament_vendor": [ + "Polymaker" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature": [ + "215" + ], + "overhang_fan_threshold": [ + "50%" + ], + "slow_down_layer_time": [ + "10" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [], + "close_additional_fan_first_x_layers": [ + "1" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..254422bb19 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "8SvrXXv743rCyyeN", + "name": "QIDI ABS Odorless @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ABS Odorless@X-Plus 5-Series", + "chamber_temperatures": [ + "0" + ], + "pressure_advance": [ + "0.03" + ], + "filament_max_volumetric_speed": [ + "2" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..1bd37ac08a --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "YviPsfkGYv6Q3r3T", + "name": "QIDI ABS Odorless @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ABS Odorless@X-Plus 5-Series", + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..cbb361fb9c --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "YLOcbaCppSmQ1twv", + "name": "QIDI ABS Odorless @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ABS Odorless@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "24.5" + ], + "nozzle_temperature": [ + "250" + ], + "pressure_advance": [ + "0.014" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..912dc04ed7 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,23 @@ +{ + "type": "filament", + "setting_id": "Klsu6iALsWgbg3vK", + "name": "QIDI ABS Odorless @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ABS Odorless@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "24.5" + ], + "nozzle_temperature": [ + "250" + ], + "pressure_advance": [ + "0.011" + ], + "slow_down_min_speed": [ + "10" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @X-Plus 5.json new file mode 100644 index 0000000000..a2f14984a0 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS Odorless @X-Plus 5.json @@ -0,0 +1,108 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_14", + "name": "QIDI ABS Odorless@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "chamber_temperatures": [ + "55" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "eng_plate_temp": [ + "90" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_max_speed": [ + "80" + ], + "fan_min_speed": [ + "10" + ], + "filament_adhesiveness_category": [ + "200" + ], + "filament_density": [ + "1.02" + ], + "filament_flow_ratio": [ + "0.92" + ], + "filament_max_volumetric_speed": [ + "22" + ], + "filament_type": [ + "ABS" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "hot_plate_temp": [ + "90" + ], + "impact_strength_z": [ + "7.4" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "260" + ], + "overhang_fan_speed": [ + "80" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.035" + ], + "slow_down_layer_time": [ + "4" + ], + "temperature_vitrification": [ + "100" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "textured_plate_temp": [ + "90" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..99a9e16c08 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "bTwNiMSHwex0gxrd", + "name": "QIDI ABS Rapido @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ABS Rapido@X-Plus 5-Series", + "chamber_temperatures": [ + "0" + ], + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..30086f5dce --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "mcPlHcr33zPv3aIf", + "name": "QIDI ABS Rapido @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ABS Rapido@X-Plus 5-Series", + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..47278a61b1 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "0np334pRpl3qa8Uq", + "name": "QIDI ABS Rapido @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ABS Rapido@X-Plus 5-Series", + "nozzle_temperature": [ + "250" + ], + "pressure_advance": [ + "0.014" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..f79fcfdfac --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "Vp2bJxFhsPvW6K0P", + "name": "QIDI ABS Rapido @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ABS Rapido@X-Plus 5-Series", + "nozzle_temperature": [ + "250" + ], + "pressure_advance": [ + "0.011" + ], + "slow_down_min_speed": [ + "10" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @X-Plus 5.json new file mode 100644 index 0000000000..0ecb9c656c --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido @X-Plus 5.json @@ -0,0 +1,105 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_11", + "name": "QIDI ABS Rapido@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "chamber_temperatures": [ + "55" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "eng_plate_temp": [ + "90" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_max_speed": [ + "80" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "200" + ], + "filament_density": [ + "1.05" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_type": [ + "ABS" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "hot_plate_temp": [ + "90" + ], + "impact_strength_z": [ + "7.4" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "260" + ], + "overhang_fan_speed": [ + "80" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.035" + ], + "slow_down_layer_time": [ + "4" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "textured_plate_temp": [ + "90" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..34632b393f --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "U69dFGlkEk9twDF6", + "name": "QIDI ABS Rapido Metal @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ABS Rapido Metal@X-Plus 5-Series", + "chamber_temperatures": [ + "0" + ], + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..59492201a5 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "XaJbATawtVrUsXpz", + "name": "QIDI ABS Rapido Metal @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ABS Rapido Metal@X-Plus 5-Series", + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..93b4cb3aba --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "Xb0A7YqmqP2peSM3", + "name": "QIDI ABS Rapido Metal @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ABS Rapido Metal@X-Plus 5-Series", + "nozzle_temperature": [ + "250" + ], + "pressure_advance": [ + "0.016" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..c4edce73be --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "4AA9wGDNebbTHf4X", + "name": "QIDI ABS Rapido Metal @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ABS Rapido Metal@X-Plus 5-Series", + "nozzle_temperature": [ + "250" + ], + "pressure_advance": [ + "0.008" + ], + "slow_down_min_speed": [ + "10" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @X-Plus 5.json new file mode 100644 index 0000000000..f3603eda99 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS Rapido Metal @X-Plus 5.json @@ -0,0 +1,105 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_13", + "name": "QIDI ABS Rapido Metal@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "chamber_temperatures": [ + "55" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "eng_plate_temp": [ + "90" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_max_speed": [ + "80" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "200" + ], + "filament_density": [ + "1.06" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_type": [ + "ABS" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "hot_plate_temp": [ + "90" + ], + "impact_strength_z": [ + "7.4" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "260" + ], + "overhang_fan_speed": [ + "80" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.035" + ], + "slow_down_layer_time": [ + "4" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "textured_plate_temp": [ + "90" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS-GF @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ABS-GF @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..d81d623d33 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS-GF @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "V9h7YWcaTejmFCh0", + "name": "QIDI ABS-GF @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ABS-GF@X-Plus 5-Series", + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS-GF @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ABS-GF @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..88ee5f2146 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS-GF @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "hO8H1GUCzMkwFtQH", + "name": "QIDI ABS-GF @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ABS-GF@X-Plus 5-Series", + "pressure_advance": [ + "0.01" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS-GF @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ABS-GF @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..997e67a0f0 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS-GF @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "LskHdeEngKlRCSmg", + "name": "QIDI ABS-GF @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ABS-GF@X-Plus 5-Series", + "pressure_advance": [ + "0.01" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ABS-GF @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI ABS-GF @X-Plus 5.json new file mode 100644 index 0000000000..2ab2fbfc84 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ABS-GF @X-Plus 5.json @@ -0,0 +1,114 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_12", + "name": "QIDI ABS-GF@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "box_temperature_range_low": [ + "0" + ], + "box_temperature": [ + "45" + ], + "chamber_temperatures": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "eng_plate_temp": [ + "90" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_max_speed": [ + "20" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "200" + ], + "filament_density": [ + "1.15" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_type": [ + "ABS-GF" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "hot_plate_temp": [ + "90" + ], + "impact_strength_z": [ + "5.3" + ], + "nozzle_temperature_initial_layer": [ + "260" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "270" + ], + "overhang_fan_speed": [ + "80" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.035" + ], + "slow_down_layer_time": [ + "5" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "textured_plate_temp": [ + "90" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..d417265f5a --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "FgeIGgT8xZCm4UO8", + "name": "QIDI ASA @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ASA@X-Plus 5-Series", + "chamber_temperatures": [ + "0" + ], + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..ed86d714a1 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "VRicNQizOCKkgLBJ", + "name": "QIDI ASA @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ASA@X-Plus 5-Series", + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..a7870accce --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "KDjln7WdhhbSztX3", + "name": "QIDI ASA @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ASA@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "13" + ], + "pressure_advance": [ + "0.014" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..30496917d1 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ASA @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "X9TOBuOKBbJIoF7y", + "name": "QIDI ASA @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ASA@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "13" + ], + "pressure_advance": [ + "0.011" + ], + "slow_down_min_speed": [ + "10" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ASA @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI ASA @X-Plus 5.json new file mode 100644 index 0000000000..97127fe57b --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ASA @X-Plus 5.json @@ -0,0 +1,111 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_18", + "name": "QIDI ASA@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "chamber_temperatures": [ + "55" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "eng_plate_temp": [ + "90" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_cooling_layer_time": [ + "40" + ], + "fan_max_speed": [ + "50" + ], + "fan_min_speed": [ + "10" + ], + "filament_adhesiveness_category": [ + "200" + ], + "filament_density": [ + "1.07" + ], + "filament_flow_ratio": [ + "0.92" + ], + "filament_max_volumetric_speed": [ + "16" + ], + "filament_type": [ + "ASA" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "hot_plate_temp": [ + "90" + ], + "impact_strength_z": [ + "4.9" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "255" + ], + "overhang_fan_speed": [ + "80" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.035" + ], + "slow_down_layer_time": [ + "4" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "textured_plate_temp": [ + "90" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ASA-Aero @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ASA-Aero @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..08a4ed22a9 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ASA-Aero @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "g5F7NP83yx0Iub4c", + "name": "QIDI ASA-Aero @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ASA-Aero@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ASA-Aero @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI ASA-Aero @X-Plus 5.json new file mode 100644 index 0000000000..14423fd58c --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ASA-Aero @X-Plus 5.json @@ -0,0 +1,126 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_19", + "name": "QIDI ASA-Aero@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "chamber_temperatures": [ + "60" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "eng_plate_temp": [ + "90" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_cooling_layer_time": [ + "40" + ], + "fan_max_speed": [ + "50" + ], + "fan_min_speed": [ + "10" + ], + "filament_adhesiveness_category": [ + "200" + ], + "filament_density": [ + "1.03" + ], + "filament_flow_ratio": [ + "0.7" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_retract_when_changing_layer": [ + "0" + ], + "filament_retraction_length": [ + "0.01" + ], + "filament_retraction_minimum_travel": [ + "0" + ], + "filament_type": [ + "ASA-AERO" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "hot_plate_temp": [ + "90" + ], + "filament_wipe": [ + "0" + ], + "filament_z_hop": [ + "0" + ], + "impact_strength_z": [ + "3.4" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "260" + ], + "overhang_fan_speed": [ + "80" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.021" + ], + "slow_down_layer_time": [ + "4" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "textured_plate_temp": [ + "90" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ASA-CF @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ASA-CF @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..be97fdfd58 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ASA-CF @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "Aqh00EJ8ZaiPCU6F", + "name": "QIDI ASA-CF @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ASA-CF@X-Plus 5-Series", + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ASA-CF @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ASA-CF @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..cd8bbc98bd --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ASA-CF @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "fgwkL5igRvM0leJf", + "name": "QIDI ASA-CF @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ASA-CF@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "13" + ], + "pressure_advance": [ + "0.014" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ASA-CF @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI ASA-CF @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..3095a16138 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ASA-CF @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "bDAcTzwdiXT4fFnT", + "name": "QIDI ASA-CF @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI ASA-CF@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "13" + ], + "pressure_advance": [ + "0.011" + ], + "slow_down_min_speed": [ + "10" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI ASA-CF @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI ASA-CF @X-Plus 5.json new file mode 100644 index 0000000000..9a8958c860 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI ASA-CF @X-Plus 5.json @@ -0,0 +1,111 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_20", + "name": "QIDI ASA-CF@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "chamber_temperatures": [ + "55" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "eng_plate_temp": [ + "90" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_cooling_layer_time": [ + "35" + ], + "fan_max_speed": [ + "25" + ], + "fan_min_speed": [ + "10" + ], + "filament_adhesiveness_category": [ + "200" + ], + "filament_density": [ + "1.07" + ], + "filament_flow_ratio": [ + "0.9" + ], + "filament_max_volumetric_speed": [ + "18" + ], + "filament_type": [ + "ASA-CF" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "hot_plate_temp": [ + "90" + ], + "impact_strength_z": [ + "4.9" + ], + "nozzle_temperature_initial_layer": [ + "275" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "260" + ], + "nozzle_temperature": [ + "275" + ], + "overhang_fan_speed": [ + "80" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.03" + ], + "slow_down_layer_time": [ + "12" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "textured_plate_temp": [ + "90" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PA12-CF @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PA12-CF @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..165c5cfb62 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PA12-CF @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "vDXAb7Kkj7nFc8go", + "name": "QIDI PA12-CF @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PA12-CF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PA12-CF @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PA12-CF @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..ad26af1f86 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PA12-CF @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "KjZ3jgo2Zoklkk0F", + "name": "QIDI PA12-CF @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PA12-CF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PA12-CF @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PA12-CF @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..5324f0c183 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PA12-CF @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "Xcl3UPe7tmXw9hXa", + "name": "QIDI PA12-CF @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PA12-CF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PA12-CF @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PA12-CF @X-Plus 5.json new file mode 100644 index 0000000000..3464bed9a3 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PA12-CF @X-Plus 5.json @@ -0,0 +1,111 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_27", + "name": "QIDI PA12-CF@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "65" + ], + "box_temperature_range_low": [ + "0" + ], + "box_temperature": [ + "55" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "10" + ], + "fan_max_speed": [ + "40" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "400" + ], + "filament_density": [ + "1.09" + ], + "filament_flow_ratio": [ + "0.96" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_type": [ + "PA12-CF" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "5.7" + ], + "nozzle_temperature_initial_layer": [ + "280" + ], + "nozzle_temperature_range_high": [ + "300" + ], + "nozzle_temperature_range_low": [ + "280" + ], + "nozzle_temperature": [ + "280" + ], + "overhang_fan_speed": [ + "40" + ], + "overhang_fan_threshold": [ + "0%" + ], + "pressure_advance": [ + "0.035" + ], + "slow_down_layer_time": [ + "5" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "supertack_plate_temp": [ + "60" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "textured_cool_plate_temp_initial_layer": [ + "60" + ], + "textured_cool_plate_temp": [ + "60" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PA6-CF @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PA6-CF @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..fbe5870078 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PA6-CF @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "qTjsP8oR1sbh56Gh", + "name": "QIDI PA6-CF @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PA6-CF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PA6-CF @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PA6-CF @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..016f9bb2e4 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PA6-CF @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "4kzkdzJmDYGic0aa", + "name": "QIDI PA6-CF @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PA6-CF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PA6-CF @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PA6-CF @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..ba0d981c29 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PA6-CF @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "97peVPSildpjdDQj", + "name": "QIDI PA6-CF @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PA6-CF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PA6-CF @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PA6-CF @X-Plus 5.json new file mode 100644 index 0000000000..9b6a66f61b --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PA6-CF @X-Plus 5.json @@ -0,0 +1,111 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_25", + "name": "QIDI PA6-CF@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "65" + ], + "box_temperature_range_low": [ + "0" + ], + "box_temperature": [ + "55" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "10" + ], + "fan_max_speed": [ + "40" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "400" + ], + "filament_density": [ + "1.09" + ], + "filament_flow_ratio": [ + "0.96" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_type": [ + "PA6-CF" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "5.7" + ], + "nozzle_temperature_initial_layer": [ + "280" + ], + "nozzle_temperature_range_high": [ + "300" + ], + "nozzle_temperature_range_low": [ + "280" + ], + "nozzle_temperature": [ + "280" + ], + "overhang_fan_speed": [ + "40" + ], + "overhang_fan_threshold": [ + "0%" + ], + "pressure_advance": [ + "0.035" + ], + "slow_down_layer_time": [ + "5" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "supertack_plate_temp": [ + "60" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "textured_cool_plate_temp_initial_layer": [ + "60" + ], + "textured_cool_plate_temp": [ + "60" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..68d604414d --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "3iw5hq0KFa9NU4b3", + "name": "QIDI PAHT-CF @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PAHT-CF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..0ca7290e39 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "7eBDjJbetxOC3aNT", + "name": "QIDI PAHT-CF @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PAHT-CF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..b3b88d5f28 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "hkIpB0QZOGZpoYFX", + "name": "QIDI PAHT-CF @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PAHT-CF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @X-Plus 5.json new file mode 100644 index 0000000000..fcfccfe0f6 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PAHT-CF @X-Plus 5.json @@ -0,0 +1,111 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_30", + "name": "QIDI PAHT-CF@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "65" + ], + "box_temperature_range_low": [ + "0" + ], + "box_temperature": [ + "60" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "10" + ], + "fan_max_speed": [ + "40" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "400" + ], + "filament_density": [ + "1.2" + ], + "filament_flow_ratio": [ + "0.96" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_type": [ + "PAHT-CF" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "13.3" + ], + "nozzle_temperature_initial_layer": [ + "300" + ], + "nozzle_temperature_range_high": [ + "320" + ], + "nozzle_temperature_range_low": [ + "300" + ], + "nozzle_temperature": [ + "300" + ], + "overhang_fan_speed": [ + "40" + ], + "overhang_fan_threshold": [ + "0%" + ], + "pressure_advance": [ + "0.032" + ], + "slow_down_layer_time": [ + "5" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "temperature_vitrification": [ + "180" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..9638d33afc --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "R7cctkITobdKgMkY", + "name": "QIDI PAHT-GF @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PAHT-GF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..4d926ff370 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "cVzpHjaSzsDm0bwG", + "name": "QIDI PAHT-GF @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PAHT-GF@X-Plus 5-Series", + "pressure_advance": [ + "0.015" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..ce49e3ef04 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "N0aUkpcJD6CvODci", + "name": "QIDI PAHT-GF @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PAHT-GF@X-Plus 5-Series", + "pressure_advance": [ + "0.01" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @X-Plus 5.json new file mode 100644 index 0000000000..3c0f1056ed --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PAHT-GF @X-Plus 5.json @@ -0,0 +1,111 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_31", + "name": "QIDI PAHT-GF@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "65" + ], + "box_temperature_range_low": [ + "0" + ], + "box_temperature": [ + "60" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "10" + ], + "fan_max_speed": [ + "20" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "400" + ], + "filament_density": [ + "1.27" + ], + "filament_flow_ratio": [ + "0.96" + ], + "filament_max_volumetric_speed": [ + "10" + ], + "filament_type": [ + "PAHT-GF" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "13.3" + ], + "nozzle_temperature_initial_layer": [ + "300" + ], + "nozzle_temperature_range_high": [ + "320" + ], + "nozzle_temperature_range_low": [ + "300" + ], + "nozzle_temperature": [ + "300" + ], + "overhang_fan_speed": [ + "40" + ], + "overhang_fan_threshold": [ + "0%" + ], + "pressure_advance": [ + "0.027" + ], + "slow_down_layer_time": [ + "5" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "temperature_vitrification": [ + "180" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..e4842206ed --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "uYwbMiemSo7LxiqR", + "name": "QIDI PC/ABS-FR @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PC/ABS-FR@X-Plus 5-Series", + "pressure_advance": [ + "0.042" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..35c317e8d3 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "Fxkv0PN8RU17fkB0", + "name": "QIDI PC/ABS-FR @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PC/ABS-FR@X-Plus 5-Series", + "pressure_advance": [ + "0.031" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..456a93a6d0 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "oKNGzYqymTnWQsBB", + "name": "QIDI PC/ABS-FR @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PC/ABS-FR@X-Plus 5-Series", + "pressure_advance": [ + "0.024" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @X-Plus 5.json new file mode 100644 index 0000000000..b6c6fb3b64 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PC-ABS-FR @X-Plus 5.json @@ -0,0 +1,111 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_34", + "name": "QIDI PC/ABS-FR@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "50" + ], + "chamber_temperatures": [ + "55" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "65" + ], + "cool_plate_temp": [ + "65" + ], + "eng_plate_temp_initial_layer": [ + "100" + ], + "eng_plate_temp": [ + "100" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "40" + ], + "fan_min_speed": [ + "10" + ], + "filament_adhesiveness_category": [ + "200" + ], + "filament_density": [ + "1.19" + ], + "filament_flow_ratio": [ + "0.92" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_type": [ + "PC-ABS-FR" + ], + "hot_plate_temp_initial_layer": [ + "100" + ], + "hot_plate_temp": [ + "100" + ], + "impact_strength_z": [ + "8" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "250" + ], + "overhang_fan_speed": [ + "90" + ], + "overhang_fan_threshold": [ + "75%" + ], + "pressure_advance": [ + "0.082" + ], + "slow_down_layer_time": [ + "4" + ], + "supertack_plate_temp_initial_layer": [ + "65" + ], + "supertack_plate_temp": [ + "65" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "100" + ], + "textured_plate_temp": [ + "100" + ], + "textured_cool_plate_temp_initial_layer": [ + "65" + ], + "textured_cool_plate_temp": [ + "65" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PEBA 95A @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PEBA 95A @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..5fa07706a9 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PEBA 95A @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "hgdi1oL4EFzh0h7h", + "name": "QIDI PEBA 95A @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PEBA 95A@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PEBA 95A @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PEBA 95A @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..f44261951e --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PEBA 95A @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "iNZpBz1iklW3sJlj", + "name": "QIDI PEBA 95A @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PEBA 95A@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PEBA 95A @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PEBA 95A @X-Plus 5.json new file mode 100644 index 0000000000..43410eabe1 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PEBA 95A @X-Plus 5.json @@ -0,0 +1,96 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_36", + "name": "QIDI PEBA 95A@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "cool_plate_temp_initial_layer": [ + "30" + ], + "cool_plate_temp": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "35" + ], + "eng_plate_temp": [ + "35" + ], + "fan_cooling_layer_time": [ + "100" + ], + "filament_adhesiveness_category": [ + "600" + ], + "filament_density": [ + "1.15" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "6" + ], + "filament_retraction_length": [ + "0.8" + ], + "filament_type": [ + "PEBA" + ], + "filament_vendor": [ + "QIDI" + ], + "filament_z_hop": [ + "0" + ], + "hot_plate_temp_initial_layer": [ + "35" + ], + "hot_plate_temp": [ + "35" + ], + "impact_strength_z": [ + "88.7" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "260" + ], + "nozzle_temperature_range_low": [ + "230" + ], + "nozzle_temperature": [ + "250" + ], + "pressure_advance": [ + "0.04" + ], + "slow_down_layer_time": [ + "14" + ], + "supertack_plate_temp_initial_layer": [ + "30" + ], + "supertack_plate_temp": [ + "30" + ], + "temperature_vitrification": [ + "30" + ], + "textured_plate_temp_initial_layer": [ + "35" + ], + "textured_plate_temp": [ + "35" + ], + "textured_cool_plate_temp_initial_layer": [ + "30" + ], + "textured_cool_plate_temp": [ + "30" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PET-CF @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PET-CF @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..bfdd1aed31 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PET-CF @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "bILtWMlzBPi4Ft8a", + "name": "QIDI PET-CF @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PET-CF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PET-CF @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PET-CF @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..cb78cf3afc --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PET-CF @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "E0Y6g3qpoERrgSUH", + "name": "QIDI PET-CF @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PET-CF@X-Plus 5-Series", + "pressure_advance": [ + "0.025" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PET-CF @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PET-CF @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..ae40d594ff --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PET-CF @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "e2HuHVJZck2nKANa", + "name": "QIDI PET-CF @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PET-CF@X-Plus 5-Series", + "pressure_advance": [ + "0.025" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PET-CF @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PET-CF @X-Plus 5.json new file mode 100644 index 0000000000..162cbec691 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PET-CF @X-Plus 5.json @@ -0,0 +1,111 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_37", + "name": "QIDI PET-CF@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "65" + ], + "box_temperature_range_low": [ + "0" + ], + "box_temperature": [ + "55" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "70" + ], + "cool_plate_temp": [ + "70" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "10" + ], + "fan_max_speed": [ + "40" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "800" + ], + "filament_density": [ + "1.3" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_type": [ + "PET-CF" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "4.5" + ], + "nozzle_temperature_initial_layer": [ + "280" + ], + "nozzle_temperature_range_high": [ + "320" + ], + "nozzle_temperature_range_low": [ + "280" + ], + "nozzle_temperature": [ + "280" + ], + "overhang_fan_speed": [ + "40" + ], + "overhang_fan_threshold": [ + "0%" + ], + "pressure_advance": [ + "0.032" + ], + "slow_down_layer_time": [ + "5" + ], + "temperature_vitrification": [ + "185" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "supertack_plate_temp_initial_layer": [ + "70" + ], + "supertack_plate_temp": [ + "70" + ], + "textured_cool_plate_temp_initial_layer": [ + "70" + ], + "textured_cool_plate_temp": [ + "70" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PET-GF @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PET-GF @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..97029aeb25 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PET-GF @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "2NHbKFmgDoN1oHlo", + "name": "QIDI PET-GF @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PET-GF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PET-GF @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PET-GF @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..480d13bb65 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PET-GF @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "cMlzOMKIIIro4H62", + "name": "QIDI PET-GF @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PET-GF@X-Plus 5-Series", + "pressure_advance": [ + "0.014" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PET-GF @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PET-GF @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..2cc0cfe2cb --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PET-GF @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "evxG7nCDQx2Y5UV5", + "name": "QIDI PET-GF @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PET-GF@X-Plus 5-Series", + "pressure_advance": [ + "0.01" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PET-GF @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PET-GF @X-Plus 5.json new file mode 100644 index 0000000000..84310856cc --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PET-GF @X-Plus 5.json @@ -0,0 +1,111 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_38", + "name": "QIDI PET-GF@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "50" + ], + "box_temperature_range_low": [ + "0" + ], + "box_temperature": [ + "50" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "70" + ], + "cool_plate_temp": [ + "70" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "10" + ], + "fan_max_speed": [ + "20" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "800" + ], + "filament_density": [ + "1.38" + ], + "filament_flow_ratio": [ + "0.97" + ], + "filament_max_volumetric_speed": [ + "10" + ], + "filament_type": [ + "PET-GF" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "4.5" + ], + "nozzle_temperature_initial_layer": [ + "300" + ], + "nozzle_temperature_range_high": [ + "320" + ], + "nozzle_temperature_range_low": [ + "280" + ], + "nozzle_temperature": [ + "300" + ], + "overhang_fan_speed": [ + "40" + ], + "overhang_fan_threshold": [ + "0%" + ], + "pressure_advance": [ + "0.022" + ], + "slow_down_layer_time": [ + "5" + ], + "supertack_plate_temp_initial_layer": [ + "70" + ], + "supertack_plate_temp": [ + "70" + ], + "temperature_vitrification": [ + "185" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "textured_cool_plate_temp_initial_layer": [ + "70" + ], + "textured_cool_plate_temp": [ + "70" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..6689cca71a --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "k4jOZFY5QV2bMKHK", + "name": "QIDI PETG Basic @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Basic@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "1" + ], + "pressure_advance": [ + "0.054" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..c1b29f1b75 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "b55sLpGKCrWLiDPf", + "name": "QIDI PETG Basic @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Basic@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..3be97a337f --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "XcxbsZ4d8Dh21WX0", + "name": "QIDI PETG Basic @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Basic@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..92a57fb1b8 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Basic @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "9MEoOjLU7AOCvb9X", + "name": "QIDI PETG Basic @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Basic@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Basic @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Basic @X-Plus 5.json new file mode 100644 index 0000000000..46810f49c3 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Basic @X-Plus 5.json @@ -0,0 +1,102 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_39", + "name": "QIDI PETG Basic@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "40" + ], + "fan_min_speed": [ + "10" + ], + "filament_adhesiveness_category": [ + "300" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "15" + ], + "filament_type": [ + "PETG" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "10.6" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "250" + ], + "overhang_fan_speed": [ + "90" + ], + "overhang_fan_threshold": [ + "10%" + ], + "pressure_advance": [ + "0.054" + ], + "slow_down_layer_time": [ + "12" + ], + "temperature_vitrification": [ + "70" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "supertack_plate_temp": [ + "60" + ], + "textured_cool_plate_temp_initial_layer": [ + "60" + ], + "textured_cool_plate_temp": [ + "60" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..220a6ce55a --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "oi5JKM4fwEYHefs0", + "name": "QIDI PETG Rapido @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Rapido@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "1" + ], + "pressure_advance": [ + "0.054" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..9fe3affac2 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "SZOwb16vrcdtaDzJ", + "name": "QIDI PETG Rapido @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Rapido@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..a550919113 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "4LKxL4N0ccD6vZ60", + "name": "QIDI PETG Rapido @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Rapido@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..b56b55d1ff --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "rsNDDt3IFUOMYV3O", + "name": "QIDI PETG Rapido @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Rapido@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @X-Plus 5.json new file mode 100644 index 0000000000..fd506d8e74 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Rapido @X-Plus 5.json @@ -0,0 +1,102 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_41", + "name": "QIDI PETG Rapido@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "20" + ], + "fan_max_speed": [ + "40" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "300" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "18" + ], + "filament_type": [ + "PETG" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "10.6" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "275" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "250" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "10%" + ], + "pressure_advance": [ + "0.054" + ], + "slow_down_layer_time": [ + "8" + ], + "temperature_vitrification": [ + "70" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "supertack_plate_temp": [ + "60" + ], + "textured_cool_plate_temp_initial_layer": [ + "60" + ], + "textured_cool_plate_temp": [ + "60" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..7708ebba0d --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "k4kLQheLeWOw8bwp", + "name": "QIDI PETG Tough @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Tough@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "1" + ], + "pressure_advance": [ + "0.056" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..5c8c182a2b --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "WEyrSDtW2CJeLQmg", + "name": "QIDI PETG Tough @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Tough@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..ad75cc5722 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "Morgo6GIzU3Voc0Q", + "name": "QIDI PETG Tough @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Tough@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..37c0beddb9 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Tough @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "DsoxBXKOjsENLEZf", + "name": "QIDI PETG Tough @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Tough@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Tough @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Tough @X-Plus 5.json new file mode 100644 index 0000000000..3e9f0a1cdf --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Tough @X-Plus 5.json @@ -0,0 +1,102 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_40", + "name": "QIDI PETG Tough@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "40" + ], + "fan_min_speed": [ + "10" + ], + "filament_adhesiveness_category": [ + "300" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "13" + ], + "filament_type": [ + "PETG" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "10.6" + ], + "nozzle_temperature_initial_layer": [ + "240" + ], + "nozzle_temperature_range_high": [ + "270" + ], + "nozzle_temperature_range_low": [ + "220" + ], + "nozzle_temperature": [ + "250" + ], + "overhang_fan_speed": [ + "90" + ], + "overhang_fan_threshold": [ + "10%" + ], + "pressure_advance": [ + "0.056" + ], + "slow_down_layer_time": [ + "8" + ], + "temperature_vitrification": [ + "70" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "supertack_plate_temp": [ + "60" + ], + "textured_cool_plate_temp_initial_layer": [ + "60" + ], + "textured_cool_plate_temp": [ + "60" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..03e72feba9 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "2UJnG0rXeU2nCIQL", + "name": "QIDI PETG Translucent @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Translucent@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "1" + ], + "pressure_advance": [ + "0.054" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..545bd42538 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "S2DQ7jy5KqbiVNnV", + "name": "QIDI PETG Translucent @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Translucent@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..963916f76e --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "G33dlk73weGNFNwg", + "name": "QIDI PETG Translucent @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Translucent@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..42bf38bde4 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "zqI9F8vplNFfm2pa", + "name": "QIDI PETG Translucent @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG Translucent@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @X-Plus 5.json new file mode 100644 index 0000000000..62ea937028 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG Translucent @X-Plus 5.json @@ -0,0 +1,102 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_45", + "name": "QIDI PETG Translucent@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "30" + ], + "fan_min_speed": [ + "10" + ], + "filament_adhesiveness_category": [ + "300" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_type": [ + "PETG" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "10.6" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "250" + ], + "overhang_fan_speed": [ + "90" + ], + "overhang_fan_threshold": [ + "10%" + ], + "pressure_advance": [ + "0.054" + ], + "slow_down_layer_time": [ + "8" + ], + "temperature_vitrification": [ + "70" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "supertack_plate_temp": [ + "60" + ], + "textured_cool_plate_temp_initial_layer": [ + "60" + ], + "textured_cool_plate_temp": [ + "60" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG-CF @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG-CF @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..04176974f5 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG-CF @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "cXbQtMQKmAFqwmqK", + "name": "QIDI PETG-CF @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG-CF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG-CF @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG-CF @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..ce16a13acf --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG-CF @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "YNIWSLXvW6kSPRFG", + "name": "QIDI PETG-CF @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG-CF@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG-CF @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG-CF @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..e1ce42ee0a --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG-CF @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "O0lwfGXO3BdPCask", + "name": "QIDI PETG-CF @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG-CF@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG-CF @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PETG-CF @X-Plus 5.json new file mode 100644 index 0000000000..fcddc636a8 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG-CF @X-Plus 5.json @@ -0,0 +1,102 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_42", + "name": "QIDI PETG-CF@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "40" + ], + "fan_min_speed": [ + "5" + ], + "filament_adhesiveness_category": [ + "300" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "11.5" + ], + "filament_type": [ + "PETG-CF" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "10.6" + ], + "nozzle_temperature_initial_layer": [ + "255" + ], + "nozzle_temperature_range_high": [ + "270" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "255" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "10%" + ], + "pressure_advance": [ + "0.048" + ], + "slow_down_layer_time": [ + "6" + ], + "temperature_vitrification": [ + "70" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "supertack_plate_temp": [ + "60" + ], + "textured_cool_plate_temp_initial_layer": [ + "60" + ], + "textured_cool_plate_temp": [ + "60" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG-GF @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG-GF @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..46b3b1176a --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG-GF @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "zfI1VXQ7E0re78CC", + "name": "QIDI PETG-GF @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG-GF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG-GF @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG-GF @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..4af6b7db02 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG-GF @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "zYEbjZPipK4BgHRO", + "name": "QIDI PETG-GF @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG-GF@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG-GF @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PETG-GF @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..bf819e04a9 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG-GF @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "5ef246YwGEK0eVCr", + "name": "QIDI PETG-GF @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PETG-GF@X-Plus 5-Series", + "pressure_advance": [ + "0.04" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PETG-GF @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PETG-GF @X-Plus 5.json new file mode 100644 index 0000000000..fa65907d3d --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PETG-GF @X-Plus 5.json @@ -0,0 +1,102 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_43", + "name": "QIDI PETG-GF@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "45" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "50" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "300" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_type": [ + "PETG-GF" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "10.6" + ], + "nozzle_temperature_initial_layer": [ + "255" + ], + "nozzle_temperature_range_high": [ + "270" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "255" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "10%" + ], + "pressure_advance": [ + "0.056" + ], + "slow_down_layer_time": [ + "8" + ], + "temperature_vitrification": [ + "70" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "supertack_plate_temp": [ + "60" + ], + "textured_cool_plate_temp_initial_layer": [ + "60" + ], + "textured_cool_plate_temp": [ + "60" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..4ec7f05eb9 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "sfrpgBzPufKwgBCT", + "name": "QIDI PLA Basic @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Basic@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.034" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..20dd378bd2 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "6ZscfuWENwCkdSYE", + "name": "QIDI PLA Basic @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Basic@X-Plus 5-Series", + "pressure_advance": [ + "0.038" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..574e748c98 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "pEry2GMq8UJEw7c7", + "name": "QIDI PLA Basic @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Basic@X-Plus 5-Series", + "pressure_advance": [ + "0.016" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..527eb00054 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Basic @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "MTq8xcAKCWABLI2k", + "name": "QIDI PLA Basic @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Basic@X-Plus 5-Series", + "pressure_advance": [ + "0.008" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Basic @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Basic @X-Plus 5.json new file mode 100644 index 0000000000..0ee194dfb3 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Basic @X-Plus 5.json @@ -0,0 +1,63 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_7", + "name": "QIDI PLA Basic@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "cool_plate_temp_initial_layer": [ + "45" + ], + "cool_plate_temp": [ + "45" + ], + "filament_adhesiveness_category": [ + "100" + ], + "filament_max_volumetric_speed": [ + "18" + ], + "filament_type": [ + "PLA" + ], + "impact_strength_z": [ + "13.8" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_initial_layer": [ + "210" + ], + "nozzle_temperature": [ + "210" + ], + "overhang_fan_threshold": [ + "50%" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [], + "close_additional_fan_first_x_layers": [ + "1" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..0078600f36 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "54iiCCwizthHtT1v", + "name": "QIDI PLA Matte Basic @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Matte Basic@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.034" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..d67aa77dc4 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "ojnl8sBbBL4QBL8q", + "name": "QIDI PLA Matte Basic @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Matte Basic@X-Plus 5-Series", + "pressure_advance": [ + "0.038" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..6575396e45 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "XtZarwF2HIipdHjN", + "name": "QIDI PLA Matte Basic @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Matte Basic@X-Plus 5-Series", + "pressure_advance": [ + "0.016" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..8c4584a70b --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "TRkCNQeoDvLBaJMt", + "name": "QIDI PLA Matte Basic @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Matte Basic@X-Plus 5-Series", + "pressure_advance": [ + "0.008" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @X-Plus 5.json new file mode 100644 index 0000000000..7796bf1faa --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Matte Basic @X-Plus 5.json @@ -0,0 +1,63 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_8", + "name": "QIDI PLA Matte Basic@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "cool_plate_temp_initial_layer": [ + "45" + ], + "cool_plate_temp": [ + "45" + ], + "filament_adhesiveness_category": [ + "100" + ], + "filament_max_volumetric_speed": [ + "18" + ], + "filament_type": [ + "PLA" + ], + "impact_strength_z": [ + "13.8" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_initial_layer": [ + "210" + ], + "nozzle_temperature": [ + "210" + ], + "overhang_fan_threshold": [ + "50%" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [], + "close_additional_fan_first_x_layers": [ + "1" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..3ea3dac12f --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "S56TixVPmXr4uFut", + "name": "QIDI PLA Rapido @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Rapido@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.034" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..178fcfd08d --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "KATHrxoL84i7MiVJ", + "name": "QIDI PLA Rapido @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Rapido@X-Plus 5-Series", + "pressure_advance": [ + "0.038" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..2ad1d18a60 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "YE6WmGAG5Ua6bbap", + "name": "QIDI PLA Rapido @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Rapido@X-Plus 5-Series", + "pressure_advance": [ + "0.016" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..ffc9edfb78 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "KPqnbBv0Np93O02u", + "name": "QIDI PLA Rapido @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Rapido@X-Plus 5-Series", + "pressure_advance": [ + "0.008" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @X-Plus 5.json new file mode 100644 index 0000000000..1aa1803258 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido @X-Plus 5.json @@ -0,0 +1,60 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_1", + "name": "QIDI PLA Rapido@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "cool_plate_temp_initial_layer": [ + "45" + ], + "cool_plate_temp": [ + "45" + ], + "filament_adhesiveness_category": [ + "100" + ], + "filament_type": [ + "PLA" + ], + "impact_strength_z": [ + "13.8" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_initial_layer": [ + "210" + ], + "nozzle_temperature": [ + "210" + ], + "overhang_fan_threshold": [ + "50%" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [], + "close_additional_fan_first_x_layers": [ + "1" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..e469cf1fd1 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "jlUpp5oaYSWwaNn1", + "name": "QIDI PLA Rapido Matte @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Rapido Matte@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.034" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..3f74323770 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "E0gYAZUksoFlebuH", + "name": "QIDI PLA Rapido Matte @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Rapido Matte@X-Plus 5-Series", + "pressure_advance": [ + "0.034" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..f45479c37f --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "juxpaK6EosaHj2ok", + "name": "QIDI PLA Rapido Matte @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Rapido Matte@X-Plus 5-Series", + "pressure_advance": [ + "0.016" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..7e4ec99248 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "OlgI3WQA3QLhPsdw", + "name": "QIDI PLA Rapido Matte @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Rapido Matte@X-Plus 5-Series", + "pressure_advance": [ + "0.008" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @X-Plus 5.json new file mode 100644 index 0000000000..d8cbd06ea1 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Matte @X-Plus 5.json @@ -0,0 +1,57 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_2", + "name": "QIDI PLA Rapido Matte@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "additional_cooling_fan_speed": [ + "100" + ], + "filament_adhesiveness_category": [ + "100" + ], + "filament_density": [ + "1.42" + ], + "filament_type": [ + "PLA" + ], + "impact_strength_z": [ + "6.6" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_initial_layer": [ + "210" + ], + "nozzle_temperature": [ + "210" + ], + "overhang_fan_threshold": [ + "50%" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [], + "close_additional_fan_first_x_layers": [ + "1" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..7506c80541 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "t9qUv1IlI5VJ8LoV", + "name": "QIDI PLA Rapido Metal @Qidi X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Rapido Metal@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "2" + ], + "pressure_advance": [ + "0.038" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..e2be1216f3 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "ARcrUoVsGSM0RB1a", + "name": "QIDI PLA Rapido Metal @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Rapido Metal@X-Plus 5-Series", + "pressure_advance": [ + "0.038" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..2b3fae0a1e --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "A23HjUFAyt4GeHAW", + "name": "QIDI PLA Rapido Metal @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Rapido Metal@X-Plus 5-Series", + "pressure_advance": [ + "0.020" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..e6868b6772 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "nMpSP1jmsQIUjGPb", + "name": "QIDI PLA Rapido Metal @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Rapido Metal@X-Plus 5-Series", + "pressure_advance": [ + "0.01" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @X-Plus 5.json new file mode 100644 index 0000000000..404b7cd1e8 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Rapido Metal @X-Plus 5.json @@ -0,0 +1,57 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_3", + "name": "QIDI PLA Rapido Metal@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "filament_type": [ + "PLA" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "filament_adhesiveness_category": [ + "100" + ], + "filament_density": [ + "1.20" + ], + "impact_strength_z": [ + "16.8" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_initial_layer": [ + "210" + ], + "nozzle_temperature": [ + "210" + ], + "overhang_fan_threshold": [ + "50%" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [], + "close_additional_fan_first_x_layers": [ + "1" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Silk @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Silk @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..dfd789a216 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Silk @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "IUU7TApRivYtrrt0", + "name": "QIDI PLA Silk @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Silk@X-Plus 5-Series", + "pressure_advance": [ + "0.034" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Silk @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Silk @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..286c1d3a36 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Silk @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "lx9Dqv6EMmZ0C2SD", + "name": "QIDI PLA Silk @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA Silk@X-Plus 5-Series", + "pressure_advance": [ + "0.021" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA Silk @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PLA Silk @X-Plus 5.json new file mode 100644 index 0000000000..57c0c3e1dc --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA Silk @X-Plus 5.json @@ -0,0 +1,84 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_4", + "name": "QIDI PLA Silk@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "additional_cooling_fan_speed": [ + "100" + ], + "filament_adhesiveness_category": [ + "100" + ], + "filament_density": [ + "1.24" + ], + "filament_max_volumetric_speed": [ + "7.5" + ], + "filament_type": [ + "PLA" + ], + "impact_strength_z": [ + "4.6" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature": [ + "220" + ], + "overhang_fan_threshold": [ + "50%" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "cool_plate_temp_initial_layer": [ + "45" + ], + "cool_plate_temp": [ + "45" + ], + "eng_plate_temp_initial_layer": [ + "55" + ], + "eng_plate_temp": [ + "55" + ], + "hot_plate_temp_initial_layer": [ + "55" + ], + "hot_plate_temp": [ + "55" + ], + "textured_plate_temp_initial_layer": [ + "55" + ], + "textured_plate_temp": [ + "55" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [], + "close_additional_fan_first_x_layers": [ + "1" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA-CF @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA-CF @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..c341f7c71d --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA-CF @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "5PocTwpY0SnNzcdc", + "name": "QIDI PLA-CF @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA-CF@X-Plus 5-Series", + "pressure_advance": [ + "0.034" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA-CF @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA-CF @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..5c08e7f67f --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA-CF @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "5NETSLSQlaoR2MYD", + "name": "QIDI PLA-CF @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA-CF@X-Plus 5-Series", + "pressure_advance": [ + "0.012" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA-CF @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PLA-CF @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..7435222e8b --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA-CF @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,17 @@ +{ + "type": "filament", + "setting_id": "AUO7iSMEa6GDvM7Y", + "name": "QIDI PLA-CF @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PLA-CF@X-Plus 5-Series", + "filament_max_volumetric_speed": [ + "18" + ], + "pressure_advance": [ + "0.008" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PLA-CF @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PLA-CF @X-Plus 5.json new file mode 100644 index 0000000000..1c4d8c99e3 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PLA-CF @X-Plus 5.json @@ -0,0 +1,75 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_5", + "name": "QIDI PLA-CF@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "additional_cooling_fan_speed": [ + "0" + ], + "cool_plate_temp_initial_layer": [ + "45" + ], + "cool_plate_temp": [ + "45" + ], + "filament_adhesiveness_category": [ + "100" + ], + "filament_density": [ + "1.25" + ], + "filament_flow_ratio": [ + "0.93" + ], + "filament_max_volumetric_speed": [ + "15" + ], + "filament_type": [ + "PLA-CF" + ], + "impact_strength_z": [ + "7.8" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature_range_high": [ + "250" + ], + "nozzle_temperature_range_low": [ + "210" + ], + "nozzle_temperature": [ + "220" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pressure_advance": [ + "0.042" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [], + "close_additional_fan_first_x_layers": [ + "1" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PPS-CF @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PPS-CF @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..2c2d573713 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PPS-CF @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "FwWut7sJIMbe87XC", + "name": "QIDI PPS-CF @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PPS-CF@X-Plus 5-Series", + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PPS-CF @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PPS-CF @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..9cc0556490 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PPS-CF @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "gDIuKCdgoP59Xc0G", + "name": "QIDI PPS-CF @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PPS-CF@X-Plus 5-Series", + "pressure_advance": [ + "0.021" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PPS-CF @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PPS-CF @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..573f8e17f8 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PPS-CF @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "D29sGCB9OI4cTn0S", + "name": "QIDI PPS-CF @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PPS-CF@X-Plus 5-Series", + "pressure_advance": [ + "0.008" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PPS-CF @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PPS-CF @X-Plus 5.json new file mode 100644 index 0000000000..c6be7046f6 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PPS-CF @X-Plus 5.json @@ -0,0 +1,117 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_44", + "name": "QIDI PPS-CF@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "65" + ], + "box_temperature_range_low": [ + "0" + ], + "box_temperature": [ + "65" + ], + "chamber_temperatures": [ + "60" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "110" + ], + "eng_plate_temp": [ + "110" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_cooling_layer_time": [ + "5" + ], + "fan_max_speed": [ + "30" + ], + "fan_min_speed": [ + "0" + ], + "filament_adhesiveness_category": [ + "801" + ], + "filament_density": [ + "1.3" + ], + "filament_flow_ratio": [ + "0.97" + ], + "filament_max_volumetric_speed": [ + "6" + ], + "filament_type": [ + "PPS-CF" + ], + "hot_plate_temp_initial_layer": [ + "110" + ], + "hot_plate_temp": [ + "110" + ], + "impact_strength_z": [ + "2.8" + ], + "nozzle_temperature_initial_layer": [ + "320" + ], + "nozzle_temperature_range_high": [ + "350" + ], + "nozzle_temperature_range_low": [ + "300" + ], + "nozzle_temperature": [ + "320" + ], + "overhang_fan_speed": [ + "40" + ], + "overhang_fan_threshold": [ + "0%" + ], + "pressure_advance": [ + "0.032" + ], + "slow_down_layer_time": [ + "2" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "temperature_vitrification": [ + "180" + ], + "textured_plate_temp_initial_layer": [ + "110" + ], + "textured_plate_temp": [ + "110" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PPS-GF @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PPS-GF @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..de96ad5f7a --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PPS-GF @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "5C6dIIgQOt4NiTu0", + "name": "QIDI PPS-GF @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PPS-GF@X-Plus 5-Series", + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PPS-GF @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PPS-GF @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..470839ef59 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PPS-GF @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "aSd6UW4Mrlxpa15E", + "name": "QIDI PPS-GF @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PPS-GF@X-Plus 5-Series", + "pressure_advance": [ + "0.021" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PPS-GF @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI PPS-GF @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..6cc49dbd68 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PPS-GF @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "7JC2zAUgtGu5zSGo", + "name": "QIDI PPS-GF @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI PPS-GF@X-Plus 5-Series", + "pressure_advance": [ + "0.008" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI PPS-GF @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI PPS-GF @X-Plus 5.json new file mode 100644 index 0000000000..757d4dbf3d --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI PPS-GF @X-Plus 5.json @@ -0,0 +1,117 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_46", + "name": "QIDI PPS-GF@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "65" + ], + "box_temperature_range_low": [ + "0" + ], + "box_temperature": [ + "65" + ], + "chamber_temperatures": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "eng_plate_temp": [ + "90" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "90" + ], + "fan_min_speed": [ + "10" + ], + "filament_adhesiveness_category": [ + "801" + ], + "filament_density": [ + "1.3" + ], + "filament_flow_ratio": [ + "0.97" + ], + "filament_max_volumetric_speed": [ + "10" + ], + "filament_type": [ + "PPS-GF" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "hot_plate_temp": [ + "90" + ], + "impact_strength_z": [ + "2.8" + ], + "nozzle_temperature_initial_layer": [ + "320" + ], + "nozzle_temperature_range_high": [ + "350" + ], + "nozzle_temperature_range_low": [ + "300" + ], + "nozzle_temperature": [ + "320" + ], + "overhang_fan_speed": [ + "50" + ], + "overhang_fan_threshold": [ + "0%" + ], + "pressure_advance": [ + "0.03" + ], + "slow_down_layer_time": [ + "6" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "temperature_vitrification": [ + "180" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "textured_plate_temp": [ + "90" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..5bd3b85fb9 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "oMvDD9rKJGcezwpq", + "name": "QIDI Support For PAHT @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI Support For PAHT@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..37f474533e --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "6BhbbuUP6HCVScDd", + "name": "QIDI Support For PAHT @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI Support For PAHT@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..f28e56c5b1 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "kA4fvvj6xZEhArXv", + "name": "QIDI Support For PAHT @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI Support For PAHT@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @X-Plus 5.json new file mode 100644 index 0000000000..ed1222daa9 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI Support For PAHT @X-Plus 5.json @@ -0,0 +1,114 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_32", + "name": "QIDI Support For PAHT@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "65" + ], + "box_temperature_range_low": [ + "0" + ], + "box_temperature": [ + "60" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "10" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "0" + ], + "filament_adhesiveness_category": [ + "800" + ], + "filament_density": [ + "1.26" + ], + "filament_flow_ratio": [ + "0.94" + ], + "filament_is_support": [ + "1" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_type": [ + "PAHT-S" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "4.5" + ], + "nozzle_temperature_initial_layer": [ + "280" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "260" + ], + "nozzle_temperature": [ + "280" + ], + "overhang_fan_speed": [ + "30" + ], + "overhang_fan_threshold": [ + "95%" + ], + "pressure_advance": [ + "0.02" + ], + "slow_down_layer_time": [ + "6" + ], + "temperature_vitrification": [ + "218" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "supertack_plate_temp_initial_layer": [ + "80" + ], + "supertack_plate_temp": [ + "80" + ], + "textured_cool_plate_temp_initial_layer": [ + "80" + ], + "textured_cool_plate_temp": [ + "80" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..615d9af041 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "0xy82KbAJD5uBara", + "name": "QIDI Support For PET/PA @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI Support For PET/PA@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..1e0c81424c --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "2oCGYFdC4dfpNUw4", + "name": "QIDI Support For PET/PA @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI Support For PET/PA@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..2d47d18707 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "hFYahJkYIgmjcuPb", + "name": "QIDI Support For PET/PA @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI Support For PET/PA@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @X-Plus 5.json new file mode 100644 index 0000000000..346c3cc3eb --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI Support For PET-PA @X-Plus 5.json @@ -0,0 +1,114 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_33", + "name": "QIDI Support For PET/PA@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "65" + ], + "box_temperature_range_low": [ + "0" + ], + "box_temperature": [ + "55" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "70" + ], + "cool_plate_temp": [ + "70" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_cooling_layer_time": [ + "10" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "0" + ], + "filament_adhesiveness_category": [ + "800" + ], + "filament_density": [ + "1.16" + ], + "filament_flow_ratio": [ + "0.91" + ], + "filament_is_support": [ + "1" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_type": [ + "PA-S" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "4.5" + ], + "nozzle_temperature_initial_layer": [ + "280" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "260" + ], + "nozzle_temperature": [ + "280" + ], + "overhang_fan_speed": [ + "30" + ], + "overhang_fan_threshold": [ + "95%" + ], + "pressure_advance": [ + "0.02" + ], + "slow_down_layer_time": [ + "6" + ], + "temperature_vitrification": [ + "168" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "supertack_plate_temp_initial_layer": [ + "70" + ], + "supertack_plate_temp": [ + "70" + ], + "textured_cool_plate_temp_initial_layer": [ + "70" + ], + "textured_cool_plate_temp": [ + "70" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..1f2db1eb25 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "ygLg4KVojo7YoG5K", + "name": "QIDI TPU 95A-HF @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI TPU 95A-HF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..94e992d0e9 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "K98nPXclatc5HnIx", + "name": "QIDI TPU 95A-HF @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI TPU 95A-HF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..e05faeed65 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "pTxBir6QC9KhWrLU", + "name": "QIDI TPU 95A-HF @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI TPU 95A-HF@X-Plus 5-Series", + "nozzle_temperature": [ + "220" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @X-Plus 5.json new file mode 100644 index 0000000000..4721ab171c --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI TPU 95A-HF @X-Plus 5.json @@ -0,0 +1,84 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_50", + "name": "QIDI TPU 95A-HF@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "cool_plate_temp_initial_layer": [ + "30" + ], + "cool_plate_temp": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "35" + ], + "eng_plate_temp": [ + "35" + ], + "filament_adhesiveness_category": [ + "600" + ], + "filament_density": [ + "1.15" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "4" + ], + "filament_type": [ + "TPU" + ], + "filament_vendor": [ + "QIDI" + ], + "hot_plate_temp_initial_layer": [ + "35" + ], + "hot_plate_temp": [ + "35" + ], + "impact_strength_z": [ + "88.7" + ], + "nozzle_temperature_initial_layer": [ + "230" + ], + "nozzle_temperature_range_high": [ + "250" + ], + "nozzle_temperature_range_low": [ + "200" + ], + "nozzle_temperature": [ + "230" + ], + "pressure_advance": [ + "0.1" + ], + "supertack_plate_temp_initial_layer": [ + "30" + ], + "supertack_plate_temp": [ + "30" + ], + "temperature_vitrification": [ + "30" + ], + "textured_plate_temp_initial_layer": [ + "35" + ], + "textured_plate_temp": [ + "35" + ], + "textured_cool_plate_temp_initial_layer": [ + "30" + ], + "textured_cool_plate_temp": [ + "30" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI TPU-Aero @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI TPU-Aero @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..592ad5a51c --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI TPU-Aero @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "KIIwoI87n5MkT83b", + "name": "QIDI TPU-Aero @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI TPU-Aero@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI TPU-Aero @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI TPU-Aero @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..f18b67f608 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI TPU-Aero @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "eUNygrv7weqgX7e0", + "name": "QIDI TPU-Aero @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI TPU-Aero@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI TPU-Aero @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI TPU-Aero @X-Plus 5.json new file mode 100644 index 0000000000..b6eee90916 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI TPU-Aero @X-Plus 5.json @@ -0,0 +1,93 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_49", + "name": "QIDI TPU-Aero@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "cool_plate_temp_initial_layer": [ + "30" + ], + "cool_plate_temp": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "35" + ], + "eng_plate_temp": [ + "35" + ], + "fan_cooling_layer_time": [ + "100" + ], + "filament_adhesiveness_category": [ + "600" + ], + "filament_density": [ + "1.15" + ], + "filament_flow_ratio": [ + "0.5" + ], + "filament_max_volumetric_speed": [ + "6" + ], + "filament_retraction_length": [ + "0" + ], + "filament_type": [ + "TPU-AERO" + ], + "filament_vendor": [ + "QIDI" + ], + "hot_plate_temp_initial_layer": [ + "35" + ], + "hot_plate_temp": [ + "35" + ], + "impact_strength_z": [ + "88.7" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_high": [ + "270" + ], + "nozzle_temperature_range_low": [ + "230" + ], + "nozzle_temperature": [ + "250" + ], + "pressure_advance": [ + "0.03" + ], + "slow_down_layer_time": [ + "14" + ], + "supertack_plate_temp_initial_layer": [ + "30" + ], + "supertack_plate_temp": [ + "30" + ], + "temperature_vitrification": [ + "30" + ], + "textured_plate_temp_initial_layer": [ + "35" + ], + "textured_plate_temp": [ + "35" + ], + "textured_cool_plate_temp_initial_layer": [ + "30" + ], + "textured_cool_plate_temp": [ + "30" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI TPU-GF @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI TPU-GF @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..8e88b23151 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI TPU-GF @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "AtsowCGhOIw4GeRJ", + "name": "QIDI TPU-GF @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI TPU-GF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI TPU-GF @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI TPU-GF @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..5a7687b51c --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI TPU-GF @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "wqk4I1KaRyLEm12W", + "name": "QIDI TPU-GF @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI TPU-GF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI TPU-GF @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI TPU-GF @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..2fe800d6ab --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI TPU-GF @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "o2JjRsoi03ST3Wh2", + "name": "QIDI TPU-GF @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI TPU-GF@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI TPU-GF @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI TPU-GF @X-Plus 5.json new file mode 100644 index 0000000000..b3f2f71866 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI TPU-GF @X-Plus 5.json @@ -0,0 +1,84 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_15", + "name": "QIDI TPU-GF@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "cool_plate_temp_initial_layer": [ + "30" + ], + "cool_plate_temp": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "35" + ], + "eng_plate_temp": [ + "35" + ], + "filament_adhesiveness_category": [ + "600" + ], + "filament_density": [ + "1.15" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "6" + ], + "filament_type": [ + "TPU-GF" + ], + "filament_vendor": [ + "QIDI" + ], + "hot_plate_temp_initial_layer": [ + "35" + ], + "hot_plate_temp": [ + "35" + ], + "impact_strength_z": [ + "88.7" + ], + "nozzle_temperature_initial_layer": [ + "240" + ], + "nozzle_temperature_range_high": [ + "270" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature": [ + "240" + ], + "pressure_advance": [ + "0.1" + ], + "supertack_plate_temp_initial_layer": [ + "30" + ], + "supertack_plate_temp": [ + "30" + ], + "temperature_vitrification": [ + "30" + ], + "textured_plate_temp_initial_layer": [ + "35" + ], + "textured_plate_temp": [ + "35" + ], + "textured_cool_plate_temp_initial_layer": [ + "30" + ], + "textured_cool_plate_temp": [ + "30" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI UltraPA @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI UltraPA @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..ae7b99531e --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI UltraPA @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "RzZGtHGu2xKASwwu", + "name": "QIDI UltraPA @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI UltraPA@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI UltraPA @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI UltraPA @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..e9bfbe4362 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI UltraPA @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "0seF33ojhYF6lNM4", + "name": "QIDI UltraPA @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI UltraPA@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI UltraPA @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI UltraPA @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..6f03ff7b5a --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI UltraPA @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "vfr7Lv94OHi4KOCw", + "name": "QIDI UltraPA @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI UltraPA@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI UltraPA @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI UltraPA @X-Plus 5.json new file mode 100644 index 0000000000..9d86c06f95 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI UltraPA @X-Plus 5.json @@ -0,0 +1,99 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_24", + "name": "QIDI UltraPA@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "55" + ], + "box_temperature_range_low": [ + "0" + ], + "box_temperature": [ + "55" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "fan_max_speed": [ + "40" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "400" + ], + "filament_density": [ + "1.21" + ], + "filament_flow_ratio": [ + "0.96" + ], + "filament_max_volumetric_speed": [ + "4" + ], + "filament_type": [ + "UltraPA" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "15.5" + ], + "nozzle_temperature_initial_layer": [ + "280" + ], + "nozzle_temperature_range_high": [ + "290" + ], + "nozzle_temperature_range_low": [ + "250" + ], + "nozzle_temperature": [ + "280" + ], + "pressure_advance": [ + "0.03" + ], + "slow_down_layer_time": [ + "15" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "supertack_plate_temp": [ + "60" + ], + "temperature_vitrification": [ + "170" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "textured_cool_plate_temp_initial_layer": [ + "60" + ], + "textured_cool_plate_temp": [ + "60" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..c88635f447 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "filament", + "setting_id": "8h1ITuLzHYf0J4NA", + "name": "QIDI UltraPA-CF25 @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI UltraPA-CF25@X-Plus 5-Series", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..66ac797bb8 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "WK63qDyLkG4fznPW", + "name": "QIDI UltraPA-CF25 @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI UltraPA-CF25@X-Plus 5-Series", + "pressure_advance": [ + "0.022" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..282fed912a --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "53sirpAAiDOx0c8P", + "name": "QIDI UltraPA-CF25 @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI UltraPA-CF25@X-Plus 5-Series", + "pressure_advance": [ + "0.02" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @X-Plus 5.json new file mode 100644 index 0000000000..73379541b3 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI UltraPA-CF25 @X-Plus 5.json @@ -0,0 +1,114 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_26", + "name": "QIDI UltraPA-CF25@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "box_temperature_range_high": [ + "65" + ], + "box_temperature_range_low": [ + "0" + ], + "box_temperature": [ + "60" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "during_print_exhaust_fan_speed": [ + "0" + ], + "fan_cooling_layer_time": [ + "5" + ], + "fan_max_speed": [ + "40" + ], + "fan_min_speed": [ + "20" + ], + "filament_adhesiveness_category": [ + "400" + ], + "filament_density": [ + "1.23" + ], + "filament_flow_ratio": [ + "0.94" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_type": [ + "UltraPA-CF25" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "hot_plate_temp": [ + "80" + ], + "impact_strength_z": [ + "15.5" + ], + "nozzle_temperature_initial_layer": [ + "300" + ], + "nozzle_temperature_range_high": [ + "320" + ], + "nozzle_temperature_range_low": [ + "300" + ], + "nozzle_temperature": [ + "300" + ], + "overhang_fan_speed": [ + "40" + ], + "overhang_fan_threshold": [ + "0%" + ], + "pressure_advance": [ + "0.026" + ], + "slow_down_layer_time": [ + "2" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "supertack_plate_temp": [ + "60" + ], + "temperature_vitrification": [ + "230" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "textured_cool_plate_temp_initial_layer": [ + "60" + ], + "textured_cool_plate_temp": [ + "60" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..2232226b78 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "gIumq0YfeZrNDTZt", + "name": "QIDI WOOD Rapido @Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI WOOD Rapido@X-Plus 5-Series", + "pressure_advance": [ + "0.044" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..b9ecf201ba --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "qUjZ8AUjivOk8uCf", + "name": "QIDI WOOD Rapido @Qidi X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI WOOD Rapido@X-Plus 5-Series", + "pressure_advance": [ + "0.024" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..fc15698443 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "setting_id": "A2kztfG9PA7Qxh7r", + "name": "QIDI WOOD Rapido @Qidi X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "QIDI WOOD Rapido@X-Plus 5-Series", + "pressure_advance": [ + "0.012" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @X-Plus 5.json b/resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @X-Plus 5.json new file mode 100644 index 0000000000..30428c7422 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/QIDI WOOD Rapido @X-Plus 5.json @@ -0,0 +1,66 @@ +{ + "type": "filament", + "filament_id": "QD_4_1_6", + "name": "QIDI WOOD Rapido@X-Plus 5-Series", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_x5_common", + "additional_cooling_fan_speed": [ + "100" + ], + "box_temperature_range_high": [ + "45" + ], + "filament_adhesiveness_category": [ + "100" + ], + "filament_density": [ + "1.23" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "18" + ], + "filament_type": [ + "PLA" + ], + "impact_strength_z": [ + "5.6" + ], + "nozzle_temperature_range_high": [ + "220" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_initial_layer": [ + "210" + ], + "nozzle_temperature": [ + "210" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pressure_advance": [ + "0.044" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp_initial_layer": [ + "45" + ], + "textured_cool_plate_temp": [ + "45" + ], + "compatible_printers": [] +} diff --git a/resources/profiles/Qidi/filament/X5/fdm_filament_x5_common.json b/resources/profiles/Qidi/filament/X5/fdm_filament_x5_common.json new file mode 100644 index 0000000000..a161158dc4 --- /dev/null +++ b/resources/profiles/Qidi/filament/X5/fdm_filament_x5_common.json @@ -0,0 +1,255 @@ +{ + "type": "filament", + "name": "fdm_filament_x5_common", + "from": "system", + "instantiation": "false", + "activate_air_filtration": [ + "1" + ], + "additional_cooling_fan_speed": [ + "0" + ], + "additional_fan_full_speed_layer": [ + "0" + ], + "bed_type": [ + "Cool Plate" + ], + "box_temperature_range_high": [ + "0" + ], + "box_temperature_range_low": [ + "0" + ], + "box_temperature": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "close_additional_fan_first_x_layers": [ + "3" + ], + "complete_print_exhaust_fan_speed": [ + "0" + ], + "cool_plate_temp_initial_layer": [ + "45" + ], + "cool_plate_temp": [ + "45" + ], + "during_print_exhaust_fan_speed": [ + "100" + ], + "enable_pressure_advance": [ + "1" + ], + "eng_plate_temp_initial_layer": [ + "60" + ], + "eng_plate_temp": [ + "60" + ], + "fan_cooling_layer_time": [ + "60" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cost": [ + "0" + ], + "filament_cooling_before_tower": [ + "0" + ], + "filament_tower_interface_pre_extrusion_dist": [ + "10" + ], + "filament_tower_interface_pre_extrusion_length": [ + "0" + ], + "filament_tower_ironing_area": [ + "4" + ], + "filament_tower_interface_purge_volume": [ + "20" + ], + "filament_tower_interface_print_temp": [ + "-1" + ], + "filament_density": [ + "1.24" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_dev_ams_drying_ams_limitations": [ + "1" + ], + "filament_dev_ams_drying_temperature": [ + "40.0", + "40.0", + "40.0", + "40.0" + ], + "filament_dev_ams_drying_time": [ + "8.0", + "8.0", + "8.0", + "8.0" + ], + "filament_dev_drying_softening_temperature": [ + "40.0" + ], + "filament_dev_ams_drying_heat_distortion_temperature": [ + "45.0" + ], + "filament_dev_drying_cooling_temperature": [ + "35.0" + ], + "filament_dev_chamber_drying_bed_temperature": [ + "90.0" + ], + "filament_dev_chamber_drying_time": [ + "12.0" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; Filament-specific end gcode \n;END gcode for filament" + ], + "filament_extruder_compatibility": [ + "0" + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_flush_temp": [ + "0" + ], + "filament_flush_volumetric_speed": [ + "0" + ], + "filament_max_volumetric_speed": [ + "24.5" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_settings_id": [ + "" + ], + "filament_soluble": [ + "0" + ], + "filament_start_gcode": [ + "; Filament start gcode" + ], + "filament_type": [ + "PLA" + ], + "filament_vendor": [ + "QIDI" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_wipe": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_ramming_travel_time": [ + "0" + ], + "filament_pre_cooling_temperature": [ + "0" + ], + "filament_ramming_volumetric_speed": [ + "-1" + ], + "filament_prime_volume": [ + "30" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp_initial_layer": [ + "60" + ], + "hot_plate_temp": [ + "60" + ], + "nozzle_temperature_initial_layer": [ + "210" + ], + "nozzle_temperature": [ + "210" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "95%" + ], + "pressure_advance": [ + "0.042" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "8" + ], + "slow_down_min_speed": [ + "20" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "supertack_plate_temp": [ + "45" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "60" + ], + "textured_plate_temp": [ + "60" + ] +} diff --git a/resources/profiles/Qidi/machine/Qidi Q2 0.4 nozzle.json b/resources/profiles/Qidi/machine/Qidi Q2 0.4 nozzle.json index 6f3115dbd5..6a0a91b2ac 100644 --- a/resources/profiles/Qidi/machine/Qidi Q2 0.4 nozzle.json +++ b/resources/profiles/Qidi/machine/Qidi Q2 0.4 nozzle.json @@ -17,7 +17,7 @@ "cooling_tube_length": "0", "parking_pos_retraction": "0", "extra_loading_move": "5", - "change_filament_gcode": "G1 Z{max_layer_z + 3.0} F1200\nTOOL_CHANGE_START F=[current_extruder] T=[next_extruder]\nBUFFER_MONITORING ENABLE=0\nDISABLE_ALL_SENSOR\nM106 S255\nMOVE_TO_TRASH\n{if long_retractions_when_cut[previous_extruder]}\nG1 E-{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{else}\nG1 E-10 F{old_filament_e_feedrate}\n{endif}\nM400\nCUT_FILAMENT T=[current_extruder]\nMOVE_TO_TRASH\nM106 P2 S0\nUNLOAD_T[current_extruder]\nT[next_extruder]\n{if nozzle_temperature_range_high[current_extruder] >= nozzle_temperature_range_high[next_extruder]}\nM104 S{nozzle_temperature_range_high[current_extruder]}\n{else}\nM104 S{nozzle_temperature_range_high[next_extruder]}\n{endif}\n; FLUSH_START\nM106 S25\nG1 E30 F300\n; FLUSH_END\n{if long_retractions_when_cut[previous_extruder]}\nG1 E{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{endif}\n{if flush_length_1 > 1}\n; FLUSH_START\n{if flush_length_1 > 23.7}\nG1 E23.7 F{old_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{old_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\n{else}\nG1 E{flush_length_1} F{old_filament_e_feedrate}\n{endif}\nG1 E-[old_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_2 > 1}\n; FLUSH_START\nG1 X92 F9000\nG1 E[old_retract_length_toolchange] F300\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_3 > 1}\n; FLUSH_START\nG1 X85 F9000\nG1 E[new_retract_length_toolchange] F300\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_4 > 1}\n; FLUSH_START\nG1 X92 F9000\nG1 E[new_retract_length_toolchange] F300\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\nM400\nM106 S255\nM104 S[new_filament_temp]\nINIT_SYNC_BUFFER_STATE\nBUFFER_MONITORING ENABLE=1\nG1 E10 F25 \nM109 S[new_filament_temp]\nG1 E-5 F1800\nCLEAR_OOZE\nTOOL_CHANGE_END\nG1 Y270 F8000\nM106 S0\nG1 E2 F1800\nENABLE_ALL_SENSOR\n", + "change_filament_gcode": "{if current_extruder != next_extruder}\nG1 Z{max_layer_z + 3.0} F1200\nTOOL_CHANGE_START F=[current_extruder] T=[next_extruder]\nBUFFER_MONITORING ENABLE=0\nDISABLE_ALL_SENSOR\nM106 S255\nMOVE_TO_TRASH\n{if long_retractions_when_cut[previous_extruder]}\nG1 E-{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{else}\nG1 E-10 F{old_filament_e_feedrate}\n{endif}\nM400\nCUT_FILAMENT T=[current_extruder]\nMOVE_TO_TRASH\nM106 P2 S0\nUNLOAD_T[current_extruder]\nT[next_extruder]\n{if nozzle_temperature_range_high[current_extruder] >= nozzle_temperature_range_high[next_extruder]}\nM104 S{nozzle_temperature_range_high[current_extruder]}\n{else}\nM104 S{nozzle_temperature_range_high[next_extruder]}\n{endif}\n; FLUSH_START\nM106 S25\nG1 E30 F300\n; FLUSH_END\n{if long_retractions_when_cut[previous_extruder]}\nG1 E{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{endif}\n{if flush_length_1 > 1}\n; FLUSH_START\n{if flush_length_1 > 23.7}\nG1 E23.7 F{old_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{old_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\n{else}\nG1 E{flush_length_1} F{old_filament_e_feedrate}\n{endif}\nG1 E-[old_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_2 > 1}\n; FLUSH_START\nG1 X92 F9000\nG1 E[old_retract_length_toolchange] F300\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_3 > 1}\n; FLUSH_START\nG1 X85 F9000\nG1 E[new_retract_length_toolchange] F300\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_4 > 1}\n; FLUSH_START\nG1 X92 F9000\nG1 E[new_retract_length_toolchange] F300\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\nM400\nM106 S255\nM104 S[new_filament_temp]\nINIT_SYNC_BUFFER_STATE\nBUFFER_MONITORING ENABLE=1\nG1 E10 F25 \nM109 S[new_filament_temp]\nG1 E-5 F1800\nCLEAR_OOZE\nTOOL_CHANGE_END\nG1 Y270 F8000\nM106 S0\nG1 E2 F1800\nENABLE_ALL_SENSOR\n{endif}\n", "default_filament_profile": [ "QIDI PLA Rapido @Qidi Q2 0.4 nozzle" ], diff --git a/resources/profiles/Qidi/machine/Qidi Q2C 0.4 nozzle.json b/resources/profiles/Qidi/machine/Qidi Q2C 0.4 nozzle.json index fbf61a6af9..9d4683885f 100644 --- a/resources/profiles/Qidi/machine/Qidi Q2C 0.4 nozzle.json +++ b/resources/profiles/Qidi/machine/Qidi Q2C 0.4 nozzle.json @@ -17,7 +17,7 @@ "cooling_tube_length": "0", "parking_pos_retraction": "0", "extra_loading_move": "5", - "change_filament_gcode": "G1 Z{max_layer_z + 3.0} F1200\nTOOL_CHANGE_START F=[current_extruder] T=[next_extruder]\nBUFFER_MONITORING ENABLE=0\nDISABLE_ALL_SENSOR\nM106 S255\nMOVE_TO_TRASH\n{if long_retractions_when_cut[previous_extruder]}\nG1 E-{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{else}\nG1 E-10 F{old_filament_e_feedrate}\n{endif}\nM400\nCUT_FILAMENT T=[current_extruder]\nMOVE_TO_TRASH\nM106 P2 S0\nUNLOAD_T[current_extruder]\nT[next_extruder]\n{if nozzle_temperature_range_high[current_extruder] >= nozzle_temperature_range_high[next_extruder]}\nM104 S{nozzle_temperature_range_high[current_extruder]}\n{else}\nM104 S{nozzle_temperature_range_high[next_extruder]}\n{endif}\n; FLUSH_START\nM106 S25\nG1 E30 F300\n; FLUSH_END\n{if long_retractions_when_cut[previous_extruder]}\nG1 E{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{endif}\n{if flush_length_1 > 1}\n; FLUSH_START\n{if flush_length_1 > 23.7}\nG1 E23.7 F{old_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{old_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\n{else}\nG1 E{flush_length_1} F{old_filament_e_feedrate}\n{endif}\nG1 E-[old_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_2 > 1}\n; FLUSH_START\nG1 X92 F9000\nG1 E[old_retract_length_toolchange] F300\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_3 > 1}\n; FLUSH_START\nG1 X85 F9000\nG1 E[new_retract_length_toolchange] F300\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_4 > 1}\n; FLUSH_START\nG1 X92 F9000\nG1 E[new_retract_length_toolchange] F300\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\nM400\nM106 S255\nM104 S[new_filament_temp]\nINIT_SYNC_BUFFER_STATE\nBUFFER_MONITORING ENABLE=1\nG1 E10 F25 \nM109 S[new_filament_temp]\nG1 E-5 F1800\nCLEAR_OOZE\nTOOL_CHANGE_END\nG1 Y270 F8000\nM106 S0\nG1 E2 F1800\nENABLE_ALL_SENSOR\n", + "change_filament_gcode": "{if current_extruder != next_extruder}\nG1 Z{max_layer_z + 3.0} F1200\nTOOL_CHANGE_START F=[current_extruder] T=[next_extruder]\nBUFFER_MONITORING ENABLE=0\nDISABLE_ALL_SENSOR\nM106 S255\nMOVE_TO_TRASH\n{if long_retractions_when_cut[previous_extruder]}\nG1 E-{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{else}\nG1 E-10 F{old_filament_e_feedrate}\n{endif}\nM400\nCUT_FILAMENT T=[current_extruder]\nMOVE_TO_TRASH\nM106 P2 S0\nUNLOAD_T[current_extruder]\nT[next_extruder]\n{if nozzle_temperature_range_high[current_extruder] >= nozzle_temperature_range_high[next_extruder]}\nM104 S{nozzle_temperature_range_high[current_extruder]}\n{else}\nM104 S{nozzle_temperature_range_high[next_extruder]}\n{endif}\n; FLUSH_START\nM106 S25\nG1 E30 F300\n; FLUSH_END\n{if long_retractions_when_cut[previous_extruder]}\nG1 E{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{endif}\n{if flush_length_1 > 1}\n; FLUSH_START\n{if flush_length_1 > 23.7}\nG1 E23.7 F{old_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{old_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\n{else}\nG1 E{flush_length_1} F{old_filament_e_feedrate}\n{endif}\nG1 E-[old_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_2 > 1}\n; FLUSH_START\nG1 X92 F9000\nG1 E[old_retract_length_toolchange] F300\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_3 > 1}\n; FLUSH_START\nG1 X85 F9000\nG1 E[new_retract_length_toolchange] F300\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_4 > 1}\n; FLUSH_START\nG1 X92 F9000\nG1 E[new_retract_length_toolchange] F300\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\nM400\nM106 S255\nM104 S[new_filament_temp]\nINIT_SYNC_BUFFER_STATE\nBUFFER_MONITORING ENABLE=1\nG1 E10 F25 \nM109 S[new_filament_temp]\nG1 E-5 F1800\nCLEAR_OOZE\nTOOL_CHANGE_END\nG1 Y270 F8000\nM106 S0\nG1 E2 F1800\nENABLE_ALL_SENSOR\n{endif}\n", "default_filament_profile": [ "QIDI PLA Rapido @Qidi Q2C 0.4 nozzle" ], diff --git a/resources/profiles/Qidi/machine/Qidi X-Max 4 0.4 nozzle.json b/resources/profiles/Qidi/machine/Qidi X-Max 4 0.4 nozzle.json index be754eb338..ef26c0a620 100644 --- a/resources/profiles/Qidi/machine/Qidi X-Max 4 0.4 nozzle.json +++ b/resources/profiles/Qidi/machine/Qidi X-Max 4 0.4 nozzle.json @@ -13,7 +13,7 @@ "bed_exclude_area": [ "0x0, 16x0, 16x13, 0x13, 0x0, 0x0, 0x0, 0x0, 0x13, 6x13, 6x23, 0x23, 0x13, 0x13, 0x13, 0x13, 0x387, 53x387, 53x390, 0x390, 0x387, 0x387, 0x397, 0x390, 338x390, 338x384, 390x384, 390x390, 0x390" ], - "change_filament_gcode": "G1 Z{max_layer_z + 3.0} F1200\nTOOL_CHANGE_START F=[current_extruder] T=[next_extruder]\nDISABLE_ALL_SENSOR\nM104 S{old_filament_temp - 10}\nM106 S255\n{if long_retractions_when_cut[previous_extruder]}\nG1 E-{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{else}\nG1 E-2 F{old_filament_e_feedrate}\n{endif}\nM400\nCUT_FILAMENT T=[current_extruder]\nMOVE_TO_TRASH\nM106 P2 S0\nUNLOAD_T[current_extruder]\nT[next_extruder]\nM106 S0\n{if nozzle_temperature_range_high[current_extruder] >= nozzle_temperature_range_high[next_extruder]}\nM104 S{nozzle_temperature_range_high[current_extruder]}\nM109.0 S{(nozzle_temperature_range_high[current_extruder])-25}\n{else}\nM104 S{nozzle_temperature_range_high[next_extruder]}\nM109.0 S{(nozzle_temperature_range_high[next_extruder])-25}\n{endif}\n{if long_retractions_when_cut[previous_extruder]}\nG1 E{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{endif}\n{if flush_length_1 > 1}\n; FLUSH_START\nG1 Y403.5 F2000\nG1 E{flush_length_1} F{old_filament_e_feedrate * 0.5}\n; FLUSH_END\n{endif}\n{if flush_length_2 > 1}\n; FLUSH_START\nG1 E{flush_length_2} F{new_filament_e_feedrate * 0.5}\n; FLUSH_END\n{endif}\n{if flush_length_3 > 1}\n; FLUSH_START\nG1 E{flush_length_3} F{new_filament_e_feedrate * 0.5}\n; FLUSH_END\n{endif}\n{if flush_length_4 > 1}\n; FLUSH_START\nG1 E{flush_length_4} F{new_filament_e_feedrate * 0.5}\n; FLUSH_END\n{endif}\nM400\nM106 S180\nM104 S{new_filament_temp - 10}\nG1 E1 F10\nM109.1 S{new_filament_temp - 10}\nG1 E-4 F1000\nG4 P2000\nM204 S5000\nG1 Y403 F2000\nG1 X163 F8000\nG1 X145 F5000\nG1 X163 F3000\nG1 X145 F2000\nG1 X175 F6000\nG1 X163\nG1 X175\nG1 X163\nG1 X175\nG1 X163\nG1 X180 F8000\nG1 Y380\nG1 X116\nG4 P2000\nG1 Y403 F3000\nG1 X130\nG1 X100 F8000\nG1 Y380\nG1 X116\nG1 Y403 F3000\nG1 X130 F3000\nG1 X100 F8000\nG1 Y380\nM104 S[new_filament_temp]\nTOOL_CHANGE_END\nG1 E{new_retract_length_toolchange + 1} F{new_filament_e_feedrate}\nENABLE_ALL_SENSOR\n", + "change_filament_gcode": "{if current_extruder != next_extruder}\nG1 Z{max_layer_z + 3.0} F1200\nTOOL_CHANGE_START F=[current_extruder] T=[next_extruder]\nDISABLE_ALL_SENSOR\nM104 S{old_filament_temp - 10}\nM106 S255\n{if long_retractions_when_cut[previous_extruder]}\nG1 E-{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{else}\nG1 E-2 F{old_filament_e_feedrate}\n{endif}\nM400\nCUT_FILAMENT T=[current_extruder]\nMOVE_TO_TRASH\nM106 P2 S0\nUNLOAD_T[current_extruder]\nT[next_extruder]\nM106 S0\n{if nozzle_temperature_range_high[current_extruder] >= nozzle_temperature_range_high[next_extruder]}\nM104 S{nozzle_temperature_range_high[current_extruder]}\nM109.0 S{(nozzle_temperature_range_high[current_extruder])-25}\n{else}\nM104 S{nozzle_temperature_range_high[next_extruder]}\nM109.0 S{(nozzle_temperature_range_high[next_extruder])-25}\n{endif}\n{if long_retractions_when_cut[previous_extruder]}\nG1 E{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{endif}\n{if flush_length_1 > 1}\n; FLUSH_START\nG1 Y403.5 F2000\nG1 E{flush_length_1} F{old_filament_e_feedrate * 0.5}\n; FLUSH_END\n{endif}\n{if flush_length_2 > 1}\n; FLUSH_START\nG1 E{flush_length_2} F{new_filament_e_feedrate * 0.5}\n; FLUSH_END\n{endif}\n{if flush_length_3 > 1}\n; FLUSH_START\nG1 E{flush_length_3} F{new_filament_e_feedrate * 0.5}\n; FLUSH_END\n{endif}\n{if flush_length_4 > 1}\n; FLUSH_START\nG1 E{flush_length_4} F{new_filament_e_feedrate * 0.5}\n; FLUSH_END\n{endif}\nM400\nM106 S180\nM104 S{new_filament_temp - 10}\nG1 E1 F10\nM109.1 S{new_filament_temp - 10}\nG1 E-4 F1000\nG4 P2000\nM204 S5000\nG1 Y403 F2000\nG1 X163 F8000\nG1 X145 F5000\nG1 X163 F3000\nG1 X145 F2000\nG1 X175 F6000\nG1 X163\nG1 X175\nG1 X163\nG1 X175\nG1 X163\nG1 X180 F8000\nG1 Y380\nG1 X116\nG4 P2000\nG1 Y403 F3000\nG1 X130\nG1 X100 F8000\nG1 Y380\nG1 X116\nG1 Y403 F3000\nG1 X130 F3000\nG1 X100 F8000\nG1 Y380\nM104 S[new_filament_temp]\nTOOL_CHANGE_END\nG1 E{new_retract_length_toolchange + 1} F{new_filament_e_feedrate}\nENABLE_ALL_SENSOR\n{endif}\n", "default_filament_profile": [ "QIDI PLA Rapido @Qidi X-Max 4 0.4 nozzle" ], diff --git a/resources/profiles/Qidi/machine/Qidi X-Plus 4 0.4 nozzle.json b/resources/profiles/Qidi/machine/Qidi X-Plus 4 0.4 nozzle.json index c4e758a451..82e9da78cb 100644 --- a/resources/profiles/Qidi/machine/Qidi X-Plus 4 0.4 nozzle.json +++ b/resources/profiles/Qidi/machine/Qidi X-Plus 4 0.4 nozzle.json @@ -60,7 +60,7 @@ "2" ], "single_extruder_multi_material": "1", - "change_filament_gcode": "{if max_layer_z < 12}\nG1 Z15 F1200\n{else}\nG1 Z{max_layer_z + 3.0} F1200\n{endif}\nTOOL_CHANGE_START F=[current_extruder] T=[next_extruder]\nDISABLE_ALL_SENSOR\n{if long_retractions_when_cut[previous_extruder]}\nMOVE_TO_TRASH\nG1 E-{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\nM400\n{else}\nG1 E-5 F{old_filament_e_feedrate}\n{endif}\nCUT_FILAMENT T=[current_extruder]\nMOVE_TO_TRASH\nM400\n{if nozzle_temperature_range_high[current_extruder] >= nozzle_temperature_range_high[next_extruder]}\nM104 S{nozzle_temperature_range_high[current_extruder]}\n{else}\nM104 S{nozzle_temperature_range_high[next_extruder]}\n{endif}\nM106 S0\nM106 P2 S0\nUNLOAD_T[current_extruder]\nG92 E0\nM83\nG1 E2 F50\nT[next_extruder]\n{if nozzle_temperature_range_high[current_extruder] >= nozzle_temperature_range_high[next_extruder]}\nSET_HEATER_TEMPERATURE HEATER=extruder TARGET={nozzle_temperature_range_high[current_extruder]} WAIT=1\n{else}\nSET_HEATER_TEMPERATURE HEATER=extruder TARGET={nozzle_temperature_range_high[next_extruder]} WAIT=1\n{endif}\n{if long_retractions_when_cut[previous_extruder]}\nG1 E{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{endif}\nM400\nM106 S60\n; FLUSH_START\nG1 E1 F50\nG1 E{65.5 * 0.58} F{old_filament_e_feedrate}\nG1 E{65.5 * 0.02} F50\nG1 E{65.5 * 0.18} F{old_filament_e_feedrate}\nG1 E{65.5 * 0.02} F50\nG1 E{65.5 * 0.18} F{old_filament_e_feedrate}\nG1 E{65.5 * 0.02} F50\nG1 E-[old_retract_length_toolchange] F1800\n; FLUSH_END\n{if flush_length_1 > 1}\nM400\nM106 S255\nG91\nG1 X-5 F60\nG1 X5 F60\nG90\nCLEAR_FLUSH\nM400\nM106 S60\n; FLUSH_START\nG1 E[old_retract_length_toolchange] F300\nG1 E{flush_length_1 * 0.58} F{new_filament_e_feedrate}\nG1 E{flush_length_1 * 0.02} F50\nG1 E{flush_length_1 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_1 * 0.02} F50\nG1 E{flush_length_1 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_1 * 0.02} F50\nG1 E-[old_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_2 > 1}\nM400\nM106 S255\nG91\nG1 X-5 F60\nG1 X5 F60\nG90\nCLEAR_FLUSH\nM400\nM106 S60\n; FLUSH_START\nG1 E[old_retract_length_toolchange] F300\nG1 E{flush_length_2 * 0.58} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_3 > 1}\nM400\nM106 S255\nG91\nG1 X-5 F60\nG1 X5 F60\nG90\nCLEAR_FLUSH\nM400\nM106 S60\n; FLUSH_START\nG1 E[new_retract_length_toolchange] F300\nG1 E{flush_length_3 * 0.58} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_4 > 1}\nM400\nM106 S255\nG91\nG1 X-5 F60\nG1 X5 F60\nG90\nCLEAR_FLUSH\nM400\nM106 S60\n; FLUSH_START\nG1 E[new_retract_length_toolchange] F300\nG1 E{flush_length_4 * 0.58} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\nM104 S[new_filament_temp]\nM400\nM106 S255\nG91\nG1 X-5 F60\nG1 X5 F60\nG90\nM109 S[new_filament_temp]\nG92 E0\nM400\nCLEAR_FLUSH\nCLEAR_OOZE\nM400\nM106 S0\nTOOL_CHANGE_END\nG1 Y305 F9000\nENABLE_ALL_SENSOR", + "change_filament_gcode": "{if current_extruder != next_extruder}\n{if max_layer_z < 12}\nG1 Z15 F1200\n{else}\nG1 Z{max_layer_z + 3.0} F1200\n{endif}\nTOOL_CHANGE_START F=[current_extruder] T=[next_extruder]\nDISABLE_ALL_SENSOR\n{if long_retractions_when_cut[previous_extruder]}\nMOVE_TO_TRASH\nG1 E-{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\nM400\n{else}\nG1 E-5 F{old_filament_e_feedrate}\n{endif}\nCUT_FILAMENT T=[current_extruder]\nMOVE_TO_TRASH\nM400\n{if nozzle_temperature_range_high[current_extruder] >= nozzle_temperature_range_high[next_extruder]}\nM104 S{nozzle_temperature_range_high[current_extruder]}\n{else}\nM104 S{nozzle_temperature_range_high[next_extruder]}\n{endif}\nM106 S0\nM106 P2 S0\nUNLOAD_T[current_extruder]\nG92 E0\nM83\nG1 E2 F50\nT[next_extruder]\n{if nozzle_temperature_range_high[current_extruder] >= nozzle_temperature_range_high[next_extruder]}\nSET_HEATER_TEMPERATURE HEATER=extruder TARGET={nozzle_temperature_range_high[current_extruder]} WAIT=1\n{else}\nSET_HEATER_TEMPERATURE HEATER=extruder TARGET={nozzle_temperature_range_high[next_extruder]} WAIT=1\n{endif}\n{if long_retractions_when_cut[previous_extruder]}\nG1 E{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{endif}\nM400\nM106 S60\n; FLUSH_START\nG1 E1 F50\nG1 E{65.5 * 0.58} F{old_filament_e_feedrate}\nG1 E{65.5 * 0.02} F50\nG1 E{65.5 * 0.18} F{old_filament_e_feedrate}\nG1 E{65.5 * 0.02} F50\nG1 E{65.5 * 0.18} F{old_filament_e_feedrate}\nG1 E{65.5 * 0.02} F50\nG1 E-[old_retract_length_toolchange] F1800\n; FLUSH_END\n{if flush_length_1 > 1}\nM400\nM106 S255\nG91\nG1 X-5 F60\nG1 X5 F60\nG90\nCLEAR_FLUSH\nM400\nM106 S60\n; FLUSH_START\nG1 E[old_retract_length_toolchange] F300\nG1 E{flush_length_1 * 0.58} F{new_filament_e_feedrate}\nG1 E{flush_length_1 * 0.02} F50\nG1 E{flush_length_1 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_1 * 0.02} F50\nG1 E{flush_length_1 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_1 * 0.02} F50\nG1 E-[old_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_2 > 1}\nM400\nM106 S255\nG91\nG1 X-5 F60\nG1 X5 F60\nG90\nCLEAR_FLUSH\nM400\nM106 S60\n; FLUSH_START\nG1 E[old_retract_length_toolchange] F300\nG1 E{flush_length_2 * 0.58} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_3 > 1}\nM400\nM106 S255\nG91\nG1 X-5 F60\nG1 X5 F60\nG90\nCLEAR_FLUSH\nM400\nM106 S60\n; FLUSH_START\nG1 E[new_retract_length_toolchange] F300\nG1 E{flush_length_3 * 0.58} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\n{if flush_length_4 > 1}\nM400\nM106 S255\nG91\nG1 X-5 F60\nG1 X5 F60\nG90\nCLEAR_FLUSH\nM400\nM106 S60\n; FLUSH_START\nG1 E[new_retract_length_toolchange] F300\nG1 E{flush_length_4 * 0.58} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E-[new_retract_length_toolchange] F1800\n; FLUSH_END\n{endif}\nM104 S[new_filament_temp]\nM400\nM106 S255\nG91\nG1 X-5 F60\nG1 X5 F60\nG90\nM109 S[new_filament_temp]\nG92 E0\nM400\nCLEAR_FLUSH\nCLEAR_OOZE\nM400\nM106 S0\nTOOL_CHANGE_END\nG1 Y305 F9000\nENABLE_ALL_SENSOR\n{endif}", "is_support_multi_box": "0", "machine_pause_gcode": "PAUSE", "thumbnails": [ diff --git a/resources/profiles/Qidi/machine/Qidi X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/machine/Qidi X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..54fed33aea --- /dev/null +++ b/resources/profiles/Qidi/machine/Qidi X-Plus 5 0.2 nozzle.json @@ -0,0 +1,28 @@ +{ + "type": "machine", + "name": "Qidi X-Plus 5 0.2 nozzle", + "inherits": "Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "setting_id": "prjWhtWxCsXqcrHr", + "instantiation": "true", + "printer_model": "Qidi X-Plus 5", + "printer_variant": "0.2", + "default_filament_profile": [ + "QIDI PLA Rapido @Qidi X-Plus 5 0.2 nozzle" + ], + "default_print_profile": "0.10mm Standard @X-Plus 5 0.2 nozzle", + "max_layer_height": [ + "0.14" + ], + "min_layer_height": [ + "0.04" + ], + "nozzle_diameter": [ + "0.2" + ], + "printer_agent": "qidi", + "retraction_length": [ + "0.4" + ], + "support_box_temp_control": "1" +} diff --git a/resources/profiles/Qidi/machine/Qidi X-Plus 5 0.4 nozzle.json b/resources/profiles/Qidi/machine/Qidi X-Plus 5 0.4 nozzle.json new file mode 100644 index 0000000000..f23f86af2a --- /dev/null +++ b/resources/profiles/Qidi/machine/Qidi X-Plus 5 0.4 nozzle.json @@ -0,0 +1,88 @@ +{ + "type": "machine", + "name": "Qidi X-Plus 5 0.4 nozzle", + "inherits": "fdm_machine_x_common", + "from": "system", + "setting_id": "exeoc5LTdCkPeWLD", + "instantiation": "true", + "printer_model": "Qidi X-Plus 5", + "auxiliary_fan": "1", + "bed_exclude_area": [ + "0x0,9x0,9x13,0x13" + ], + "box_id": "4", + "change_filament_gcode": "{if current_extruder != next_extruder}\n{if max_layer_z + 3 > max_print_height}\nG0 Z{max_print_height} F1200\n{else}\nG0 Z{max_layer_z + 3} F1200\n{endif}\nTOOL_CHANGE_START F=[current_extruder] T=[next_extruder]\nDISABLE_ALL_SENSOR\nM104 S{old_filament_temp - 10}\nM106 S255\n{if long_retractions_when_cut[previous_extruder]}\nG1 E-{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{else}\nG1 E-5 F{old_filament_e_feedrate}\n{endif}\nM400\nCUT_FILAMENT T=[current_extruder]\nMOVE_TO_TRASH\nM106 P2 S0\nUNLOAD_T[current_extruder]\nT[next_extruder]\nM106 S0\n{if nozzle_temperature_range_high[current_extruder] >= nozzle_temperature_range_high[next_extruder]}\nM104 S{nozzle_temperature_range_high[current_extruder]}\nM109.0 S{(nozzle_temperature_range_high[current_extruder])-25}\n{else}\nM104 S{nozzle_temperature_range_high[next_extruder]}\nM109.0 S{(nozzle_temperature_range_high[next_extruder])-25}\n{endif}\n{if long_retractions_when_cut[previous_extruder]}\nG1 E{retraction_distances_when_cut[previous_extruder]} F{old_filament_e_feedrate}\n{endif}\n{if flush_length_1 > 1}\n; FLUSH_START\nG1 E{flush_length_1} F{old_filament_e_feedrate * 0.5}\n; FLUSH_END\n{endif}\n{if flush_length_2 > 1}\n; FLUSH_START\nG1 E{flush_length_2} F{new_filament_e_feedrate * 0.5}\n; FLUSH_END\n{endif}\n{if flush_length_3 > 1}\n; FLUSH_START\nG1 E{flush_length_3} F{new_filament_e_feedrate * 0.5}\n; FLUSH_END\n{endif}\n{if flush_length_4 > 1}\n; FLUSH_START\nG1 E{flush_length_4} F{new_filament_e_feedrate * 0.5}\n; FLUSH_END\n{endif}\nM400\nM106 S180\nM104 S{new_filament_temp - 10}\nG1 E1 F10\nM109.1 S{new_filament_temp - 10}\nG1 E-4 F1000\nG4 P2000\nM204 S5000\nG1 X109 F8000\nG1 X95 F5000\nG1 X109 F8000\nG1 X95 F5000\nG1 X140 F10000\nG1 Y319\nG1 X110\nG4 P2000\nG1 Y339 F2000\nG1 X123 F6000\nG1 X110\nG1 X123\nG1 X110\nG1 X123\nG1 X110\nG1 X123\nG1 X95\nG1 Y319 F10000\nM104 S[new_filament_temp]\nTOOL_CHANGE_END\nG1 E{new_retract_length_toolchange} F{new_filament_e_feedrate}\nENABLE_ALL_SENSOR\n{endif}", + "default_bed_type": "Textured PEI Plate", + "default_filament_profile": [ + "QIDI PLA Rapido @Qidi X-Plus 5 0.4 nozzle" + ], + "default_print_profile": "0.20mm Standard @X-Plus 5", + "enable_long_retraction_when_cut": "2", + "extruder_clearance_dist_to_rod": "42", + "extruder_clearance_height_to_lid": "168", + "extruder_clearance_height_to_rod": "42", + "extruder_clearance_max_radius": "75", + "fan_direction": "left", + "gcode_flavor": "klipper", + "is_support_3mf": "1", + "is_support_mqtt": "1", + "is_support_multi_box": "1", + "is_support_polar_cooler": "1", + "is_support_timelapse": "1", + "layer_change_gcode": "{if timelapse_type == 1} ; timelapse with wipe tower\nG92 E0\nG1 E-[retraction_length] F1800\n{if layer_z + 0.4 > max_print_height}\nG2 Z{max_print_height} I0.86 J0.86 P1 F20000 ; spiral lift a little\n{else}\nG2 Z{layer_z + 0.4} I0.86 J0.86 P1 F20000 ; spiral lift a little\n{endif}\nMOVE_TO_TRASH\n{if layer_z <=25}\nG1 Z25\n{endif}\nG92 E0\nM400\nTIMELAPSE_TAKE_FRAME\nG1 E[retraction_length] F300\nG1 X140 F8000\nG1 Y319\n{if layer_z <=25}\nG1 Z[layer_z]\n{endif}\n{elsif timelapse_type == 0} ; timelapse without wipe tower\nTIMELAPSE_TAKE_FRAME\n{endif}\nG92 E0\nSET_PRINT_STATS_INFO CURRENT_LAYER={layer_num + 1}", + "machine_end_gcode": "SET_PRINT_MAIN_STATUS MAIN_STATUS=print_end\nDISABLE_BOX_HEATER\nM141 S0\nM140 S0\nDISABLE_ALL_SENSOR\nG1 E-3 F1800\n{if max_layer_z + 3 > max_print_height}\nG0 Z{max_print_height} F600\n{else}\nG0 Z{max_layer_z + 3} F600\n{endif}\nUNLOAD_FILAMENT T=[current_extruder]\nG0 Y320 F12000\nG0 X105 Y320 F12000\n{if max_layer_z < max_print_height / 2}G1 Z{max_print_height / 2 + 10} F600{else}G1 Z{min(max_print_height, max_layer_z + 3)}{endif}\nM104 S0\nPRINT_END", + "machine_max_acceleration_x": [ + "20000" + ], + "machine_max_acceleration_y": [ + "20000" + ], + "machine_max_jerk_e": [ + "4" + ], + "machine_max_jerk_x": [ + "9" + ], + "machine_max_jerk_y": [ + "9" + ], + "machine_max_jerk_z": [ + "4" + ], + "machine_max_speed_x": [ + "600" + ], + "machine_max_speed_y": [ + "600" + ], + "machine_max_speed_z": [ + "20" + ], + "machine_pause_gcode": "PAUSE", + "machine_start_gcode": ";===== PRINT_PHASE_INIT =====\nSET_PRINT_STATS_INFO TOTAL_LAYER=[total_layer_count]\nSET_PRINT_MAIN_STATUS MAIN_STATUS=print_start\nM220 S100\nM221 S100\nDISABLE_ALL_SENSOR\nM1002 R1\nM107\nCLEAR_PAUSE\nM140 S[bed_temperature_initial_layer_single]\nM141 S[chamber_temperature]\nG29.0\nSET_PRINT_SUB_STATUS SUB_STATUS=tool_head_reset\nG28\n\n;===== BOX_PREPAR =====\nSET_PRINT_SUB_STATUS SUB_STATUS=change_filament\nBOX_PRINT_START EXTRUDER=[initial_no_support_extruder] HOTENDTEMP={nozzle_temperature_range_high[initial_tool]}\nM400\nEXTRUSION_AND_FLUSH HOTEND=[nozzle_temperature_initial_layer]\n\n;===== CLEAR_NOZZLE =====\nSET_PRINT_SUB_STATUS SUB_STATUS=flush_filament\nG1 Z20 F480\nMOVE_TO_TRASH\n{if chamber_temperature[0] == 0}\nM106 P3 S[during_print_exhaust_fan_speed]\n{else}\nM106 P3 S0\n{endif}\nM1004\nM106 S0\nM109 S[nozzle_temperature_initial_layer]\nG92 E0\nM83\nG1 E5 F80\nG1 E200 F300\nM400\nM106 S255\nG1 E-3 F1000\nM104 S140\nSET_PRINT_SUB_STATUS SUB_STATUS=clear_nozzle\nM109.1 S{nozzle_temperature_initial_layer[0]-30}\nM204 S10000\nG1 X109 F10000\nG1 X95 F6000\nG1 X109 F10000\nG1 X95 F6000\nG1 X109 F10000\nG1 X95 F6000\nG1 Y318\nG1 X151 F15000\nG1 Y327\nG1 Z5 F480\nM400\nprobe samples=1\nG91\nG1 Z0.1\nG90\nM106 S255\nM109.1 S150\nG91\nG1 X20 F200\nG1 Y3\nG1 X-20\nG1 Y-3\nG1 X20\nG90\nG2 I0.5 J0.5 F480\nG2 I0.5 J0.5\nG2 I0.5 J0.5\nG1 Z10\nG1 Y318 F12000\nG1 X77\nG1 Y338 F2000\nG1 X95 F12000\nG1 X123\nG1 X110\nG1 X123\nG1 X110\nG1 X123\nG1 X110\nG1 X123\nG1 X110\nG1 X140\nG1 X160 Y160\nM106 S0\nSET_PRINT_SUB_STATUS SUB_STATUS=wait_bed_temp\nM190 S[bed_temperature_initial_layer_single]\nSET_PRINT_SUB_STATUS SUB_STATUS=wait_chamber_temp\nM191 S[chamber_temperature]\nG1 Y-2 F15000\nG1 X15\nG1 X-2 F5000\nG4 P1000\nG1 X-1 F1000\nG1 X-2 F5000\nG4 P1000\nG1 E-4 F1800\nG1 X15 F3000\nG1 X20 Y20 F15000\nSET_PRINT_SUB_STATUS SUB_STATUS=z_tilt_adjust\nZ_TILT_ADJUST\nSET_PRINT_SUB_STATUS SUB_STATUS=auto_bed_adjust\nG29\nM1002 A1\nG1 X160 Y160 Z10 F20000\nM1006 Z{10 - ((nozzle_temperature_initial_layer[initial_tool] - 130) / 14 - 5.0) / 100}\nG0 Y-1\nM109 S[nozzle_temperature_initial_layer]\nENABLE_ALL_SENSOR\n\n;===== PRINT_START =====\n; LAYER_HEIGHT: 0.2\nT[initial_tool]\nM140 S[bed_temperature_initial_layer_single]\nM104 S[nozzle_temperature_initial_layer]\nM141 S[chamber_temperature]\nG4 P3000\nprobe samples=1\nG91\nG0 Z0.6 F480\nG90\nG1 X140 Y1 F20000\nG1 E5 F{filament_max_volumetric_speed[initial_no_support_extruder]/2/2.4053*60}\nG1 X180 E20 F{filament_max_volumetric_speed[initial_no_support_extruder]/2/2.4053*60}\nG1 Z1 F480\nSET_PRINT_MAIN_STATUS MAIN_STATUS=printing", + "nozzle_diameter": [ + "0.4" + ], + "nozzle_volume": [ + "125" + ], + "printable_area": [ + "0x0", + "320x0", + "320x320", + "0x320", + "0x0" + ], + "printable_height": "300", + "printer_agent": "qidi", + "printer_settings_id": "Qidi", + "retract_lift_below": [ + "299" + ], + "support_box_temp_control": "1", + "support_multi_bed_types": "1", + "thumbnail_size": [ + "50x50" + ], + "use_3mf": "1" +} diff --git a/resources/profiles/Qidi/machine/Qidi X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/machine/Qidi X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..649462eab9 --- /dev/null +++ b/resources/profiles/Qidi/machine/Qidi X-Plus 5 0.6 nozzle.json @@ -0,0 +1,31 @@ +{ + "type": "machine", + "name": "Qidi X-Plus 5 0.6 nozzle", + "inherits": "Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "setting_id": "C4EIoDQYYzDGANJA", + "instantiation": "true", + "printer_model": "Qidi X-Plus 5", + "printer_variant": "0.6", + "default_filament_profile": [ + "QIDI PLA Rapido @Qidi X-Plus 5 0.6 nozzle" + ], + "default_print_profile": "0.30mm Standard @X-Plus 5 0.6 nozzle", + "max_layer_height": [ + "0.42" + ], + "min_layer_height": [ + "0.12" + ], + "nozzle_diameter": [ + "0.6" + ], + "printer_agent": "qidi", + "retraction_length": [ + "1.4" + ], + "retraction_minimum_travel": [ + "3" + ], + "support_box_temp_control": "1" +} diff --git a/resources/profiles/Qidi/machine/Qidi X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/machine/Qidi X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..ed932902f9 --- /dev/null +++ b/resources/profiles/Qidi/machine/Qidi X-Plus 5 0.8 nozzle.json @@ -0,0 +1,31 @@ +{ + "type": "machine", + "name": "Qidi X-Plus 5 0.8 nozzle", + "inherits": "Qidi X-Plus 5 0.4 nozzle", + "from": "system", + "setting_id": "5eqkluxp0SrRzhV7", + "instantiation": "true", + "printer_model": "Qidi X-Plus 5", + "printer_variant": "0.8", + "default_filament_profile": [ + "QIDI PLA Rapido @Qidi X-Plus 5 0.8 nozzle" + ], + "default_print_profile": "0.40mm Standard @X-Plus 5 0.8 nozzle", + "max_layer_height": [ + "0.56" + ], + "min_layer_height": [ + "0.16" + ], + "nozzle_diameter": [ + "0.8" + ], + "printer_agent": "qidi", + "retract_length_toolchange": [ + "3" + ], + "retraction_length": [ + "3" + ], + "support_box_temp_control": "1" +} diff --git a/resources/profiles/Qidi/machine/Qidi X-Plus 5.json b/resources/profiles/Qidi/machine/Qidi X-Plus 5.json new file mode 100644 index 0000000000..afc1d9af54 --- /dev/null +++ b/resources/profiles/Qidi/machine/Qidi X-Plus 5.json @@ -0,0 +1,12 @@ +{ + "type": "machine_model", + "name": "Qidi X-Plus 5", + "model_id": "Qidi-XPlus-5", + "nozzle_diameter": "0.4;0.2;0.6;0.8", + "machine_tech": "FFF", + "family": "Qidi", + "bed_model": "qidi_xplus5_buildplate_model.stl", + "bed_texture": "qidi_xplus5_buildplate_texture.svg", + "hotend_model": "qidi_xseries_gen3_hotend.stl", + "default_materials": "Generic ABS @Qidi X-Plus 5 0.4 nozzle;Generic PLA @Qidi X-Plus 5 0.4 nozzle;QIDI ABS Odorless @Qidi X-Plus 5 0.4 nozzle;QIDI ABS Rapido @Qidi X-Plus 5 0.4 nozzle;QIDI PLA Rapido @Qidi X-Plus 5 0.2 nozzle;QIDI PLA Rapido @Qidi X-Plus 5 0.4 nozzle;QIDI PLA Rapido @Qidi X-Plus 5 0.6 nozzle;QIDI PLA Rapido @Qidi X-Plus 5 0.8 nozzle;QIDI PLA Rapido Matte @Qidi X-Plus 5 0.4 nozzle;QIDI PLA-CF @Qidi X-Plus 5 0.4 nozzle;Generic PLA Silk @Qidi X-Plus 5 0.4 nozzle;QIDI PLA Silk @Qidi X-Plus 5 0.4 nozzle;QIDI ASA @Qidi X-Plus 5 0.4 nozzle;QIDI PETG Basic @Qidi X-Plus 5 0.4 nozzle;QIDI PETG Rapido @Qidi X-Plus 5 0.4 nozzle;QIDI PETG Tough @Qidi X-Plus 5 0.4 nozzle;QIDI PETG Translucent @Qidi X-Plus 5 0.4 nozzle;QIDI PLA Basic @Qidi X-Plus 5 0.4 nozzle;QIDI PLA Matte Basic @Qidi X-Plus 5 0.4 nozzle;Generic PETG @Qidi X-Plus 5 0.4 nozzle" +} diff --git a/resources/profiles/Qidi/process/0.08mm High Quality @X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/process/0.08mm High Quality @X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..6ef2deee1a --- /dev/null +++ b/resources/profiles/Qidi/process/0.08mm High Quality @X-Plus 5 0.2 nozzle.json @@ -0,0 +1,70 @@ +{ + "type": "process", + "setting_id": "ojwggKwtZ95dDdGn", + "name": "0.08mm High Quality @X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_n_common", + "bottom_color_penetration_layers": "5", + "bottom_shell_layers": "5", + "bridge_flow": "1", + "default_acceleration": [ + "10000" + ], + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "initial_layer_infill_speed": [ + "70" + ], + "initial_layer_line_width": "0.25", + "initial_layer_print_height": "0.1", + "initial_layer_speed": [ + "40" + ], + "inner_wall_acceleration": [ + "0" + ], + "inner_wall_line_width": "0.22", + "inner_wall_speed": [ + "150" + ], + "internal_solid_infill_line_width": "0.22", + "layer_height": "0.08", + "line_width": "0.22", + "outer_wall_acceleration": [ + "5000" + ], + "outer_wall_line_width": "0.22", + "outer_wall_speed": [ + "100" + ], + "overhang_1_4_speed": [ + "60" + ], + "prime_tower_width": "60", + "prime_tower_brim_width": "-1", + "prime_tower_flat_ironing": "1", + "skin_infill_line_width": "0.22", + "skeleton_infill_line_width": "0.22", + "sparse_infill_line_width": "0.22", + "sparse_infill_pattern": "gyroid", + "sparse_infill_speed": [ + "100" + ], + "support_bottom_z_distance": "0.08", + "support_line_width": "0.22", + "support_top_z_distance": "0.08", + "top_color_penetration_layers": "7", + "top_shell_layers": "7", + "top_surface_line_width": "0.22", + "top_surface_speed": [ + "150" + ], + "travel_speed": [ + "500" + ], + "wall_loops": "4", + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/process/0.08mm High Quality @X-Plus 5.json b/resources/profiles/Qidi/process/0.08mm High Quality @X-Plus 5.json new file mode 100644 index 0000000000..5b76c79ef4 --- /dev/null +++ b/resources/profiles/Qidi/process/0.08mm High Quality @X-Plus 5.json @@ -0,0 +1,73 @@ +{ + "type": "process", + "setting_id": "pdbmnAHtrlkeD1D6", + "name": "0.08mm High Quality @X-Plus 5", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_n_common", + "bottom_color_penetration_layers": "7", + "bottom_shell_layers": "7", + "bridge_flow": "1", + "default_acceleration": [ + "4000" + ], + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "gap_infill_speed": [ + "210" + ], + "initial_layer_infill_speed": [ + "105" + ], + "initial_layer_speed": [ + "50" + ], + "inner_wall_acceleration": [ + "0" + ], + "inner_wall_speed": [ + "120" + ], + "internal_solid_infill_speed": [ + "150" + ], + "ironing_flow": "8%", + "layer_height": "0.08", + "outer_wall_acceleration": [ + "2000" + ], + "outer_wall_speed": [ + "60" + ], + "overhang_1_4_speed": [ + "60" + ], + "overhang_2_4_speed": [ + "30" + ], + "overhang_3_4_speed": [ + "10" + ], + "prime_tower_width": "60", + "prime_tower_brim_width": "-1", + "prime_tower_flat_ironing": "0", + "sparse_infill_speed": [ + "150" + ], + "sparse_infill_pattern": "gyroid", + "support_bottom_z_distance": "0.08", + "support_threshold_angle": "15", + "support_top_z_distance": "0.08", + "top_color_penetration_layers": "9", + "top_shell_layers": "9", + "top_shell_thickness": "1", + "top_surface_speed": [ + "150" + ], + "travel_speed": [ + "350" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/process/0.10mm Standard @X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/process/0.10mm Standard @X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..a8a9aa5f37 --- /dev/null +++ b/resources/profiles/Qidi/process/0.10mm Standard @X-Plus 5 0.2 nozzle.json @@ -0,0 +1,63 @@ +{ + "type": "process", + "setting_id": "3k8N3voNC9Kp0Ov6", + "name": "0.10mm Standard @X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_n_common", + "bottom_color_penetration_layers": "5", + "bottom_shell_layers": "5", + "bridge_flow": "1", + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "initial_layer_infill_speed": [ + "70" + ], + "initial_layer_line_width": "0.25", + "initial_layer_print_height": "0.1", + "initial_layer_speed": [ + "40" + ], + "inner_wall_acceleration": [ + "0" + ], + "inner_wall_line_width": "0.22", + "internal_solid_infill_line_width": "0.22", + "ironing_flow": "20%", + "ironing_speed": "20", + "layer_height": "0.1", + "line_width": "0.22", + "outer_wall_acceleration": [ + "5000" + ], + "outer_wall_line_width": "0.22", + "overhang_1_4_speed": [ + "60" + ], + "skin_infill_line_width": "0.22", + "outer_wall_speed": [ + "100" + ], + "prime_tower_width": "60", + "skeleton_infill_line_width": "0.22", + "sparse_infill_line_width": "0.22", + "sparse_infill_speed": [ + "100" + ], + "support_bottom_z_distance": "0.1", + "support_line_width": "0.22", + "support_top_z_distance": "0.1", + "top_color_penetration_layers": "7", + "top_shell_layers": "7", + "top_surface_line_width": "0.22", + "top_surface_speed": [ + "150" + ], + "travel_speed": [ + "500" + ], + "wall_loops": "4", + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/process/0.12mm Balanced Quality @X-Plus 5 0.2 nozzle.json b/resources/profiles/Qidi/process/0.12mm Balanced Quality @X-Plus 5 0.2 nozzle.json new file mode 100644 index 0000000000..1c1d304ccd --- /dev/null +++ b/resources/profiles/Qidi/process/0.12mm Balanced Quality @X-Plus 5 0.2 nozzle.json @@ -0,0 +1,66 @@ +{ + "type": "process", + "setting_id": "O20HfmdyTRg2xayA", + "name": "0.12mm Balanced Quality @X-Plus 5 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_n_common", + "bottom_color_penetration_layers": "5", + "bottom_shell_layers": "5", + "bridge_flow": "1", + "default_acceleration": [ + "10000" + ], + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "initial_layer_infill_speed": [ + "70" + ], + "initial_layer_line_width": "0.25", + "initial_layer_print_height": "0.1", + "initial_layer_speed": [ + "40" + ], + "inner_wall_acceleration": [ + "0" + ], + "inner_wall_line_width": "0.22", + "internal_solid_infill_line_width": "0.22", + "layer_height": "0.12", + "line_width": "0.22", + "outer_wall_acceleration": [ + "5000" + ], + "outer_wall_line_width": "0.22", + "outer_wall_speed": [ + "100" + ], + "overhang_1_4_speed": [ + "60" + ], + "prime_tower_width": "60", + "prime_tower_brim_width": "-1", + "prime_tower_flat_ironing": "1", + "skin_infill_line_width": "0.22", + "skeleton_infill_line_width": "0.22", + "sparse_infill_line_width": "0.22", + "sparse_infill_speed": [ + "100" + ], + "support_bottom_z_distance": "0.12", + "support_line_width": "0.22", + "support_top_z_distance": "0.12", + "top_color_penetration_layers": "7", + "top_shell_layers": "7", + "top_surface_line_width": "0.22", + "top_surface_speed": [ + "150" + ], + "travel_speed": [ + "500" + ], + "wall_loops": "4", + "compatible_printers": [ + "Qidi X-Plus 5 0.2 nozzle" + ] +} diff --git a/resources/profiles/Qidi/process/0.12mm High Quality @X-Plus 5.json b/resources/profiles/Qidi/process/0.12mm High Quality @X-Plus 5.json new file mode 100644 index 0000000000..a74aecb369 --- /dev/null +++ b/resources/profiles/Qidi/process/0.12mm High Quality @X-Plus 5.json @@ -0,0 +1,73 @@ +{ + "type": "process", + "setting_id": "xWoxLO8XiKAOEvPO", + "name": "0.12mm High Quality @X-Plus 5", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_n_common", + "bottom_color_penetration_layers": "5", + "bottom_shell_layers": "5", + "bridge_flow": "1", + "default_acceleration": [ + "4000" + ], + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "gap_infill_speed": [ + "230" + ], + "initial_layer_infill_speed": [ + "105" + ], + "initial_layer_speed": [ + "50" + ], + "inner_wall_acceleration": [ + "0" + ], + "inner_wall_speed": [ + "150" + ], + "internal_solid_infill_speed": [ + "180" + ], + "layer_height": "0.12", + "outer_wall_acceleration": [ + "2000" + ], + "outer_wall_speed": [ + "60" + ], + "overhang_1_4_speed": [ + "60" + ], + "overhang_2_4_speed": [ + "30" + ], + "overhang_3_4_speed": [ + "10" + ], + "prime_tower_width": "60", + "prime_tower_brim_width": "-1", + "prime_tower_flat_ironing": "1", + "sparse_infill_pattern": "gyroid", + "sparse_infill_speed": [ + "180" + ], + "support_bottom_z_distance": "0.12", + "support_threshold_angle": "20", + "support_top_z_distance": "0.12", + "top_color_penetration_layers": "7", + "top_shell_layers": "5", + "top_shell_thickness": "0.6", + "top_surface_speed": [ + "150" + ], + "travel_speed": [ + "350" + ], + "wall_loops": "2", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/process/0.16mm High Quality @X-Plus 5.json b/resources/profiles/Qidi/process/0.16mm High Quality @X-Plus 5.json new file mode 100644 index 0000000000..54f20f7324 --- /dev/null +++ b/resources/profiles/Qidi/process/0.16mm High Quality @X-Plus 5.json @@ -0,0 +1,65 @@ +{ + "type": "process", + "setting_id": "7hYw7osV25Xu2yiu", + "name": "0.16mm High Quality @X-Plus 5", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_n_common", + "bottom_color_penetration_layers": "4", + "bottom_shell_layers": "4", + "bridge_flow": "1", + "default_acceleration": [ + "4000" + ], + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "gap_infill_speed": [ + "250" + ], + "inner_wall_acceleration": [ + "0" + ], + "internal_solid_infill_speed": [ + "200" + ], + "ironing_flow": "25%", + "ironing_speed": "20", + "layer_height": "0.16", + "outer_wall_acceleration": [ + "2000" + ], + "outer_wall_speed": [ + "60" + ], + "overhang_1_4_speed": [ + "60" + ], + "overhang_2_4_speed": [ + "30" + ], + "overhang_3_4_speed": [ + "10" + ], + "prime_tower_width": "60", + "prime_tower_brim_width": "-1", + "prime_tower_flat_ironing": "1", + "sparse_infill_pattern": "gyroid", + "sparse_infill_speed": [ + "200" + ], + "support_bottom_z_distance": "0.16", + "support_threshold_angle": "25", + "support_top_z_distance": "0.16", + "top_color_penetration_layers": "6", + "top_shell_layers": "6", + "top_shell_thickness": "1.0", + "top_surface_speed": [ + "150" + ], + "travel_speed": [ + "350" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/process/0.16mm Standard @X-Plus 5.json b/resources/profiles/Qidi/process/0.16mm Standard @X-Plus 5.json new file mode 100644 index 0000000000..5399e693aa --- /dev/null +++ b/resources/profiles/Qidi/process/0.16mm Standard @X-Plus 5.json @@ -0,0 +1,62 @@ +{ + "type": "process", + "setting_id": "xP7mco0WGscmPNoV", + "name": "0.16mm Standard @X-Plus 5", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_n_common", + "bottom_color_penetration_layers": "4", + "bottom_shell_layers": "4", + "bridge_flow": "1", + "default_acceleration": [ + "10000" + ], + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "gap_infill_speed": [ + "250" + ], + "inner_wall_acceleration": [ + "0" + ], + "inner_wall_speed": [ + "300" + ], + "internal_solid_infill_speed": [ + "250" + ], + "layer_height": "0.16", + "outer_wall_acceleration": [ + "5000" + ], + "outer_wall_speed": [ + "200" + ], + "overhang_1_4_speed": [ + "60" + ], + "overhang_2_4_speed": [ + "30" + ], + "overhang_3_4_speed": [ + "10" + ], + "prime_tower_width": "60", + "prime_tower_brim_width": "-1", + "prime_tower_flat_ironing": "1", + "sparse_infill_speed": [ + "350" + ], + "support_bottom_z_distance": "0.16", + "support_threshold_angle": "25", + "support_top_z_distance": "0.16", + "top_color_penetration_layers": "6", + "top_shell_layers": "6", + "top_shell_thickness": "1.0", + "travel_speed": [ + "500" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/process/0.18mm Balanced Quality @X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/process/0.18mm Balanced Quality @X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..85d94d49a7 --- /dev/null +++ b/resources/profiles/Qidi/process/0.18mm Balanced Quality @X-Plus 5 0.6 nozzle.json @@ -0,0 +1,73 @@ +{ + "type": "process", + "setting_id": "kj7YrKOrYowWXXrY", + "name": "0.18mm Balanced Quality @X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_n_common", + "bridge_flow": "1", + "bridge_speed": [ + "30" + ], + "default_acceleration": [ + "10000" + ], + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "gap_infill_speed": [ + "50" + ], + "initial_layer_line_width": "0.62", + "initial_layer_print_height": "0.3", + "initial_layer_speed": [ + "50" + ], + "inner_wall_acceleration": [ + "0" + ], + "inner_wall_line_width": "0.62", + "inner_wall_speed": [ + "300" + ], + "internal_solid_infill_line_width": "0.62", + "internal_solid_infill_speed": [ + "250" + ], + "layer_height": "0.18", + "line_width": "0.62", + "outer_wall_acceleration": [ + "5000" + ], + "outer_wall_line_width": "0.62", + "outer_wall_speed": [ + "200" + ], + "overhang_1_4_speed": [ + "0" + ], + "overhang_2_4_speed": [ + "50" + ], + "prime_tower_width": "60", + "prime_tower_brim_width": "-1", + "prime_tower_flat_ironing": "1", + "skin_infill_line_width": "0.62", + "skeleton_infill_line_width": "0.62", + "sparse_infill_line_width": "0.62", + "sparse_infill_speed": [ + "350" + ], + "support_bottom_z_distance": "0.18", + "support_line_width": "0.62", + "support_top_z_distance": "0.18", + "top_surface_line_width": "0.62", + "top_surface_speed": [ + "200" + ], + "travel_speed": [ + "500" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/process/0.20mm High Quality @X-Plus 5.json b/resources/profiles/Qidi/process/0.20mm High Quality @X-Plus 5.json new file mode 100644 index 0000000000..4f8c7b4ef4 --- /dev/null +++ b/resources/profiles/Qidi/process/0.20mm High Quality @X-Plus 5.json @@ -0,0 +1,63 @@ +{ + "type": "process", + "setting_id": "azERQAEOdeNEo2z7", + "name": "0.20mm High Quality @X-Plus 5", + "from": "system", + "inherits": "fdm_process_n_common", + "instantiation": "true", + "bottom_shell_layers": "3", + "bridge_flow": "1", + "default_acceleration": [ + "4000" + ], + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "gap_infill_speed": [ + "250" + ], + "inner_wall_acceleration": [ + "0" + ], + "inner_wall_speed": [ + "150" + ], + "internal_solid_infill_speed": [ + "200" + ], + "outer_wall_acceleration": [ + "2000" + ], + "outer_wall_speed": [ + "60" + ], + "overhang_1_4_speed": [ + "60" + ], + "overhang_2_4_speed": [ + "30" + ], + "overhang_3_4_speed": [ + "10" + ], + "prime_tower_width": "60", + "prime_tower_brim_width": "-1", + "prime_tower_flat_ironing": "1", + "sparse_infill_speed": [ + "200" + ], + "sparse_infill_density": "15%", + "sparse_infill_pattern": "gyroid", + "top_color_penetration_layers": "5", + "top_shell_layers": "5", + "top_shell_thickness": "1.0", + "top_surface_speed": [ + "150" + ], + "travel_speed": [ + "350" + ], + "wall_loops": "2", + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/process/0.20mm Standard @X-Plus 5.json b/resources/profiles/Qidi/process/0.20mm Standard @X-Plus 5.json new file mode 100644 index 0000000000..decaceecae --- /dev/null +++ b/resources/profiles/Qidi/process/0.20mm Standard @X-Plus 5.json @@ -0,0 +1,47 @@ +{ + "type": "process", + "setting_id": "ug7kxxCLKKE7MoJW", + "name": "0.20mm Standard @X-Plus 5", + "from": "system", + "inherits": "fdm_process_n_common", + "instantiation": "true", + "bridge_flow": "1", + "default_acceleration": [ + "10000" + ], + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "gap_infill_speed": [ + "250" + ], + "inner_wall_speed": [ + "300" + ], + "inner_wall_acceleration": [ + "0" + ], + "internal_solid_infill_speed": [ + "250" + ], + "ironing_flow": "15%", + "outer_wall_acceleration": [ + "5000" + ], + "outer_wall_speed": [ + "200" + ], + "prime_tower_width": "60", + "prime_tower_flat_ironing": "1", + "sparse_infill_speed": [ + "350" + ], + "top_color_penetration_layers": "5", + "top_shell_layers": "5", + "top_shell_thickness": "1.0", + "travel_speed": [ + "500" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/process/0.24mm Balanced Quality @X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/process/0.24mm Balanced Quality @X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..16e25dcef3 --- /dev/null +++ b/resources/profiles/Qidi/process/0.24mm Balanced Quality @X-Plus 5 0.6 nozzle.json @@ -0,0 +1,71 @@ +{ + "type": "process", + "setting_id": "BWwslzDWus0iHZM8", + "name": "0.24mm Balanced Quality @X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_n_common", + "bridge_flow": "1", + "bridge_speed": [ + "30" + ], + "default_acceleration": [ + "10000" + ], + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "gap_infill_speed": [ + "50" + ], + "initial_layer_infill_speed": [ + "105" + ], + "initial_layer_line_width": "0.62", + "initial_layer_print_height": "0.3", + "initial_layer_speed": [ + "50" + ], + "inner_wall_acceleration": [ + "0" + ], + "inner_wall_line_width": "0.62", + "inner_wall_speed": [ + "300" + ], + "internal_solid_infill_line_width": "0.62", + "internal_solid_infill_speed": [ + "250" + ], + "layer_height": "0.24", + "line_width": "0.62", + "outer_wall_acceleration": [ + "5000" + ], + "outer_wall_line_width": "0.62", + "outer_wall_speed": [ + "200" + ], + "overhang_3_4_speed": [ + "30" + ], + "prime_tower_width": "60", + "prime_tower_brim_width": "-1", + "prime_tower_flat_ironing": "1", + "skin_infill_line_width": "0.62", + "skeleton_infill_line_width": "0.62", + "sparse_infill_line_width": "0.62", + "sparse_infill_speed": [ + "350" + ], + "support_line_width": "0.62", + "top_surface_line_width": "0.62", + "top_surface_speed": [ + "200" + ], + "travel_speed": [ + "500" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/process/0.24mm Balanced Quality @X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/process/0.24mm Balanced Quality @X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..e7d69b3f09 --- /dev/null +++ b/resources/profiles/Qidi/process/0.24mm Balanced Quality @X-Plus 5 0.8 nozzle.json @@ -0,0 +1,63 @@ +{ + "type": "process", + "setting_id": "TdXf6dJK5dAiFtIW", + "name": "0.24mm Balanced Quality @X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_n_common", + "bridge_flow": "1", + "bridge_speed": [ + "30" + ], + "default_acceleration": [ + "10000" + ], + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "gap_infill_speed": [ + "50" + ], + "initial_layer_line_width": "0.82", + "initial_layer_print_height": "0.4", + "initial_layer_speed": [ + "50" + ], + "inner_wall_acceleration": [ + "0" + ], + "inner_wall_line_width": "0.82", + "inner_wall_speed": [ + "300" + ], + "internal_solid_infill_line_width": "0.82", + "internal_solid_infill_speed": [ + "250" + ], + "layer_height": "0.24", + "line_width": "0.82", + "outer_wall_acceleration": [ + "5000" + ], + "outer_wall_line_width": "0.82", + "outer_wall_speed": [ + "200" + ], + "prime_tower_width": "60", + "prime_tower_brim_width": "-1", + "prime_tower_flat_ironing": "1", + "skin_infill_line_width": "0.82", + "skeleton_infill_line_width": "0.82", + "sparse_infill_line_width": "0.82", + "sparse_infill_speed": [ + "350" + ], + "support_line_width": "0.82", + "top_surface_line_width": "0.82", + "top_surface_pattern": "monotonic", + "travel_speed": [ + "500" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/process/0.24mm Standard @X-Plus 5.json b/resources/profiles/Qidi/process/0.24mm Standard @X-Plus 5.json new file mode 100644 index 0000000000..8a435e69e7 --- /dev/null +++ b/resources/profiles/Qidi/process/0.24mm Standard @X-Plus 5.json @@ -0,0 +1,50 @@ +{ + "type": "process", + "setting_id": "fiMTwk6ObF3WNpi5", + "name": "0.24mm Standard @X-Plus 5", + "from": "system", + "inherits": "fdm_process_n_common", + "instantiation": "true", + "bridge_flow": "1", + "default_acceleration": [ + "10000" + ], + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "gap_infill_speed": [ + "250" + ], + "inner_wall_acceleration": [ + "0" + ], + "inner_wall_speed": [ + "300" + ], + "internal_solid_infill_speed": [ + "250" + ], + "layer_height": "0.24", + "outer_wall_acceleration": [ + "5000" + ], + "outer_wall_speed": [ + "200" + ], + "prime_tower_width": "60", + "prime_tower_brim_width": "-1", + "prime_tower_flat_ironing": "1", + "sparse_infill_speed": [ + "350" + ], + "support_threshold_angle": "35", + "top_color_penetration_layers": "4", + "top_shell_layers": "4", + "top_shell_thickness": "1.0", + "top_surface_line_width": "0.45", + "travel_speed": [ + "500" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.4 nozzle" + ] +} diff --git a/resources/profiles/Qidi/process/0.30mm Standard @X-Plus 5 0.6 nozzle.json b/resources/profiles/Qidi/process/0.30mm Standard @X-Plus 5 0.6 nozzle.json new file mode 100644 index 0000000000..a297f33bac --- /dev/null +++ b/resources/profiles/Qidi/process/0.30mm Standard @X-Plus 5 0.6 nozzle.json @@ -0,0 +1,65 @@ +{ + "type": "process", + "setting_id": "ZHUAMUGv0HI3h8fQ", + "name": "0.30mm Standard @X-Plus 5 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_n_common", + "bridge_flow": "1", + "bridge_speed": [ + "30" + ], + "default_acceleration": [ + "10000" + ], + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "gap_infill_speed": [ + "50" + ], + "initial_layer_line_width": "0.62", + "initial_layer_print_height": "0.3", + "initial_layer_speed": [ + "50" + ], + "inner_wall_acceleration": [ + "0" + ], + "inner_wall_line_width": "0.62", + "inner_wall_speed": [ + "300" + ], + "internal_solid_infill_line_width": "0.62", + "internal_solid_infill_speed": [ + "250" + ], + "layer_height": "0.3", + "line_width": "0.62", + "outer_wall_acceleration": [ + "5000" + ], + "outer_wall_line_width": "0.62", + "outer_wall_speed": [ + "120" + ], + "prime_tower_width": "60", + "prime_tower_flat_ironing": "1", + "skin_infill_line_width": "0.62", + "skeleton_infill_line_width": "0.62", + "sparse_infill_line_width": "0.62", + "sparse_infill_speed": [ + "350" + ], + "support_line_width": "0.62", + "top_shell_layers": "4", + "top_surface_line_width": "0.62", + "top_surface_speed": [ + "200" + ], + "travel_speed": [ + "500" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.6 nozzle" + ] +} diff --git a/resources/profiles/Qidi/process/0.32mm Balanced Quality @X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/process/0.32mm Balanced Quality @X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..be02d140d6 --- /dev/null +++ b/resources/profiles/Qidi/process/0.32mm Balanced Quality @X-Plus 5 0.8 nozzle.json @@ -0,0 +1,72 @@ +{ + "type": "process", + "setting_id": "Vl4hMKR69J1JcquX", + "name": "0.32mm Balanced Quality @X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_n_common", + "bridge_flow": "1", + "bridge_speed": [ + "30" + ], + "default_acceleration": [ + "10000" + ], + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "gap_infill_speed": [ + "50" + ], + "initial_layer_infill_speed": [ + "105" + ], + "initial_layer_line_width": "0.82", + "initial_layer_print_height": "0.4", + "initial_layer_speed": [ + "50" + ], + "inner_wall_acceleration": [ + "0" + ], + "inner_wall_line_width": "0.82", + "inner_wall_speed": [ + "300" + ], + "internal_solid_infill_line_width": "0.82", + "internal_solid_infill_speed": [ + "250" + ], + "layer_height": "0.32", + "line_width": "0.82", + "outer_wall_acceleration": [ + "5000" + ], + "outer_wall_line_width": "0.82", + "outer_wall_speed": [ + "200" + ], + "overhang_3_4_speed": [ + "30" + ], + "prime_tower_width": "60", + "prime_tower_brim_width": "-1", + "prime_tower_flat_ironing": "1", + "skin_infill_line_width": "0.82", + "skeleton_infill_line_width": "0.82", + "sparse_infill_line_width": "0.82", + "sparse_infill_speed": [ + "350" + ], + "support_line_width": "0.82", + "top_surface_line_width": "0.82", + "top_surface_pattern": "monotonic", + "top_surface_speed": [ + "200" + ], + "travel_speed": [ + "500" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/process/0.40mm Standard @X-Plus 5 0.8 nozzle.json b/resources/profiles/Qidi/process/0.40mm Standard @X-Plus 5 0.8 nozzle.json new file mode 100644 index 0000000000..cb3f30c20e --- /dev/null +++ b/resources/profiles/Qidi/process/0.40mm Standard @X-Plus 5 0.8 nozzle.json @@ -0,0 +1,60 @@ +{ + "type": "process", + "setting_id": "6EBzl1Pg5Px36Cu6", + "name": "0.40mm Standard @X-Plus 5 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_n_common", + "bridge_flow": "1", + "bridge_speed": [ + "30" + ], + "default_acceleration": [ + "10000" + ], + "elefant_foot_compensation": "0.15", + "enable_arc_fitting": "0", + "gap_infill_speed": [ + "50" + ], + "initial_layer_line_width": "0.82", + "initial_layer_print_height": "0.4", + "inner_wall_acceleration": [ + "0" + ], + "inner_wall_line_width": "0.82", + "inner_wall_speed": [ + "300" + ], + "internal_solid_infill_line_width": "0.82", + "internal_solid_infill_speed": [ + "250" + ], + "layer_height": "0.4", + "line_width": "0.82", + "outer_wall_acceleration": [ + "5000" + ], + "outer_wall_line_width": "0.82", + "prime_tower_width": "60", + "prime_tower_flat_ironing": "1", + "skin_infill_line_width": "0.82", + "skeleton_infill_line_width": "0.82", + "sparse_infill_line_width": "0.82", + "sparse_infill_speed": [ + "350" + ], + "support_line_width": "0.82", + "top_surface_line_width": "0.82", + "top_surface_pattern": "monotonic", + "top_surface_speed": [ + "200" + ], + "top_shell_layers": "4", + "travel_speed": [ + "500" + ], + "compatible_printers": [ + "Qidi X-Plus 5 0.8 nozzle" + ] +} diff --git a/resources/profiles/Qidi/qidi_xplus5_buildplate_model.stl b/resources/profiles/Qidi/qidi_xplus5_buildplate_model.stl new file mode 100644 index 0000000000000000000000000000000000000000..5e2d7ca48585ce2287c9981b73a28977b93c779b GIT binary patch literal 28284 zcmbtbfAD8zRlb@IBPHp&5Tvlne)xXXP^>|X1iv4bPq-;f6a6%kQ9+CxEDRka#jZ$N zMos@X6X@gwVrUgzjF=|0VX)`q<4z^|#4R)UMob$fVd++@$&h#DF zJ$ui2-shb2p7-ay-z(mF*+svx_f^mT*~{K`#oiaa_M%JPu=oG<^TH=~@zXC&=ubHP znftr`jMW$JzHV*uA(8$0-FM%8M}z1R0nG^EXd)hb`IYMj-*fE_uowN_D-Qkj%b({Q z5C74{hd%YfZI|=;W&|{fNVy=E!m%G5f!GfY$j0H%5ntDtR}%y@)^0(hOvK`*3wPf2 z&8y~eRq}JzTVJsM`_DSV`MORJC0A%mtx_h(kuN`UdHhM|JBMmgMjSg2FZbX4=H~~8 zAiA_dTWXauIZl1X#mfud^bPb!ubPxKSCG3-5M5fKt<0z*3dcG)nm*Tlww4anIE-T! zp;jrA!y;ctuHcoo1x?EE$})1O_QxiKTBS@5>%oK3=g6+N1x?D}$jWD~HX+n1WpZ41 z#o>; z_A5?{x>AH{<`CpK$?EEA)>Ws7lsyg^U0tV$9Batp9HMZnlS5~Klp~HqH4ft_2y3@! z<`Cqt$k&-GMWpO;T=Tv|wLcVL`6-$?1Uak+4`!b$B4t=vZ`v#>eO?f%nM07{nFp?1 zUwh592QkjAouTXZ4ql@n!|Kwr@%+?bf-p=)s8!0W_9IVv(Hj4QLp3RTyVgGbO%6eH zX+^KZDiGvA42Xqs&}xdcZj#Z7rI5r?otyVo{ za#-Zc$Q8VDtB9i@tbOCo{@8?2tCY!MF)X9ckzH>Knv@v_p6{)FK8vsnRI8914qwm1 zigO07d_507m%A>!njq9FWpYI1SO+r>=SVB*kKovZh)mOpS*N#M^q_O3m9vKxIlLBv zV>3dmSTU6YwHq8>agi&^5yybIT!vR05MIX_ha*a^Fa|S@s$u0j!rC7YBRR}^7NJ%t zmp;c_;ytLElo^N57{P(jG>5>*!U$6YIbQ#gn=b1wom6cSA=Tj5ajs4XAc}awEG>-p@@`Wb>$;(Jq$0ID@CYg4l(8U{bN?v*7Llr zlwq~_@PWhcKks?N(GhBuGQGO>Cyrac@;>HDH7TRr&%WpU!$0`p(}QCZLakCR9LwY| z&ADg`nv^4sb88&NF^e#-idD)byF1w*s!16fmbY_}!;-66gj%IM<***Kw%E5Rqh0IG zb8B5$pBE0*%pvHNRpK&hR}m@0%Bu3*tm&>(glgsx&Pzm+6_k! zuksWRO`f(P=M6%G@HkYXi1xINnEBJ=mdkH$g2QiaARD*euoRBo5ca=&RWy0~0V{2Z zt@F>8LlKrMzh|0qXj^JE8;5(P8bxgGj}c;W57&5Qq4?}$=Ycqx#OcMY^qe4}`z&gR zIA=77QJ-53_!%R_N=_Cu^*<|OT1&ADFL4ksk8rfjlZcNkg*E;vkt;{YeukStl@_2U*uHp>VHiw7JUwq8T>=X=hPIHcAY2+w+~ z$YqbC2+c^#F+!BRh z2qIU8M0opzMpe5eMv=&+uBHfj#q+r!2JLh1`huN%XL?1e{&=icv8N7qd}rCIMi9*^ z8lfjgZA-0EE|If+8&bIrhVSNyo(G>%yo&YaE1 z#W4u4azxR?IyM~vW8YIJ0(nIBEny1ZxOY6m{$9XZQ8#{7uH)?l| zLu#}^c-Cv=);@l+O7ebJtT39jN(gX-Xkwhxt2&y)*#82DBC6GRoF}SZ=KP9wbKZrV zYhn|5k2rEQfF{={$j$5u0<*?Xzf_GPn!cfNAXKA>9JP&C&Y_6LN@fh9@a#%e(`x1I z>YOi-c6`LV;s}e+PfJs;Y}}O*)mZ6TGRNWdqX>)7&zu`M9HCY^x}2gXQNL8p2;nF1 zDTg9VE>@f8#N3~wE!*jrH?FzAo^q&05xLi%B65cu9OW%yo=Xa%M6Md+^Y`4a(w3N| z%#~^sp{s=377j(Il|A>9Oz|p+`lV_Vu{paVM0p#oIgIA%+%k81V9z}xWE=B-YdH0) zSu=E{-n@ROMiDwI!JnT0+lXoqI(Nz11w{N{42nkDoy>4OAuU3!bXLmt@pn64DZ*wV zzdM=cO50K^on4)y2LU*Ae$5>++MOUA283!9p*`!y);@kF2)}g%hk8p}{@F&Z?QX6T zZA-0mmGIVkcm&B1b+(jwH=masnc21o*9ao#U?M*9hAaF%>KAW*`})%_wUxfZyNOR6 zqP*?$1sCkG=i5W~*vAfaT_CzKLait-0&(x(KF9Z=AAI}E)~Zp&&);y0bDaJ^A2E(V zbYp~CQCecfq@jLlLT(A{GM?k6z3;9GbI$qY;qP~Lz2esmxwZO>&+i%jyuaDn+FITHp}oTk zeh2-$zqp*bk*g<*CJQwqi2U-;owvN?{rg6_Qp95Q?=Rdlobc6~B3GLb z)oN>mc=u0VwY=rL zR+rv(%5cN=Ck2Nhszwou5#otYe$nz@{hgGyrB>iRW!Uqzrv`^2szwpuQ^c3-`^1Or zJ4Nr?qERbwoNRGCB{*6{Y7_xEpO312sMWqDvdy4ne7yRiKfe8|cO2L`d@SBpt40x9 z!_&{%JAB^@2VYv^AJ3ks^FQ7@8>}_a&PUMAPcquiCe| z{D!R=jz;62M7wvMy0RD_4VBn-!{&CYpHd}7_UE>q z&-6JEp|QFu2=qnPn{)Jt1G&;&D&?ppoGdNA84l4*5mJeT18YQS%jK}L5dhB`4)+Sa z7EOcLH{5)QR3bR+$8NV3ac8xfL{0$5V9kjjK6c4z_FN+G3Gq=|5Uo|sde>Q>FM&Xn zSl@c&b*I1WJAFOLvyDG8bxf45X9l!scos1?HO#`7mi*LRig;omnZ@NLy@Cus+INN%6fN(qt#S| z^^GC?hCU)s4n;IpoL4Fbys{tjN;EBE-wOXOk-PaA0WXRb=f@U74%JK$wvR782y^F9 zgv+#g;Pp>gp|2W*b2OR>A~{e~X5OK$6hWC*PkZpm&cS+9gleXUt*B5#?7$^(7y{$N zHI!*(Xn)Q)6rq|aBI7^|_R}L*il7`;oRwyBWmQ<%r-(TYMNkea&PpwZdlmB)HO`la zeM6}j#1KDTiI@|Ku=y&j>=|aImcvl}ve5{_kcJqIj|rl+^8Ne_hxH!L0Iq2fm=k4Y zsBs8_D_L4ChB_;SxqAhUs?m10WvU(%;&iej=BBt`O8ne z_l`T3&pyd_7KunJ^k94E^jF`$dFL62pK!;sf8{M})hMFfQ*ZJr5$YA|>cz*rcDd`- zk9r(w1x?C8iu!qV77?q>Og+>_d)C2(?O?96$HiFYO#S z|F@k(H7R?$UisStIW{3M&*BWI2y#4ZBkJpZOJsrgY@oaQK*Zjc92*g86*4(ue0UtT zs?`0tAhr|66edjKm@+L%{ofJV1OAuo~r#EBGMo~G% zL$3F5@f}Ve>dj_*FRFJkBaU)gGeTHj8di~o z;7~-PVI0np&&h#2nP)qQBQ=O4WqRec5FCm?26OhALy*IB6l;jya&jM3P8K#($H{_# zTy^x!5i<4(){?Diayw`!pWl1E-_`fd#^(sum3pNbMd+LHaB9Y@#>!^zjd2u>B24z@ ze5*h5N)g4%Jan0F^##%EHxrs^y~}LlP>mw8Zzj3w6`@vo!`g75KipscLO}8}iKCAm z?6e29Z;X3|?DC5gV=0J6BmKOwN;*ZTmF3Vm_$`i|g4a0JGa~NWxMNNEo;&kw$mfb^ zHFJnqYs>FcE27F~6=&Sw;4I3SK{WFSaLk?0y{&>atH>KU8iZ~lp_8CKkpF%I07 zBtkXw2%zn!&uTY>Ra~AL><*yFe4cx12eHosL5(6PPY}kXyGc8r83(QSoNtuDAYQpu zzH6=sqWL_koqGnJ)qMBjF zLQD`=C#unJnA-87=fM^s)oweS`o&g3I7iiJyE-1nUX2kkx}1Y^$sB?jZCAf%5`^cf z-T?rS=YEqdj_-v-5aYA6wT~Zd3mkdE);E~ql_TU%zd>Nt$z2BbZ%$zx4Wd}-8_eM7 z6Cv*=EZS@r-sYPPLvU<3MBga1ZyIJ1#?!v@5Ds}aAsmj7I0i-3yamFn@zZ)$t@Kt+ zI2=*?7PE8d54j0B8lv8p=yy3|ujDJ{pI9kyKZ>qamslBcHn+R1G38tEkJl z4z_&`f7uohv5FcZpN}K2cRlTwXLXjC#8KAQ7E$kmj)tgK@Nndn*GR0dHlBSif(nnZ zt=}LBM-N0DA9bz8^ID;TFdo&k2-GpT1>qdEEh1VEx%bg=uKTEzxxcC{8OJihhF3Dy zT14X&5atnnCW!D|-)06!?*Kzcu6)!+94>RcqGi-pb34@BGg;r9P;v!K+#~bcPfdF> z<%lvTV!rDAf4NnOlQ(D1IE7F8!*D#GyC%@yZahy8YdtgE+(z(bf(YKWB}ap>oaFt* z6p(JVxs?1CG!Zi3Yi?NMEr?r)P1|| zACR|t{zwcFRig;sKiDd9WS!QPLlGDku+r}iT12az4a-AoUP zrbY0pg`*?#+XlDNnNK>z>Pj^>ui$ItijW;ZPuK|IX#J97E^^EY$nd0Hf4+f35x$Z+ znzu&tx$^Ih4v!!;8uljV;E+s2XjT zJ-eE4z$-TK;&Cij+k6*EIYG#YQWMRWZ? z+sQG9fR#NTz*jgFQ8mHg?RwsF{cwtiqiIX5ns0dtsF6E|=R^>!n20G5Ub~jBoX`E# z=qq)cEKJ_r^dNwiVU7=Kq(5w~!fG&sXf%Ro-YBP6&e0EGwgJjg@=522UcrVueP^-uYTWS!hQAA|-aS)AF znfXu)^{0G+&9=(wqkHN=^h6cJDtZm8C}pDKxpH79fmp@}i^V*%TyA={LFhWD>lL53djI0_$C7G3G>AMGl7 \ No newline at end of file diff --git a/resources/profiles/Snapmaker.json b/resources/profiles/Snapmaker.json index cdc7f0fe81..9a6fab7942 100644 --- a/resources/profiles/Snapmaker.json +++ b/resources/profiles/Snapmaker.json @@ -1,6 +1,6 @@ { "name": "Snapmaker", - "version": "02.04.00.07", + "version": "02.04.00.09", "force_update": "0", "description": "Snapmaker configurations", "machine_model_list": [ @@ -426,10 +426,6 @@ "name": "0.16 Optimal @Snapmaker U1 (0.4 nozzle)", "sub_path": "process/0.16 Optimal @Snapmaker U1 (0.4 nozzle).json" }, - { - "name": "0.20 Bambu Support W @Snapmaker U1 (0.4 nozzle)", - "sub_path": "process/0.20 Bambu Support W @Snapmaker U1 (0.4 nozzle).json" - }, { "name": "0.20 Quality @Snapmaker U1 (0.4 nozzle)", "sub_path": "process/0.20 Quality @Snapmaker U1 (0.4 nozzle).json" @@ -486,6 +482,66 @@ "name": "fdm_process_U1_0.8_common", "sub_path": "process/fdm_process_U1_0.8_common.json" }, + { + "name": "fdm_process_U1_0.06_nozzle_0.2", + "sub_path": "process/fdm_process_U1_0.06_nozzle_0.2.json" + }, + { + "name": "fdm_process_U1_0.08_nozzle_0.2", + "sub_path": "process/fdm_process_U1_0.08_nozzle_0.2.json" + }, + { + "name": "fdm_process_U1_0.10_nozzle_0.2", + "sub_path": "process/fdm_process_U1_0.10_nozzle_0.2.json" + }, + { + "name": "fdm_process_U1_0.12_nozzle_0.2", + "sub_path": "process/fdm_process_U1_0.12_nozzle_0.2.json" + }, + { + "name": "fdm_process_U1_0.14_nozzle_0.2", + "sub_path": "process/fdm_process_U1_0.14_nozzle_0.2.json" + }, + { + "name": "fdm_process_U1_0.18_nozzle_0.6", + "sub_path": "process/fdm_process_U1_0.18_nozzle_0.6.json" + }, + { + "name": "fdm_process_U1_0.24_nozzle_0.6", + "sub_path": "process/fdm_process_U1_0.24_nozzle_0.6.json" + }, + { + "name": "fdm_process_U1_0.24_nozzle_0.8", + "sub_path": "process/fdm_process_U1_0.24_nozzle_0.8.json" + }, + { + "name": "fdm_process_U1_0.30_nozzle_0.6", + "sub_path": "process/fdm_process_U1_0.30_nozzle_0.6.json" + }, + { + "name": "fdm_process_U1_0.32_nozzle_0.8", + "sub_path": "process/fdm_process_U1_0.32_nozzle_0.8.json" + }, + { + "name": "fdm_process_U1_0.36_nozzle_0.6", + "sub_path": "process/fdm_process_U1_0.36_nozzle_0.6.json" + }, + { + "name": "fdm_process_U1_0.40_nozzle_0.8", + "sub_path": "process/fdm_process_U1_0.40_nozzle_0.8.json" + }, + { + "name": "fdm_process_U1_0.42_nozzle_0.6", + "sub_path": "process/fdm_process_U1_0.42_nozzle_0.6.json" + }, + { + "name": "fdm_process_U1_0.48_nozzle_0.8", + "sub_path": "process/fdm_process_U1_0.48_nozzle_0.8.json" + }, + { + "name": "fdm_process_U1_0.56_nozzle_0.8", + "sub_path": "process/fdm_process_U1_0.56_nozzle_0.8.json" + }, { "name": "0.06 High Quality @Snapmaker U1 (0.2 nozzle)", "sub_path": "process/0.06 High Quality @Snapmaker U1 (0.2 nozzle).json" @@ -1508,10 +1564,6 @@ "name": "Snapmaker PLA Metal @U1", "sub_path": "filament/Snapmaker PLA Metal @U1.json" }, - { - "name": "Snapmaker PLA Silk @U1", - "sub_path": "filament/Snapmaker PLA Silk @U1.json" - }, { "name": "Snapmaker PLA Silk", "sub_path": "filament/Snapmaker PLA Silk.json" @@ -1671,6 +1723,214 @@ { "name": "Snapmaker PLA Matte @U1 base", "sub_path": "filament/Snapmaker PLA Matte @U1 base.json" + }, + { + "name": "Polymaker PLA @U1 base", + "sub_path": "filament/Polymaker PLA @U1 base.json" + }, + { + "name": "Polymaker Silk PLA Family @U1", + "sub_path": "filament/Polymaker Silk PLA Family @U1.json" + }, + { + "name": "Polymaker Tough PLA Family @U1", + "sub_path": "filament/Polymaker Tough PLA Family @U1.json" + }, + { + "name": "Snapmaker Breakaway Support For PLA @U1 0.2 nozzle", + "sub_path": "filament/Snapmaker Breakaway Support For PLA @U1 0.2 nozzle.json" + }, + { + "name": "Snapmaker Breakaway Support For PLA @U1 0.6 nozzle", + "sub_path": "filament/Snapmaker Breakaway Support For PLA @U1 0.6 nozzle.json" + }, + { + "name": "Snapmaker Breakaway Support For PLA @U1 0.8 nozzle", + "sub_path": "filament/Snapmaker Breakaway Support For PLA @U1 0.8 nozzle.json" + }, + { + "name": "Snapmaker PETG HF @U1 base2", + "sub_path": "filament/Snapmaker PETG HF @U1 base2.json" + }, + { + "name": "Snapmaker PETG Translucent @U1 base", + "sub_path": "filament/Snapmaker PETG Translucent @U1 base.json" + }, + { + "name": "Snapmaker PLA Basic @U1 base", + "sub_path": "filament/Snapmaker PLA Basic @U1 base.json" + }, + { + "name": "Snapmaker PLA Full Spectrum @U1 0.4 nozzle", + "sub_path": "filament/Snapmaker PLA Full Spectrum @U1 0.4 nozzle.json" + }, + { + "name": "Snapmaker PLA Glow @U1 base", + "sub_path": "filament/Snapmaker PLA Glow @U1 base.json" + }, + { + "name": "Snapmaker PLA Matte @U1 base2", + "sub_path": "filament/Snapmaker PLA Matte @U1 base2.json" + }, + { + "name": "Snapmaker PLA Silk @U1 0.2 nozzle", + "sub_path": "filament/Snapmaker PLA Silk @U1 0.2 nozzle.json" + }, + { + "name": "Snapmaker PLA Silk @U1 0.6 nozzle", + "sub_path": "filament/Snapmaker PLA Silk @U1 0.6 nozzle.json" + }, + { + "name": "Snapmaker PLA Silk @U1 0.8 nozzle", + "sub_path": "filament/Snapmaker PLA Silk @U1 0.8 nozzle.json" + }, + { + "name": "Snapmaker PLA SnapSpeed @U1 base2", + "sub_path": "filament/Snapmaker PLA SnapSpeed @U1 base2.json" + }, + { + "name": "Snapmaker PLA Translucent @U1 base", + "sub_path": "filament/Snapmaker PLA Translucent @U1 base.json" + }, + { + "name": "Snapmaker PLA Wood @U1 0.4 nozzle", + "sub_path": "filament/Snapmaker PLA Wood @U1 0.4 nozzle.json" + }, + { + "name": "Snapmaker PLA Wood @U1 0.6 nozzle", + "sub_path": "filament/Snapmaker PLA Wood @U1 0.6 nozzle.json" + }, + { + "name": "Snapmaker PLA Wood @U1 0.8 nozzle", + "sub_path": "filament/Snapmaker PLA Wood @U1 0.8 nozzle.json" + }, + { + "name": "Snapmaker PLA-CF @U1 0.4 nozzle", + "sub_path": "filament/Snapmaker PLA-CF @U1 0.4 nozzle.json" + }, + { + "name": "Snapmaker PLA-CF @U1 0.6 nozzle", + "sub_path": "filament/Snapmaker PLA-CF @U1 0.6 nozzle.json" + }, + { + "name": "Snapmaker PLA-CF @U1 0.8 nozzle", + "sub_path": "filament/Snapmaker PLA-CF @U1 0.8 nozzle.json" + }, + { + "name": "Snapmaker PVA @U1 0.6 nozzle", + "sub_path": "filament/Snapmaker PVA @U1 0.6 nozzle.json" + }, + { + "name": "Snapmaker PVA @U1 0.8 nozzle", + "sub_path": "filament/Snapmaker PVA @U1 0.8 nozzle.json" + }, + { + "name": "Snapmaker TPU 90A @U1", + "sub_path": "filament/Snapmaker TPU 90A @U1.json" + }, + { + "name": "Snapmaker TPU 90A @U1 0.6 nozzle", + "sub_path": "filament/Snapmaker TPU 90A @U1 0.6 nozzle.json" + }, + { + "name": "Snapmaker TPU 90A @U1 0.8 nozzle", + "sub_path": "filament/Snapmaker TPU 90A @U1 0.8 nozzle.json" + }, + { + "name": "Snapmaker TPU 95A HF @U1", + "sub_path": "filament/Snapmaker TPU 95A HF @U1.json" + }, + { + "name": "Snapmaker TPU 95A HF @U1 0.6 nozzle", + "sub_path": "filament/Snapmaker TPU 95A HF @U1 0.6 nozzle.json" + }, + { + "name": "Snapmaker TPU 95A HF @U1 0.8 nozzle", + "sub_path": "filament/Snapmaker TPU 95A HF @U1 0.8 nozzle.json" + }, + { + "name": "Snapmaker PLA Silk @U1", + "sub_path": "filament/Snapmaker PLA Silk @U1.json" + }, + { + "name": "Polymaker General PLA Family @U1", + "sub_path": "filament/Polymaker General PLA Family @U1.json" + }, + { + "name": "Snapmaker PETG HF @U1 0.2 nozzle", + "sub_path": "filament/Snapmaker PETG HF @U1 0.2 nozzle.json" + }, + { + "name": "Snapmaker PETG HF @U1 0.6 nozzle", + "sub_path": "filament/Snapmaker PETG HF @U1 0.6 nozzle.json" + }, + { + "name": "Snapmaker PETG HF @U1 0.8 nozzle", + "sub_path": "filament/Snapmaker PETG HF @U1 0.8 nozzle.json" + }, + { + "name": "Snapmaker PETG Translucent @U1 0.2 nozzle", + "sub_path": "filament/Snapmaker PETG Translucent @U1 0.2 nozzle.json" + }, + { + "name": "Snapmaker PETG Translucent @U1 0.4 nozzle", + "sub_path": "filament/Snapmaker PETG Translucent @U1 0.4 nozzle.json" + }, + { + "name": "Snapmaker PETG Translucent @U1 0.6 nozzle", + "sub_path": "filament/Snapmaker PETG Translucent @U1 0.6 nozzle.json" + }, + { + "name": "Snapmaker PETG Translucent @U1 0.8 nozzle", + "sub_path": "filament/Snapmaker PETG Translucent @U1 0.8 nozzle.json" + }, + { + "name": "Snapmaker PLA Basic @U1", + "sub_path": "filament/Snapmaker PLA Basic @U1.json" + }, + { + "name": "Snapmaker PLA Glow @U1 0.4 nozzle", + "sub_path": "filament/Snapmaker PLA Glow @U1 0.4 nozzle.json" + }, + { + "name": "Snapmaker PLA Matte @U1 0.2 nozzle", + "sub_path": "filament/Snapmaker PLA Matte @U1 0.2 nozzle.json" + }, + { + "name": "Snapmaker PLA Matte @U1 0.6 nozzle", + "sub_path": "filament/Snapmaker PLA Matte @U1 0.6 nozzle.json" + }, + { + "name": "Snapmaker PLA Matte @U1 0.8 nozzle", + "sub_path": "filament/Snapmaker PLA Matte @U1 0.8 nozzle.json" + }, + { + "name": "Snapmaker PLA SnapSpeed @U1 0.2 nozzle", + "sub_path": "filament/Snapmaker PLA SnapSpeed @U1 0.2 nozzle.json" + }, + { + "name": "Snapmaker PLA SnapSpeed @U1 0.6 nozzle", + "sub_path": "filament/Snapmaker PLA SnapSpeed @U1 0.6 nozzle.json" + }, + { + "name": "Snapmaker PLA SnapSpeed @U1 0.8 nozzle", + "sub_path": "filament/Snapmaker PLA SnapSpeed @U1 0.8 nozzle.json" + }, + { + "name": "Snapmaker PLA Translucent @U1 0.2 nozzle", + "sub_path": "filament/Snapmaker PLA Translucent @U1 0.2 nozzle.json" + }, + { + "name": "Snapmaker PLA Translucent @U1 0.4 nozzle", + "sub_path": "filament/Snapmaker PLA Translucent @U1 0.4 nozzle.json" + }, + { + "name": "Snapmaker PLA Translucent @U1 0.6 nozzle", + "sub_path": "filament/Snapmaker PLA Translucent @U1 0.6 nozzle.json" + }, + { + "name": "Snapmaker PLA Translucent @U1 0.8 nozzle", + "sub_path": "filament/Snapmaker PLA Translucent @U1 0.8 nozzle.json" } ], "machine_list": [ diff --git a/resources/profiles/Snapmaker/filament/Polymaker General PLA Family @U1.json b/resources/profiles/Snapmaker/filament/Polymaker General PLA Family @U1.json new file mode 100644 index 0000000000..c706ba776d --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Polymaker General PLA Family @U1.json @@ -0,0 +1,32 @@ +{ + "type": "filament", + "name": "Polymaker General PLA Family @U1", + "inherits": "Polymaker PLA @U1 base", + "from": "system", + "setting_id": "thXfSaUkOAKJ50ey", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.4 nozzle)" + ], + "enable_pressure_advance": [ + "0" + ], + "filament_max_volumetric_speed": [ + "15" + ], + "filament_vendor": [ + "Polymaker" + ], + "nozzle_temperature_range_high": [ + "230" + ], + "temperature_vitrification": [ + "62" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Polymaker PLA @U1 base.json b/resources/profiles/Snapmaker/filament/Polymaker PLA @U1 base.json new file mode 100644 index 0000000000..b27c48f720 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Polymaker PLA @U1 base.json @@ -0,0 +1,107 @@ +{ + "type": "filament", + "name": "Polymaker PLA @U1 base", + "inherits": "fdm_filament_pla", + "from": "system", + "filament_id": "OGFL99", + "instantiation": "false", + "compatible_printers": [ + "Snapmaker U1 (0.4 nozzle)" + ], + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "35" + ], + "cool_plate_temp_initial_layer": [ + "35" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "filament_cost": [ + "20" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_vendor": [ + "Generic" + ], + "filament_scarf_seam_type": [ + "none" + ], + "filament_scarf_height": [ + "10%" + ], + "filament_scarf_gap": [ + "15%" + ], + "filament_scarf_length": [ + "10" + ], + "filament_shrink": [ + "100%" + ], + "hot_plate_temp": [ + "55" + ], + "hot_plate_temp_initial_layer": [ + "55" + ], + "nozzle_temperature": [ + "220" + ], + "overhang_fan_threshold": [ + "50%" + ], + "supertack_plate_temp": [ + "45" + ], + "supertack_plate_temp_initial_layer": [ + "45" + ], + "slow_down_layer_time": [ + "4" + ], + "slow_down_min_speed": [ + "10" + ], + "temperature_vitrification": [ + "45" + ], + "textured_plate_temp": [ + "55" + ], + "textured_plate_temp_initial_layer": [ + "55" + ], + "filament_start_gcode": [ + "; Filament gcode\n" + ], + "filament_end_gcode": [ + "; filament end gcode\n" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Polymaker Silk PLA Family @U1.json b/resources/profiles/Snapmaker/filament/Polymaker Silk PLA Family @U1.json new file mode 100644 index 0000000000..b6bd119022 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Polymaker Silk PLA Family @U1.json @@ -0,0 +1,32 @@ +{ + "type": "filament", + "name": "Polymaker Silk PLA Family @U1", + "inherits": "Polymaker PLA @U1 base", + "from": "system", + "setting_id": "h8vIYpXbxFtHPV6e", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.4 nozzle)" + ], + "filament_density": [ + "1.34" + ], + "filament_vendor": [ + "Polymaker" + ], + "nozzle_temperature": [ + "230" + ], + "nozzle_temperature_initial_layer": [ + "230" + ], + "nozzle_temperature_range_high": [ + "230" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Polymaker Tough PLA Family @U1.json b/resources/profiles/Snapmaker/filament/Polymaker Tough PLA Family @U1.json new file mode 100644 index 0000000000..e5c2c7d7f6 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Polymaker Tough PLA Family @U1.json @@ -0,0 +1,32 @@ +{ + "type": "filament", + "name": "Polymaker Tough PLA Family @U1", + "inherits": "Polymaker PLA @U1 base", + "from": "system", + "setting_id": "d6CC81Es2hp46bto", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.4 nozzle)" + ], + "filament_density": [ + "1.23" + ], + "filament_flow_ratio": [ + "0.96" + ], + "filament_vendor": [ + "Polymaker" + ], + "slow_down_layer_time": [ + "6" + ], + "temperature_vitrification": [ + "55" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Polymaker/Fiberon ASA-CF08 @Snapmaker U1.json b/resources/profiles/Snapmaker/filament/Polymaker/Fiberon ASA-CF08 @Snapmaker U1.json index 31799163c6..b38925e01b 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/Fiberon ASA-CF08 @Snapmaker U1.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/Fiberon ASA-CF08 @Snapmaker U1.json @@ -11,7 +11,6 @@ "filament_minimal_purge_on_wipe_tower": [ "15" ], - "pressure_advance": [ "0.05" ] diff --git a/resources/profiles/Snapmaker/filament/Polymaker/Fiberon PA12-CF10 @Snapmaker U1.json b/resources/profiles/Snapmaker/filament/Polymaker/Fiberon PA12-CF10 @Snapmaker U1.json index fd99eee105..1bb569c291 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/Fiberon PA12-CF10 @Snapmaker U1.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/Fiberon PA12-CF10 @Snapmaker U1.json @@ -17,7 +17,6 @@ "filament_z_hop": [ "0.0" ], - "enable_pressure_advance": [ "1" ], diff --git a/resources/profiles/Snapmaker/filament/Polymaker/Fiberon PA6-CF20 @Snapmaker U1.json b/resources/profiles/Snapmaker/filament/Polymaker/Fiberon PA6-CF20 @Snapmaker U1.json index 1b227b2fd0..d6106faa50 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/Fiberon PA6-CF20 @Snapmaker U1.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/Fiberon PA6-CF20 @Snapmaker U1.json @@ -17,7 +17,6 @@ "filament_z_hop": [ "0.0" ], - "enable_pressure_advance": [ "1" ], diff --git a/resources/profiles/Snapmaker/filament/Polymaker/Fiberon PETG-ESD @Snapmaker U1.json b/resources/profiles/Snapmaker/filament/Polymaker/Fiberon PETG-ESD @Snapmaker U1.json index cfe6890a80..6e1797904c 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/Fiberon PETG-ESD @Snapmaker U1.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/Fiberon PETG-ESD @Snapmaker U1.json @@ -17,7 +17,6 @@ "supertack_plate_temp_initial_layer": [ "70" ], - "pressure_advance": [ "0.04" ] diff --git a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite Dual PLA @0.2 nozzle.json b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite Dual PLA @0.2 nozzle.json index 707d5ae54b..f4703d6c40 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite Dual PLA @0.2 nozzle.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite Dual PLA @0.2 nozzle.json @@ -1,10 +1,10 @@ { "type": "filament", - "from": "system", - "instantiation": "true", "name": "PolyLite Dual PLA @0.2 nozzle", - "setting_id": "jhmy4YHi9MuL0DWu", "inherits": "PolyLite PLA @0.2 nozzle", + "from": "system", + "setting_id": "jhmy4YHi9MuL0DWu", + "instantiation": "true", "compatible_printers": [ "Snapmaker A250 Dual (0.2 nozzle)", "Snapmaker A250 Dual BKit (0.2 nozzle)", diff --git a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite J1 PLA @0.2 nozzle.json b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite J1 PLA @0.2 nozzle.json index 1a4422472c..e1ce855c61 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite J1 PLA @0.2 nozzle.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite J1 PLA @0.2 nozzle.json @@ -1,10 +1,10 @@ { "type": "filament", - "from": "system", - "instantiation": "true", "name": "PolyLite J1 PLA @0.2 nozzle", - "setting_id": "jFlRSxx0KvN3BOUu", "inherits": "PolyLite PLA @0.2 nozzle", + "from": "system", + "setting_id": "jFlRSxx0KvN3BOUu", + "instantiation": "true", "compatible_printers": [ "Snapmaker J1 (0.2 nozzle)" ] diff --git a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite J1 PLA.json b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite J1 PLA.json index 6c5017d0a8..55d39a0832 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite J1 PLA.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite J1 PLA.json @@ -1,10 +1,10 @@ { "type": "filament", - "from": "system", - "instantiation": "true", "name": "PolyLite J1 PLA", - "setting_id": "wcpOTTMyZNPFKyXr", "inherits": "PolyLite PLA @base", + "from": "system", + "setting_id": "wcpOTTMyZNPFKyXr", + "instantiation": "true", "compatible_printers": [ "Snapmaker J1 (0.4 nozzle)", "Snapmaker J1 (0.6 nozzle)", diff --git a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PETG @Base.json b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PETG @Base.json index cd5f75a463..579940a5b2 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PETG @Base.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PETG @Base.json @@ -1,4 +1,9 @@ { + "type": "filament", + "name": "PolyLite PETG @Base", + "inherits": "fdm_filament_petg", + "from": "system", + "instantiation": "false", "filament_density": [ "1.25" ], @@ -18,11 +23,6 @@ "0" ], "description": "", - "inherits": "fdm_filament_petg", - "name": "PolyLite PETG @Base", - "type": "filament", - "instantiation": "false", - "from": "system", "filament_vendor": [ "Polymaker" ] diff --git a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PETG @Snapmaker U1.json b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PETG @Snapmaker U1.json index 47cf37385d..f51cc5eeec 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PETG @Snapmaker U1.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PETG @Snapmaker U1.json @@ -17,7 +17,6 @@ "supertack_plate_temp_initial_layer": [ "70" ], - "pressure_advance": [ "0.05" ] diff --git a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PETG Translucent @Snapmaker U1.json b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PETG Translucent @Snapmaker U1.json index 6089dd66c4..a3efeee371 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PETG Translucent @Snapmaker U1.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PETG Translucent @Snapmaker U1.json @@ -17,7 +17,6 @@ "supertack_plate_temp_initial_layer": [ "70" ], - "pressure_advance": [ "0.05" ] diff --git a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PLA @0.2 nozzle.json b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PLA @0.2 nozzle.json index c3897e63c2..fcceb14014 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PLA @0.2 nozzle.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PLA @0.2 nozzle.json @@ -1,10 +1,10 @@ { "type": "filament", - "from": "system", - "instantiation": "true", "name": "PolyLite PLA @0.2 nozzle", - "setting_id": "s9mdMaFca8SHfji9", "inherits": "PolyLite PLA @base", + "from": "system", + "setting_id": "s9mdMaFca8SHfji9", + "instantiation": "true", "compatible_printers": [ "Snapmaker A250 (0.2 nozzle)", "Snapmaker A250 BKit (0.2 nozzle)", diff --git a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PLA @base.json b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PLA @base.json index 4173572637..3a4621b838 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PLA @base.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/PolyLite PLA @base.json @@ -1,10 +1,10 @@ { "type": "filament", - "from": "system", - "instantiation": "false", "name": "PolyLite PLA @base", - "filament_id": "1393866034", "inherits": "fdm_filament_pla", + "from": "system", + "filament_id": "1393866034", + "instantiation": "false", "filament_flow_ratio": [ "0.95" ], diff --git a/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra Dual PLA @0.2 nozzle.json b/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra Dual PLA @0.2 nozzle.json index b45068dd52..3f8cbc7674 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra Dual PLA @0.2 nozzle.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra Dual PLA @0.2 nozzle.json @@ -1,10 +1,10 @@ { "type": "filament", - "from": "system", - "instantiation": "true", "name": "PolyTerra Dual PLA @0.2 nozzle", - "setting_id": "UQYgjH1uVxf3d2Nv", "inherits": "PolyTerra PLA @0.2 nozzle", + "from": "system", + "setting_id": "UQYgjH1uVxf3d2Nv", + "instantiation": "true", "compatible_printers": [ "Snapmaker A250 Dual (0.2 nozzle)", "Snapmaker A250 Dual BKit (0.2 nozzle)", diff --git a/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra J1 PLA @0.2 nozzle.json b/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra J1 PLA @0.2 nozzle.json index dd4f969f62..9cb7060139 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra J1 PLA @0.2 nozzle.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra J1 PLA @0.2 nozzle.json @@ -1,10 +1,10 @@ { "type": "filament", - "from": "system", - "instantiation": "true", "name": "PolyTerra J1 PLA @0.2 nozzle", - "setting_id": "mxKHxGmBZzPLS82O", "inherits": "PolyTerra PLA @0.2 nozzle", + "from": "system", + "setting_id": "mxKHxGmBZzPLS82O", + "instantiation": "true", "compatible_printers": [ "Snapmaker J1 (0.2 nozzle)" ] diff --git a/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra J1 PLA.json b/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra J1 PLA.json index 7b66438058..2583b2a2c3 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra J1 PLA.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra J1 PLA.json @@ -1,10 +1,10 @@ { "type": "filament", - "from": "system", - "instantiation": "true", "name": "PolyTerra J1 PLA", - "setting_id": "4MZWZX7QPBzxdEGj", "inherits": "PolyTerra PLA @base", + "from": "system", + "setting_id": "4MZWZX7QPBzxdEGj", + "instantiation": "true", "compatible_printers": [ "Snapmaker J1 (0.4 nozzle)", "Snapmaker J1 (0.6 nozzle)", diff --git a/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra PLA @0.2 nozzle.json b/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra PLA @0.2 nozzle.json index 07d45a7633..e70ee3d5a0 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra PLA @0.2 nozzle.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/PolyTerra PLA @0.2 nozzle.json @@ -1,10 +1,10 @@ { "type": "filament", - "from": "system", - "instantiation": "true", "name": "PolyTerra PLA @0.2 nozzle", - "setting_id": "6W1ygT08NordBdIW", "inherits": "PolyTerra PLA @base", + "from": "system", + "setting_id": "6W1ygT08NordBdIW", + "instantiation": "true", "compatible_printers": [ "Snapmaker A250 (0.2 nozzle)", "Snapmaker A250 BKit (0.2 nozzle)", diff --git a/resources/profiles/Snapmaker/filament/Polymaker/Polymaker HT-PLA @Base.json b/resources/profiles/Snapmaker/filament/Polymaker/Polymaker HT-PLA @Base.json index 7c05254a2e..76b1d2020c 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/Polymaker HT-PLA @Base.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/Polymaker HT-PLA @Base.json @@ -1,4 +1,9 @@ { + "type": "filament", + "name": "Polymaker HT-PLA @Base", + "inherits": "fdm_filament_pla", + "from": "system", + "instantiation": "false", "filament_density": [ "1.28" ], @@ -18,11 +23,6 @@ "0" ], "description": "", - "inherits": "fdm_filament_pla", - "name": "Polymaker HT-PLA @Base", - "type": "filament", - "instantiation": "false", - "from": "system", "filament_vendor": [ "Polymaker" ] diff --git a/resources/profiles/Snapmaker/filament/Polymaker/Polymaker HT-PLA-GF @Base.json b/resources/profiles/Snapmaker/filament/Polymaker/Polymaker HT-PLA-GF @Base.json index 3a64237122..06019b562c 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/Polymaker HT-PLA-GF @Base.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/Polymaker HT-PLA-GF @Base.json @@ -1,4 +1,9 @@ { + "type": "filament", + "name": "Polymaker HT-PLA-GF @Base", + "inherits": "fdm_filament_pla", + "from": "system", + "instantiation": "false", "filament_density": [ "1.34" ], @@ -18,11 +23,6 @@ "0" ], "description": "", - "inherits": "fdm_filament_pla", - "name": "Polymaker HT-PLA-GF @Base", - "type": "filament", - "instantiation": "false", - "from": "system", "filament_vendor": [ "Polymaker" ] diff --git a/resources/profiles/Snapmaker/filament/Polymaker/Polymaker PETG @Base.json b/resources/profiles/Snapmaker/filament/Polymaker/Polymaker PETG @Base.json index 0965bd153b..3692eac7d5 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/Polymaker PETG @Base.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/Polymaker PETG @Base.json @@ -1,4 +1,9 @@ { + "type": "filament", + "name": "Polymaker PETG @Base", + "inherits": "fdm_filament_petg", + "from": "system", + "instantiation": "false", "filament_density": [ "1.3" ], @@ -18,11 +23,6 @@ "0" ], "description": "", - "inherits": "fdm_filament_petg", - "name": "Polymaker PETG @Base", - "type": "filament", - "instantiation": "false", - "from": "system", "filament_vendor": [ "Polymaker" ] diff --git a/resources/profiles/Snapmaker/filament/Polymaker/Polymaker PLA Pro @Base.json b/resources/profiles/Snapmaker/filament/Polymaker/Polymaker PLA Pro @Base.json index 072fa53c93..d69ccc79f2 100644 --- a/resources/profiles/Snapmaker/filament/Polymaker/Polymaker PLA Pro @Base.json +++ b/resources/profiles/Snapmaker/filament/Polymaker/Polymaker PLA Pro @Base.json @@ -1,4 +1,9 @@ { + "type": "filament", + "name": "Polymaker PLA Pro @Base", + "inherits": "fdm_filament_pla", + "from": "system", + "instantiation": "false", "filament_density": [ "1.23" ], @@ -18,11 +23,6 @@ "0" ], "description": "", - "inherits": "fdm_filament_pla", - "name": "Polymaker PLA Pro @Base", - "type": "filament", - "instantiation": "false", - "from": "system", "filament_vendor": [ "Polymaker" ] diff --git a/resources/profiles/Snapmaker/filament/Snapmaker ABS @U1.json b/resources/profiles/Snapmaker/filament/Snapmaker ABS @U1.json index 083432ebd5..fe6c59ba80 100644 --- a/resources/profiles/Snapmaker/filament/Snapmaker ABS @U1.json +++ b/resources/profiles/Snapmaker/filament/Snapmaker ABS @U1.json @@ -7,5 +7,8 @@ "instantiation": "true", "compatible_printers": [ "Snapmaker U1 (0.4 nozzle)" + ], + "filament_retract_length_toolchange": [ + "5" ] } diff --git a/resources/profiles/Snapmaker/filament/Snapmaker ASA @U1.json b/resources/profiles/Snapmaker/filament/Snapmaker ASA @U1.json index 0c5d22723a..67bde29e8d 100644 --- a/resources/profiles/Snapmaker/filament/Snapmaker ASA @U1.json +++ b/resources/profiles/Snapmaker/filament/Snapmaker ASA @U1.json @@ -7,5 +7,8 @@ "instantiation": "true", "compatible_printers": [ "Snapmaker U1 (0.4 nozzle)" + ], + "filament_retract_length_toolchange": [ + "5" ] } diff --git a/resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1 0.2 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1 0.2 nozzle.json new file mode 100644 index 0000000000..db331b0daa --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1 0.2 nozzle.json @@ -0,0 +1,104 @@ +{ + "type": "filament", + "name": "Snapmaker Breakaway Support For PLA @U1 0.2 nozzle", + "inherits": "Snapmaker Breakaway Support @base", + "from": "system", + "setting_id": "mJoaud6wulT4p8SA", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.2 nozzle)" + ], + "filament_type": [ + "PLA" + ], + "enable_pressure_advance": [ + "0" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "fan_max_speed": [ + "30" + ], + "fan_min_speed": [ + "20" + ], + "filament_cost": [ + "69.98" + ], + "filament_density": [ + "1.3" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "0.5" + ], + "filament_retract_length_toolchange": [ + "10" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "nozzle_temperature": [ + "240" + ], + "nozzle_temperature_initial_layer": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "pressure_advance": [ + "0.2" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_loading_speed": [ + "28" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "5" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1 0.6 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1 0.6 nozzle.json new file mode 100644 index 0000000000..248c57f6d0 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1 0.6 nozzle.json @@ -0,0 +1,104 @@ +{ + "type": "filament", + "name": "Snapmaker Breakaway Support For PLA @U1 0.6 nozzle", + "inherits": "Snapmaker Breakaway Support @base", + "from": "system", + "setting_id": "rKUUREJNhstIU0I2", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.6 nozzle)" + ], + "filament_type": [ + "PLA" + ], + "enable_pressure_advance": [ + "0" + ], + "filament_cost": [ + "69.98" + ], + "filament_density": [ + "1.3" + ], + "filament_flow_ratio": [ + "0.95" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "nozzle_temperature": [ + "210" + ], + "nozzle_temperature_initial_layer": [ + "210" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "pressure_advance": [ + "0.02" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "fan_min_speed": [ + "100" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_retract_length_toolchange": [ + "10" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "1" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_wipe_distance": [ + "2" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_loading_speed": [ + "28" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1 0.8 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1 0.8 nozzle.json new file mode 100644 index 0000000000..47cf80d076 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1 0.8 nozzle.json @@ -0,0 +1,98 @@ +{ + "type": "filament", + "name": "Snapmaker Breakaway Support For PLA @U1 0.8 nozzle", + "inherits": "Snapmaker Breakaway Support @base", + "from": "system", + "setting_id": "hQ8jQ5GKQKGKuPew", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.8 nozzle)" + ], + "filament_type": [ + "PLA" + ], + "enable_pressure_advance": [ + "0" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "filament_cost": [ + "69.98" + ], + "filament_density": [ + "1.3" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_flow_ratio": [ + "0.93" + ], + "filament_retract_length_toolchange": [ + "10" + ], + "filament_retraction_length": [ + "3" + ], + "filament_retraction_speed": [ + "nil" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "nozzle_temperature": [ + "210" + ], + "nozzle_temperature_initial_layer": [ + "210" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "pressure_advance": [ + "0.015" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_loading_speed": [ + "28" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "textured_plate_temp": [ + "65" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1.json b/resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1.json index 97b2f8b07f..9e5d63a63c 100644 --- a/resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1.json +++ b/resources/profiles/Snapmaker/filament/Snapmaker Breakaway Support For PLA @U1.json @@ -10,5 +10,83 @@ ], "filament_type": [ "PLA" + ], + "enable_pressure_advance": [ + "1" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "fan_min_speed": [ + "100" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_loading_speed": [ + "28" + ], + "filament_minimal_purge_on_wipe_tower": [ + "20" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_retract_length_toolchange": [ + "5" + ], + "filament_retraction_length": [ + "1" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "nozzle_temperature": [ + "210" + ], + "nozzle_temperature_initial_layer": [ + "210" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "pressure_advance": [ + "0.03" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" ] } diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 0.2 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 0.2 nozzle.json new file mode 100644 index 0000000000..f1c3aa30a1 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 0.2 nozzle.json @@ -0,0 +1,108 @@ +{ + "type": "filament", + "name": "Snapmaker PETG HF @U1 0.2 nozzle", + "inherits": "Snapmaker PETG HF @U1 base2", + "from": "system", + "setting_id": "Ujul2YTBwfldFiFd", + "instantiation": "true", + "filament_max_volumetric_speed": [ + "1", + "1" + ], + "filament_ramming_travel_time": [ + "0", + "0" + ], + "long_retractions_when_ec": [ + "0", + "0" + ], + "retraction_distances_when_ec": [ + "0", + "0" + ], + "compatible_printers": [ + "Snapmaker U1 (0.2 nozzle)" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "fan_cooling_layer_time": [ + "20" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "30" + ], + "filament_end_gcode": [ + "\n\n" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "3" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_retract_length_toolchange": [ + "5" + ], + "filament_retraction_length": [ + "1.5" + ], + "filament_start_gcode": [ + "" + ], + "filament_vendor": [ + "Snapmaker" + ], + "hot_plate_temp": [ + "80" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "nozzle_temperature": [ + "245" + ], + "nozzle_temperature_initial_layer": [ + "245" + ], + "nozzle_temperature_range_low": [ + "230" + ], + "overhang_fan_speed": [ + "100" + ], + "slow_down_layer_time": [ + "10" + ], + "slow_down_min_speed": [ + "20" + ], + "supertack_plate_temp": [ + "60" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "textured_plate_temp": [ + "80" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "filament_z_hop_types": [ + "Slope Lift" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 0.6 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 0.6 nozzle.json new file mode 100644 index 0000000000..66a535b7fb --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 0.6 nozzle.json @@ -0,0 +1,113 @@ +{ + "type": "filament", + "name": "Snapmaker PETG HF @U1 0.6 nozzle", + "inherits": "Snapmaker PETG HF @U1 base2", + "from": "system", + "setting_id": "2FfQZdp5xunngnF0", + "instantiation": "true", + "filament_ramming_travel_time": [ + "0", + "0" + ], + "long_retractions_when_ec": [ + "0", + "0" + ], + "retraction_distances_when_ec": [ + "0", + "0" + ], + "compatible_printers": [ + "Snapmaker U1 (0.6 nozzle)" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "fan_cooling_layer_time": [ + "20" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "30" + ], + "filament_end_gcode": [ + "\n" + ], + "filament_max_volumetric_speed": [ + "20" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_retract_length_toolchange": [ + "5" + ], + "filament_retraction_length": [ + "2.5" + ], + "filament_start_gcode": [ + "" + ], + "filament_vendor": [ + "Snapmaker" + ], + "filament_wipe": [ + "1" + ], + "filament_wipe_distance": [ + "1" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "hot_plate_temp": [ + "80" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "nozzle_temperature": [ + "245" + ], + "nozzle_temperature_initial_layer": [ + "245" + ], + "nozzle_temperature_range_low": [ + "230" + ], + "overhang_fan_speed": [ + "100" + ], + "slow_down_layer_time": [ + "10" + ], + "slow_down_min_speed": [ + "20" + ], + "supertack_plate_temp": [ + "60" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "textured_plate_temp": [ + "80" + ], + "textured_plate_temp_initial_layer": [ + "80" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 0.8 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 0.8 nozzle.json new file mode 100644 index 0000000000..04446a623e --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 0.8 nozzle.json @@ -0,0 +1,110 @@ +{ + "type": "filament", + "name": "Snapmaker PETG HF @U1 0.8 nozzle", + "inherits": "Snapmaker PETG HF @U1 base2", + "from": "system", + "setting_id": "ebANa67V4B2nwUaX", + "instantiation": "true", + "filament_ramming_travel_time": [ + "0", + "0" + ], + "long_retractions_when_ec": [ + "0", + "0" + ], + "retraction_distances_when_ec": [ + "0", + "0" + ], + "compatible_printers": [ + "Snapmaker U1 (0.8 nozzle)" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "fan_cooling_layer_time": [ + "20" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "30" + ], + "filament_max_volumetric_speed": [ + "20" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_retract_length_toolchange": [ + "5" + ], + "filament_retraction_length": [ + "1" + ], + "filament_start_gcode": [ + "" + ], + "filament_vendor": [ + "Snapmaker" + ], + "filament_wipe": [ + "1" + ], + "filament_wipe_distance": [ + "2" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "hot_plate_temp": [ + "80" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "nozzle_temperature": [ + "245" + ], + "nozzle_temperature_initial_layer": [ + "245" + ], + "nozzle_temperature_range_low": [ + "230" + ], + "overhang_fan_speed": [ + "100" + ], + "slow_down_layer_time": [ + "10" + ], + "slow_down_min_speed": [ + "20" + ], + "supertack_plate_temp": [ + "60" + ], + "supertack_plate_temp_initial_layer": [ + "60" + ], + "textured_plate_temp": [ + "80" + ], + "textured_plate_temp_initial_layer": [ + "80" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 base2.json b/resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 base2.json new file mode 100644 index 0000000000..0ad75759a1 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PETG HF @U1 base2.json @@ -0,0 +1,279 @@ +{ + "type": "filament", + "name": "Snapmaker PETG HF @U1 base2", + "inherits": "fdm_filament_petg", + "from": "system", + "filament_id": "GFG96", + "instantiation": "false", + "cool_plate_temp": [ + "0" + ], + "cool_plate_temp_initial_layer": [ + "0" + ], + "eng_plate_temp": [ + "70" + ], + "eng_plate_temp_initial_layer": [ + "70" + ], + "filament_type": [ + "PETG" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "40" + ], + "filament_cost": [ + "24.99" + ], + "filament_density": [ + "1.28" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "16" + ], + "hot_plate_temp": [ + "70" + ], + "hot_plate_temp_initial_layer": [ + "70" + ], + "nozzle_temperature_range_high": [ + "270" + ], + "nozzle_temperature": [ + "220" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "overhang_fan_speed": [ + "90" + ], + "overhang_fan_threshold": [ + "10%" + ], + "slow_down_layer_time": [ + "25" + ], + "textured_plate_temp": [ + "70" + ], + "textured_plate_temp_initial_layer": [ + "70" + ], + "filament_start_gcode": [ + "; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}" + ], + "activate_air_filtration": [ + "0" + ], + "additional_cooling_fan_speed": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "counter_coef_1": [ + "0" + ], + "counter_coef_2": [ + "0.008" + ], + "counter_coef_3": [ + "-0.041" + ], + "counter_limit_min": [ + "-0.035" + ], + "counter_limit_max": [ + "0.033" + ], + "circle_compensation_speed": [ + "200" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "diameter_limit": [ + "50" + ], + "fan_min_speed": [ + "20" + ], + "filament_cooling_before_tower": [ + "0" + ], + "filament_dev_ams_drying_ams_limitations": [ + "0" + ], + "filament_dev_ams_drying_temperature": [ + "40.0" + ], + "filament_dev_ams_drying_time": [ + "8.0" + ], + "filament_dev_drying_softening_temperature": [ + "40.0" + ], + "filament_dev_ams_drying_heat_distortion_temperature": [ + "45.0" + ], + "filament_dev_drying_cooling_temperature": [ + "35.0" + ], + "filament_dev_chamber_drying_bed_temperature": [ + "90.0" + ], + "filament_dev_chamber_drying_time": [ + "12.0" + ], + "filament_flush_temp": [ + "0" + ], + "filament_flush_volumetric_speed": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_long_retractions_when_ec": [ + "nil" + ], + "filament_ramming_volumetric_speed": [ + "-1" + ], + "filament_ramming_volumetric_speed_nc": [ + "-1" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_printable": [ + "3" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_distances_when_ec": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_vendor": [ + "Generic" + ], + "filament_prime_volume": [ + "45" + ], + "filament_prime_volume_nc": [ + "60" + ], + "filament_extruder_variant": [ + "Direct Drive Standard" + ], + "filament_scarf_seam_type": [ + "none" + ], + "filament_scarf_height": [ + "10%" + ], + "filament_scarf_gap": [ + "0%" + ], + "filament_scarf_length": [ + "10" + ], + "filament_shrink": [ + "100%" + ], + "filament_pre_cooling_temperature": [ + "0" + ], + "filament_pre_cooling_temperature_nc": [ + "0" + ], + "filament_ramming_travel_time": [ + "0" + ], + "filament_ramming_travel_time_nc": [ + "0" + ], + "filament_retract_length_nc": [ + "14" + ], + "hole_coef_1": [ + "0" + ], + "hole_coef_2": [ + "-0.008" + ], + "hole_coef_3": [ + "0.23415" + ], + "hole_limit_min": [ + "0.088" + ], + "hole_limit_max": [ + "0.22" + ], + "impact_strength_z": [ + "10" + ], + "long_retractions_when_ec": [ + "0" + ], + "retraction_distances_when_ec": [ + "0" + ], + "supertack_plate_temp": [ + "70" + ], + "supertack_plate_temp_initial_layer": [ + "70" + ], + "no_slow_down_for_cooling_on_outwalls": [ + "0" + ], + "slow_down_min_speed": [ + "10" + ], + "temperature_vitrification": [ + "70" + ], + "filament_change_length": [ + "10" + ], + "filament_velocity_adaptation_factor": [ + "1" + ], + "compatible_printers": [], + "filament_end_gcode": [ + "; filament end gcode \n\n" + ], + "filament_adaptive_volumetric_speed": [ + "0" + ], + "volumetric_speed_coefficients": [ + "0 0 0 0 0 0" + ], + "filament_adhesiveness_category": [ + "300" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.2 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.2 nozzle.json new file mode 100644 index 0000000000..ee6234f406 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.2 nozzle.json @@ -0,0 +1,110 @@ +{ + "type": "filament", + "name": "Snapmaker PETG Translucent @U1 0.2 nozzle", + "inherits": "Snapmaker PETG Translucent @U1 base", + "from": "system", + "setting_id": "UTpedqYJysaoe3OI", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.2 nozzle)" + ], + "additional_cooling_fan_speed": [ + "20" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "fan_max_speed": [ + "40" + ], + "fan_min_speed": [ + "20" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_cost": [ + "25" + ], + "filament_density": [ + "1.25" + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_loading_speed": [ + "28" + ], + "filament_max_volumetric_speed": [ + "1" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "5" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_retract_length_toolchange": [ + "10" + ], + "filament_retraction_length": [ + "1" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "50" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "hot_plate_temp": [ + "80" + ], + "nozzle_temperature": [ + "245" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_low": [ + "230" + ], + "overhang_fan_threshold": [ + "10%" + ], + "pressure_advance": [ + "0.23" + ], + "slow_down_min_speed": [ + "10" + ], + "textured_plate_temp": [ + "80" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "enable_pressure_advance": [ + "0" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.4 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.4 nozzle.json new file mode 100644 index 0000000000..e0e60a0e14 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.4 nozzle.json @@ -0,0 +1,98 @@ +{ + "type": "filament", + "name": "Snapmaker PETG Translucent @U1 0.4 nozzle", + "inherits": "Snapmaker PETG Translucent @U1 base", + "from": "system", + "setting_id": "k6UQJJASzFSfePqN", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.4 nozzle)" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "fan_max_speed": [ + "30" + ], + "fan_min_speed": [ + "10" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_cost": [ + "24.99" + ], + "filament_flow_ratio": [ + "0.97" + ], + "filament_loading_speed": [ + "28" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_retract_length_toolchange": [ + "5" + ], + "filament_retraction_length": [ + "1" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "hot_plate_temp": [ + "80" + ], + "nozzle_temperature": [ + "250" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_low": [ + "230" + ], + "overhang_fan_threshold": [ + "10%" + ], + "pressure_advance": [ + "0.04" + ], + "slow_down_min_speed": [ + "10" + ], + "textured_plate_temp": [ + "80" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "filament_density": [ + "1.25" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.6 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.6 nozzle.json new file mode 100644 index 0000000000..14f59104f8 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.6 nozzle.json @@ -0,0 +1,107 @@ +{ + "type": "filament", + "name": "Snapmaker PETG Translucent @U1 0.6 nozzle", + "inherits": "Snapmaker PETG Translucent @U1 base", + "from": "system", + "setting_id": "FlcbnP3kWiJLMDMl", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.6 nozzle)" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "20" + ], + "filament_cost": [ + "25" + ], + "filament_density": [ + "1.25" + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_max_volumetric_speed": [ + "16" + ], + "hot_plate_temp": [ + "80" + ], + "nozzle_temperature": [ + "245" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_low": [ + "230" + ], + "overhang_fan_threshold": [ + "10%" + ], + "pressure_advance": [ + "0.02" + ], + "slow_down_min_speed": [ + "10" + ], + "textured_plate_temp": [ + "80" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_loading_speed": [ + "28" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_retract_length_toolchange": [ + "10" + ], + "filament_retraction_length": [ + "1.2" + ], + "filament_retraction_minimum_travel": [ + "1" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_wipe_distance": [ + "2" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "enable_pressure_advance": [ + "0" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.8 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.8 nozzle.json new file mode 100644 index 0000000000..e746141f06 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 0.8 nozzle.json @@ -0,0 +1,104 @@ +{ + "type": "filament", + "name": "Snapmaker PETG Translucent @U1 0.8 nozzle", + "inherits": "Snapmaker PETG Translucent @U1 base", + "from": "system", + "setting_id": "aJk3TnFTU3uQGjd3", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.8 nozzle)" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "20" + ], + "filament_cost": [ + "25" + ], + "filament_density": [ + "1.25" + ], + "filament_flow_ratio": [ + "0.97" + ], + "filament_max_volumetric_speed": [ + "16" + ], + "hot_plate_temp": [ + "80" + ], + "nozzle_temperature": [ + "245" + ], + "nozzle_temperature_initial_layer": [ + "250" + ], + "nozzle_temperature_range_low": [ + "230" + ], + "overhang_fan_threshold": [ + "10%" + ], + "pressure_advance": [ + "0.02" + ], + "slow_down_min_speed": [ + "10" + ], + "textured_plate_temp": [ + "80" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_loading_speed": [ + "28" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "30" + ], + "filament_multitool_ramming_volume": [ + "10" + ], + "filament_retract_length_toolchange": [ + "10" + ], + "filament_retraction_length": [ + "1" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "enable_pressure_advance": [ + "0" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 base.json b/resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 base.json new file mode 100644 index 0000000000..eb18fb4838 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PETG Translucent @U1 base.json @@ -0,0 +1,8 @@ +{ + "type": "filament", + "name": "Snapmaker PETG Translucent @U1 base", + "inherits": "fdm_filament_petg", + "from": "system", + "filament_id": "PETG_TRANSLUCENT_001", + "instantiation": "false" +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Basic @U1 base.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Basic @U1 base.json new file mode 100644 index 0000000000..adf7624e1f --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Basic @U1 base.json @@ -0,0 +1,127 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Basic @U1 base", + "from": "system", + "filament_id": "1417031127011", + "instantiation": "false", + "filament_end_gcode": [ + "" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_loading_speed_start": [ + "35" + ], + "filament_loading_speed": [ + "35" + ], + "filament_unloading_speed_start": [ + "35" + ], + "filament_unloading_speed": [ + "35" + ], + "filament_load_time": [ + "2" + ], + "filament_unload_time": [ + "2" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_cooling_initial_speed": [ + "35" + ], + "filament_cooling_final_speed": [ + "60" + ], + "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" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Basic @U1.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Basic @U1.json new file mode 100644 index 0000000000..4b68672fa5 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Basic @U1.json @@ -0,0 +1,284 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Basic @U1", + "inherits": "Snapmaker PLA Basic @U1 base", + "from": "system", + "setting_id": "ZtUJN4JpkR0MLpiY", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (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" + ], + "compatible_printers_condition": "", + "compatible_prints": [], + "compatible_prints_condition": "", + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "0" + ], + "eng_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "60" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cooling_final_speed": [ + "3.5" + ], + "filament_cooling_initial_speed": [ + "10" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_cost": [ + "25.4" + ], + "filament_density": [ + "1.32" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_is_support": [ + "0" + ], + "filament_loading_speed": [ + "10" + ], + "filament_loading_speed_start": [ + "50" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "15" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "25" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_notes": [ + "" + ], + "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_length_toolchange": [ + "10" + ], + "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": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_start_gcode": [ + "" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_unloading_speed": [ + "100" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_vendor": [ + "Snapmaker" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "idle_temperature": [ + "0" + ], + "nozzle_temperature": [ + "220" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "pressure_advance": [ + "0.02" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "0" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "4" + ], + "slow_down_min_speed": [ + "20" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Full Spectrum @U1 0.4 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Full Spectrum @U1 0.4 nozzle.json new file mode 100644 index 0000000000..990e67a79e --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Full Spectrum @U1 0.4 nozzle.json @@ -0,0 +1,284 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Full Spectrum @U1 0.4 nozzle", + "inherits": "Snapmaker PLA Basic @U1 base", + "from": "system", + "setting_id": "iybaFWrXKOsmXgMJ", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (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" + ], + "compatible_printers_condition": "", + "compatible_prints": [], + "compatible_prints_condition": "", + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "0" + ], + "eng_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "60" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cooling_final_speed": [ + "3.5" + ], + "filament_cooling_initial_speed": [ + "10" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_cost": [ + "25.4" + ], + "filament_density": [ + "1.32" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_is_support": [ + "0" + ], + "filament_loading_speed": [ + "10" + ], + "filament_loading_speed_start": [ + "50" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "15" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "25" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_notes": [ + "" + ], + "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_length_toolchange": [ + "10" + ], + "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": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_start_gcode": [ + "" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_unloading_speed": [ + "100" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_vendor": [ + "Snapmaker" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "idle_temperature": [ + "0" + ], + "nozzle_temperature": [ + "220" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "pressure_advance": [ + "0.02" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "0" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "4" + ], + "slow_down_min_speed": [ + "20" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Glow @U1 0.4 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Glow @U1 0.4 nozzle.json new file mode 100644 index 0000000000..907781cd2c --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Glow @U1 0.4 nozzle.json @@ -0,0 +1,95 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Glow @U1 0.4 nozzle", + "inherits": "Snapmaker PLA Glow @U1 base", + "from": "system", + "setting_id": "ee1YNNr8CwKetuvY", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.4 nozzle)" + ], + "additional_cooling_fan_speed": [ + "80" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "filament_cooling_final_speed": [ + "3.4" + ], + "filament_cooling_initial_speed": [ + "2.2" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_cost": [ + "20" + ], + "filament_flow_ratio": [ + "0.97" + ], + "filament_loading_speed": [ + "28" + ], + "filament_loading_speed_start": [ + "3" + ], + "filament_max_volumetric_speed": [ + "16" + ], + "filament_minimal_purge_on_wipe_tower": [ + "30" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_multitool_ramming_volume": [ + "10" + ], + "filament_retract_length_toolchange": [ + "5" + ], + "filament_retraction_length": [ + "0.4" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_z_hop": [ + "0.2" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "overhang_fan_threshold": [ + "50%" + ], + "slow_down_layer_time": [ + "4" + ], + "slow_down_min_speed": [ + "20" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Glow @U1 base.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Glow @U1 base.json new file mode 100644 index 0000000000..ad3c1f4bbb --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Glow @U1 base.json @@ -0,0 +1,44 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Glow @U1 base", + "inherits": "fdm_filament_pla", + "from": "system", + "filament_id": "SPGLOW001", + "instantiation": "false", + "filament_end_gcode": [ + "" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_loading_speed_start": [ + "35" + ], + "filament_loading_speed": [ + "35" + ], + "filament_unloading_speed_start": [ + "35" + ], + "filament_unloading_speed": [ + "35" + ], + "filament_load_time": [ + "2" + ], + "filament_unload_time": [ + "2" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_cooling_initial_speed": [ + "35" + ], + "filament_cooling_final_speed": [ + "60" + ], + "nozzle_temperature": [ + "220" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 0.2 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 0.2 nozzle.json new file mode 100644 index 0000000000..2a8c1e40c3 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 0.2 nozzle.json @@ -0,0 +1,287 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Matte @U1 0.2 nozzle", + "inherits": "Snapmaker PLA Matte @U1 base2", + "from": "system", + "setting_id": "d3c48DeNk7VDeeHf", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.2 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" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "compatible_printers_condition": "", + "compatible_prints": [], + "compatible_prints_condition": "", + "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": [ + "0" + ], + "eng_plate_temp": [ + "45" + ], + "eng_plate_temp_initial_layer": [ + "45" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cost": [ + "24.99" + ], + "filament_density": [ + "1.26" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + " " + ], + "filament_is_support": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_notes": [ + "" + ], + "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_length_toolchange": [ + "2" + ], + "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_shrink": [ + "100%" + ], + "filament_shrinkage_compensation_z": [ + "100%" + ], + "filament_soluble": [ + "0" + ], + "filament_start_gcode": [ + " " + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_vendor": [ + "Snapmaker" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "idle_temperature": [ + "0" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "0" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "4" + ], + "slow_down_min_speed": [ + "20" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "filament_max_volumetric_speed": [ + "2" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "additional_cooling_fan_speed": [ + "80" + ], + "filament_cooling_final_speed": [ + "3.5" + ], + "filament_cooling_initial_speed": [ + "10" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_flow_ratio": [ + "1.05" + ], + "filament_loading_speed": [ + "10" + ], + "filament_loading_speed_start": [ + "50" + ], + "filament_minimal_purge_on_wipe_tower": [ + "5" + ], + "filament_multitool_ramming_flow": [ + "4" + ], + "filament_multitool_ramming_volume": [ + "4" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_unloading_speed": [ + "100" + ], + "filament_z_hop_types": [ + "nil" + ], + "nozzle_temperature": [ + "215" + ], + "nozzle_temperature_initial_layer": [ + "215" + ], + "pressure_advance": [ + "0.025" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 0.6 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 0.6 nozzle.json new file mode 100644 index 0000000000..9de7615ae5 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 0.6 nozzle.json @@ -0,0 +1,287 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Matte @U1 0.6 nozzle", + "inherits": "Snapmaker PLA Matte @U1 base2", + "from": "system", + "setting_id": "l3E1WaljDn2uoTqW", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.6 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" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "compatible_printers_condition": "", + "compatible_prints": [], + "compatible_prints_condition": "", + "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": [ + "0" + ], + "eng_plate_temp": [ + "45" + ], + "eng_plate_temp_initial_layer": [ + "45" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cost": [ + "24.99" + ], + "filament_density": [ + "1.26" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + " " + ], + "filament_is_support": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "20" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_notes": [ + "" + ], + "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_length_toolchange": [ + "10" + ], + "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_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_shrink": [ + "100%" + ], + "filament_shrinkage_compensation_z": [ + "100%" + ], + "filament_soluble": [ + "0" + ], + "filament_start_gcode": [ + " " + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_vendor": [ + "Snapmaker" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "idle_temperature": [ + "0" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "0" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "4" + ], + "slow_down_min_speed": [ + "20" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "45" + ], + "textured_plate_temp_initial_layer": [ + "45" + ], + "additional_cooling_fan_speed": [ + "80" + ], + "filament_cooling_final_speed": [ + "3.5" + ], + "filament_cooling_initial_speed": [ + "10" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_flow_ratio": [ + "0.99" + ], + "filament_loading_speed": [ + "10" + ], + "filament_loading_speed_start": [ + "50" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_multitool_ramming_volume": [ + "10" + ], + "filament_retraction_length": [ + "0.6" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_unloading_speed": [ + "100" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "nozzle_temperature": [ + "215" + ], + "nozzle_temperature_initial_layer": [ + "215" + ], + "pressure_advance": [ + "0.015" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 0.8 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 0.8 nozzle.json new file mode 100644 index 0000000000..251b2a47b6 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 0.8 nozzle.json @@ -0,0 +1,287 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Matte @U1 0.8 nozzle", + "inherits": "Snapmaker PLA Matte @U1 base2", + "from": "system", + "setting_id": "NLPd4AA0seW3NXdy", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.8 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" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "compatible_printers_condition": "", + "compatible_prints": [], + "compatible_prints_condition": "", + "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": [ + "0" + ], + "eng_plate_temp": [ + "45" + ], + "eng_plate_temp_initial_layer": [ + "45" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cost": [ + "24.99" + ], + "filament_density": [ + "1.26" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + " " + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_is_support": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "20" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_notes": [ + "" + ], + "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_length_toolchange": [ + "10" + ], + "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_minimum_travel": [ + "nil" + ], + "filament_shrink": [ + "100%" + ], + "filament_shrinkage_compensation_z": [ + "100%" + ], + "filament_soluble": [ + "0" + ], + "filament_start_gcode": [ + " " + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_vendor": [ + "Snapmaker" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "idle_temperature": [ + "0" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "0" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "4" + ], + "slow_down_min_speed": [ + "20" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "nozzle_temperature": [ + "215" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "additional_cooling_fan_speed": [ + "80" + ], + "filament_cooling_final_speed": [ + "3.5" + ], + "filament_cooling_initial_speed": [ + "10" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_loading_speed": [ + "10" + ], + "filament_loading_speed_start": [ + "50" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_multitool_ramming_volume": [ + "10" + ], + "filament_retraction_length": [ + "0.6" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_unloading_speed": [ + "100" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "nozzle_temperature_initial_layer": [ + "215" + ], + "pressure_advance": [ + "0.015" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 base2.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 base2.json new file mode 100644 index 0000000000..6c0dcf26fd --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1 base2.json @@ -0,0 +1,127 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Matte @U1 base2", + "from": "system", + "filament_id": "141703112701", + "instantiation": "false", + "filament_end_gcode": [ + "" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_loading_speed_start": [ + "35" + ], + "filament_loading_speed": [ + "35" + ], + "filament_unloading_speed_start": [ + "35" + ], + "filament_unloading_speed": [ + "35" + ], + "filament_load_time": [ + "2" + ], + "filament_unload_time": [ + "2" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_cooling_initial_speed": [ + "35" + ], + "filament_cooling_final_speed": [ + "60" + ], + "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" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1.json index fcb1d74c92..a71c43f9b0 100644 --- a/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1.json +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Matte @U1.json @@ -27,7 +27,7 @@ "0" ], "additional_cooling_fan_speed": [ - "70" + "80" ], "chamber_temperature": [ "0" @@ -47,9 +47,6 @@ "cool_plate_temp_initial_layer": [ "60" ], - "default_filament_colour": [ - "" - ], "dont_slow_down_outer_wall": [ "0" ], @@ -60,7 +57,7 @@ "1" ], "enable_pressure_advance": [ - "1" + "0" ], "eng_plate_temp": [ "60" @@ -102,7 +99,7 @@ "; filament end gcode \n" ], "filament_flow_ratio": [ - "1.01" + "1" ], "filament_is_support": [ "0" @@ -117,7 +114,7 @@ "nil" ], "filament_max_volumetric_speed": [ - "20" + "22" ], "filament_minimal_purge_on_wipe_tower": [ "15" @@ -140,6 +137,9 @@ "filament_retract_before_wipe": [ "nil" ], + "filament_retract_length_toolchange": [ + "5" + ], "filament_retract_lift_above": [ "nil" ], @@ -216,19 +216,19 @@ "0" ], "hot_plate_temp": [ - "55" + "65" ], "hot_plate_temp_initial_layer": [ - "55" + "65" ], "idle_temperature": [ "0" ], "nozzle_temperature": [ - "220" + "215" ], "nozzle_temperature_initial_layer": [ - "220" + "215" ], "nozzle_temperature_range_high": [ "240" @@ -276,9 +276,9 @@ "40" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ] } diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Metal @U1 base.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Metal @U1 base.json index a530b9208e..9fba864f40 100644 --- a/resources/profiles/Snapmaker/filament/Snapmaker PLA Metal @U1 base.json +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Metal @U1 base.json @@ -46,8 +46,5 @@ ], "nozzle_temperature": [ "220" - ], - "default_filament_colour": [ - "" ] } diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 0.2 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 0.2 nozzle.json new file mode 100644 index 0000000000..5eb860506c --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 0.2 nozzle.json @@ -0,0 +1,285 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Silk @U1 0.2 nozzle", + "inherits": "Snapmaker PLA Basic @U1 base", + "from": "system", + "setting_id": "Q5xH6oGGlbXr14Pa", + "filament_id": "11813638720", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.2 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": [ + "100" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "compatible_printers_condition": "", + "compatible_prints": [], + "compatible_prints_condition": "", + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "0" + ], + "eng_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "60" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cost": [ + "25.4" + ], + "filament_density": [ + "1.32" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_flow_ratio": [ + "1.02" + ], + "filament_is_support": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "3" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_notes": [ + "" + ], + "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_length_toolchange": [ + "5" + ], + "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_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_shrink": [ + "100%" + ], + "filament_shrinkage_compensation_z": [ + "100%" + ], + "filament_soluble": [ + "0" + ], + "filament_start_gcode": [ + "" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_vendor": [ + "Snapmaker" + ], + "filament_wipe": [ + "1" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "full_fan_speed_layer": [ + "0" + ], + "idle_temperature": [ + "0" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "0" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "18" + ], + "slow_down_min_speed": [ + "20" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "dont_slow_down_outer_wall": [ + "1" + ], + "filament_cooling_final_speed": [ + "3.4" + ], + "filament_cooling_initial_speed": [ + "2.2" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_loading_speed": [ + "28" + ], + "filament_loading_speed_start": [ + "3" + ], + "filament_max_volumetric_speed": [ + "2" + ], + "filament_retraction_length": [ + "0.4" + ], + "filament_stamping_distance": [ + "0" + ], + "filament_stamping_loading_speed": [ + "0" + ], + "filament_unloading_speed": [ + "90" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "nozzle_temperature": [ + "230" + ], + "nozzle_temperature_initial_layer": [ + "230" + ], + "pressure_advance": [ + "0.015" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 0.6 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 0.6 nozzle.json new file mode 100644 index 0000000000..5df6ff5a3a --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 0.6 nozzle.json @@ -0,0 +1,285 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Silk @U1 0.6 nozzle", + "inherits": "Snapmaker PLA Basic @U1 base", + "from": "system", + "setting_id": "2pieDQoz9PiDCnU1", + "filament_id": "11813638720", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.6 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": [ + "100" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "compatible_printers_condition": "", + "compatible_prints": [], + "compatible_prints_condition": "", + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "0" + ], + "eng_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "60" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cost": [ + "25.4" + ], + "filament_density": [ + "1.32" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_flow_ratio": [ + "0.97" + ], + "filament_is_support": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_multitool_ramming_volume": [ + "10" + ], + "filament_notes": [ + "" + ], + "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_length_toolchange": [ + "10" + ], + "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_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_shrink": [ + "100%" + ], + "filament_shrinkage_compensation_z": [ + "100%" + ], + "filament_soluble": [ + "0" + ], + "filament_start_gcode": [ + "" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_vendor": [ + "Snapmaker" + ], + "filament_wipe": [ + "1" + ], + "filament_wipe_distance": [ + "1" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "full_fan_speed_layer": [ + "0" + ], + "idle_temperature": [ + "0" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "0" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "15" + ], + "slow_down_min_speed": [ + "20" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "filament_cooling_final_speed": [ + "3.4" + ], + "filament_cooling_initial_speed": [ + "2.2" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_loading_speed": [ + "28" + ], + "filament_loading_speed_start": [ + "3" + ], + "filament_max_volumetric_speed": [ + "10" + ], + "filament_retraction_length": [ + "0.4" + ], + "filament_stamping_distance": [ + "0" + ], + "filament_stamping_loading_speed": [ + "0" + ], + "filament_unloading_speed": [ + "90" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "nozzle_temperature": [ + "230" + ], + "nozzle_temperature_initial_layer": [ + "230" + ], + "pressure_advance": [ + "0.015" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 0.8 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 0.8 nozzle.json new file mode 100644 index 0000000000..0758372ea0 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 0.8 nozzle.json @@ -0,0 +1,285 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Silk @U1 0.8 nozzle", + "inherits": "Snapmaker PLA Basic @U1 base", + "from": "system", + "setting_id": "f3H0JFUnds0mkKCN", + "filament_id": "11813638720", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.8 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": [ + "100" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "compatible_printers_condition": "", + "compatible_prints": [], + "compatible_prints_condition": "", + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "0" + ], + "eng_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "60" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cost": [ + "25.4" + ], + "filament_density": [ + "1.32" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_flow_ratio": [ + "0.97" + ], + "filament_is_support": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_multitool_ramming_volume": [ + "10" + ], + "filament_notes": [ + "" + ], + "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_length_toolchange": [ + "10" + ], + "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_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_shrink": [ + "100%" + ], + "filament_shrinkage_compensation_z": [ + "100%" + ], + "filament_soluble": [ + "0" + ], + "filament_start_gcode": [ + "" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_vendor": [ + "Snapmaker" + ], + "filament_wipe": [ + "1" + ], + "filament_wipe_distance": [ + "1" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "full_fan_speed_layer": [ + "0" + ], + "idle_temperature": [ + "0" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "0" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "15" + ], + "slow_down_min_speed": [ + "20" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "filament_cooling_final_speed": [ + "3.4" + ], + "filament_cooling_initial_speed": [ + "2.2" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_loading_speed": [ + "28" + ], + "filament_loading_speed_start": [ + "3" + ], + "filament_max_volumetric_speed": [ + "10" + ], + "filament_retraction_length": [ + "0.4" + ], + "filament_stamping_distance": [ + "0" + ], + "filament_stamping_loading_speed": [ + "0" + ], + "filament_unloading_speed": [ + "90" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "nozzle_temperature": [ + "230" + ], + "nozzle_temperature_initial_layer": [ + "230" + ], + "pressure_advance": [ + "0.015" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 base.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 base.json index 12d65834ea..227fa034dc 100644 --- a/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 base.json +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1 base.json @@ -55,8 +55,5 @@ ], "nozzle_temperature": [ "230" - ], - "default_filament_colour": [ - "" ] } diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1.json index 7fdf44e792..c68904ffd9 100644 --- a/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1.json +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Silk @U1.json @@ -1,11 +1,285 @@ { "type": "filament", "name": "Snapmaker PLA Silk @U1", - "inherits": "Snapmaker PLA Silk @U1 base", + "inherits": "Snapmaker PLA Basic @U1 base", "from": "system", "setting_id": "9PkHSwtXFM0zPWth", + "filament_id": "11813638720", "instantiation": "true", "compatible_printers": [ "Snapmaker U1 (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" + ], + "compatible_printers_condition": "", + "compatible_prints": [], + "compatible_prints_condition": "", + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "0" + ], + "eng_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "60" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cost": [ + "25.4" + ], + "filament_density": [ + "1.32" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_is_support": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "25" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_notes": [ + "" + ], + "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_length_toolchange": [ + "5" + ], + "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_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_shrink": [ + "100%" + ], + "filament_shrinkage_compensation_z": [ + "100%" + ], + "filament_soluble": [ + "0" + ], + "filament_start_gcode": [ + "" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_vendor": [ + "Snapmaker" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "idle_temperature": [ + "0" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "0" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "4" + ], + "slow_down_min_speed": [ + "20" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "dont_slow_down_outer_wall": [ + "1" + ], + "filament_cooling_final_speed": [ + "3.4" + ], + "filament_cooling_initial_speed": [ + "2.2" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_loading_speed": [ + "28" + ], + "filament_loading_speed_start": [ + "3" + ], + "filament_max_volumetric_speed": [ + "10" + ], + "filament_retraction_length": [ + "0.2" + ], + "filament_stamping_distance": [ + "0" + ], + "filament_stamping_loading_speed": [ + "0" + ], + "filament_unloading_speed": [ + "90" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "nozzle_temperature": [ + "230" + ], + "nozzle_temperature_initial_layer": [ + "230" + ], + "pressure_advance": [ + "0.015" ] } diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 0.2 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 0.2 nozzle.json new file mode 100644 index 0000000000..7fcb20f31b --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 0.2 nozzle.json @@ -0,0 +1,50 @@ +{ + "type": "filament", + "name": "Snapmaker PLA SnapSpeed @U1 0.2 nozzle", + "inherits": "Snapmaker PLA SnapSpeed @U1 base2", + "from": "system", + "setting_id": "jsAgNNiUC6DoO7rz", + "instantiation": "true", + "filament_deretraction_speed": [ + "30" + ], + "filament_flow_ratio": [ + "1.01" + ], + "filament_max_volumetric_speed": [ + "2" + ], + "filament_multitool_ramming_flow": [ + "30" + ], + "filament_retract_length_toolchange": [ + "5" + ], + "filament_retraction_speed": [ + "30" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "pressure_advance": [ + "0.2" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "compatible_printers": [ + "Snapmaker U1 (0.2 nozzle)" + ], + "enable_pressure_advance": [ + "0" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 0.6 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 0.6 nozzle.json new file mode 100644 index 0000000000..18fca8b4fd --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 0.6 nozzle.json @@ -0,0 +1,41 @@ +{ + "type": "filament", + "name": "Snapmaker PLA SnapSpeed @U1 0.6 nozzle", + "inherits": "Snapmaker PLA SnapSpeed @U1 base2", + "from": "system", + "setting_id": "aKudBpQBj3MZZZav", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.6 nozzle)" + ], + "filament_deretraction_speed": [ + "30" + ], + "filament_flow_ratio": [ + "0.97" + ], + "filament_multitool_ramming_flow": [ + "30" + ], + "filament_retract_length_toolchange": [ + "5" + ], + "filament_retraction_length": [ + "1.6" + ], + "filament_retraction_speed": [ + "30" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "enable_pressure_advance": [ + "0" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 0.8 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 0.8 nozzle.json new file mode 100644 index 0000000000..2ebadbd2b2 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 0.8 nozzle.json @@ -0,0 +1,41 @@ +{ + "type": "filament", + "name": "Snapmaker PLA SnapSpeed @U1 0.8 nozzle", + "inherits": "Snapmaker PLA SnapSpeed @U1 base2", + "from": "system", + "setting_id": "sWoInox4hzxzIHfe", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.8 nozzle)" + ], + "filament_deretraction_speed": [ + "30" + ], + "filament_multitool_ramming_flow": [ + "30" + ], + "filament_retract_length_toolchange": [ + "5" + ], + "filament_retraction_length": [ + "1.6" + ], + "filament_retraction_speed": [ + "30" + ], + "nozzle_temperature": [ + "215" + ], + "pressure_advance": [ + "0.018" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "enable_pressure_advance": [ + "0" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 base2.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 base2.json new file mode 100644 index 0000000000..84889e3d9b --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1 base2.json @@ -0,0 +1,281 @@ +{ + "type": "filament", + "name": "Snapmaker PLA SnapSpeed @U1 base2", + "from": "system", + "filament_id": "141703112701", + "instantiation": "false", + "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" + ], + "compatible_printers": [], + "compatible_printers_condition": "", + "compatible_prints": [], + "compatible_prints_condition": "", + "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": [ + "45" + ], + "eng_plate_temp_initial_layer": [ + "45" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cooling_final_speed": [ + "3.4" + ], + "filament_cooling_initial_speed": [ + "2.2" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_cost": [ + "24.99" + ], + "filament_density": [ + "1.26" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + " " + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_is_support": [ + "0" + ], + "filament_loading_speed": [ + "28" + ], + "filament_loading_speed_start": [ + "3" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "20" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_notes": [ + "" + ], + "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_toolchange_delay": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_vendor": [ + "snapmaker" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "55" + ], + "hot_plate_temp_initial_layer": [ + "55" + ], + "idle_temperature": [ + "0" + ], + "nozzle_temperature": [ + "220" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "pressure_advance": [ + "0.02" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "0" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "4" + ], + "slow_down_min_speed": [ + "20" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "45" + ], + "textured_plate_temp_initial_layer": [ + "45" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1.json index 96d86d2a81..2525f5b2a9 100644 --- a/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1.json +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA SnapSpeed @U1.json @@ -33,13 +33,13 @@ "0" ], "close_fan_the_first_x_layers": [ - "3" + "1" ], "compatible_printers_condition": "", "compatible_prints": [], "compatible_prints_condition": "", "complete_print_exhaust_fan_speed": [ - "80" + "70" ], "cool_plate_temp": [ "60" @@ -47,20 +47,17 @@ "cool_plate_temp_initial_layer": [ "60" ], - "default_filament_colour": [ - "" - ], "dont_slow_down_outer_wall": [ "0" ], "during_print_exhaust_fan_speed": [ - "60" + "70" ], "enable_overhang_bridge_fan": [ "1" ], "enable_pressure_advance": [ - "1" + "0" ], "eng_plate_temp": [ "60" @@ -102,7 +99,7 @@ "; filament end gcode \n" ], "filament_flow_ratio": [ - "0.99" + "0.966" ], "filament_is_support": [ "0" @@ -117,7 +114,7 @@ "nil" ], "filament_max_volumetric_speed": [ - "18" + "20" ], "filament_minimal_purge_on_wipe_tower": [ "15" @@ -126,7 +123,7 @@ "1" ], "filament_multitool_ramming_flow": [ - "40" + "30" ], "filament_multitool_ramming_volume": [ "5" @@ -140,6 +137,9 @@ "filament_retract_before_wipe": [ "nil" ], + "filament_retract_length_toolchange": [ + "5" + ], "filament_retract_lift_above": [ "nil" ], @@ -159,13 +159,13 @@ "nil" ], "filament_retraction_length": [ - "0.8" + "1.2" ], "filament_retraction_minimum_travel": [ "nil" ], "filament_retraction_speed": [ - "30" + "nil" ], "filament_shrink": [ "100%" @@ -207,19 +207,19 @@ "nil" ], "filament_z_hop": [ - "nil" + "0.4" ], "filament_z_hop_types": [ - "nil" + "Slope Lift" ], "full_fan_speed_layer": [ "0" ], "hot_plate_temp": [ - "55" + "65" ], "hot_plate_temp_initial_layer": [ - "55" + "65" ], "idle_temperature": [ "0" @@ -231,7 +231,7 @@ "220" ], "nozzle_temperature_range_high": [ - "230" + "240" ], "nozzle_temperature_range_low": [ "190" @@ -246,7 +246,7 @@ "0.4157" ], "pressure_advance": [ - "0.026" + "0.02" ], "reduce_fan_stop_start_freq": [ "1" @@ -267,7 +267,7 @@ "-1" ], "temperature_vitrification": [ - "60" + "45" ], "textured_cool_plate_temp": [ "40" @@ -276,9 +276,9 @@ "40" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ] } diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.2 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.2 nozzle.json new file mode 100644 index 0000000000..6271b7af42 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.2 nozzle.json @@ -0,0 +1,284 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Translucent @U1 0.2 nozzle", + "inherits": "Snapmaker PLA Translucent @U1 base", + "from": "system", + "setting_id": "zIg9XLrieYNBduyn", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.2 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": [ + "100" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "compatible_printers_condition": "", + "compatible_prints": [], + "compatible_prints_condition": "", + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "0" + ], + "eng_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "60" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cooling_final_speed": [ + "3.4" + ], + "filament_cooling_initial_speed": [ + "2.2" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_cost": [ + "25" + ], + "filament_density": [ + "1.22" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_flow_ratio": [ + "1.02" + ], + "filament_is_support": [ + "0" + ], + "filament_loading_speed": [ + "28" + ], + "filament_loading_speed_start": [ + "3" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "1.6" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "5" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_notes": [ + "" + ], + "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": [ + "0%" + ], + "filament_retract_length_toolchange": [ + "5" + ], + "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.2" + ], + "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" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_vendor": [ + "Snapmaker" + ], + "filament_wipe": [ + "1" + ], + "filament_wipe_distance": [ + "1" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "idle_temperature": [ + "0" + ], + "nozzle_temperature": [ + "220" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "200" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "pressure_advance": [ + "0.15" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "0" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "10" + ], + "slow_down_min_speed": [ + "20" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.4 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.4 nozzle.json new file mode 100644 index 0000000000..7d4270ef31 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.4 nozzle.json @@ -0,0 +1,284 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Translucent @U1 0.4 nozzle", + "inherits": "Snapmaker PLA Translucent @U1 base", + "from": "system", + "setting_id": "RqtrcLcy124ICGEc", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (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": [ + "100" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "compatible_printers_condition": "", + "compatible_prints": [], + "compatible_prints_condition": "", + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "1" + ], + "eng_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "60" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cooling_final_speed": [ + "3.4" + ], + "filament_cooling_initial_speed": [ + "2.2" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_cost": [ + "25.4" + ], + "filament_density": [ + "1.32" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_flow_ratio": [ + "0.97" + ], + "filament_is_support": [ + "0" + ], + "filament_loading_speed": [ + "8" + ], + "filament_loading_speed_start": [ + "3" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_minimal_purge_on_wipe_tower": [ + "50" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_multitool_ramming_volume": [ + "10" + ], + "filament_notes": [ + "" + ], + "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_length_toolchange": [ + "5" + ], + "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.2" + ], + "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" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_vendor": [ + "Snapmaker" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "idle_temperature": [ + "0" + ], + "nozzle_temperature": [ + "220" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "pressure_advance": [ + "0.02" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "0" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "8" + ], + "slow_down_min_speed": [ + "20" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.6 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.6 nozzle.json new file mode 100644 index 0000000000..af3f95c757 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.6 nozzle.json @@ -0,0 +1,284 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Translucent @U1 0.6 nozzle", + "inherits": "Snapmaker PLA Translucent @U1 base", + "from": "system", + "setting_id": "OZHemzEcvzFMN8fL", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.6 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": [ + "100" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "compatible_printers_condition": "", + "compatible_prints": [], + "compatible_prints_condition": "", + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "0" + ], + "eng_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "60" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cooling_final_speed": [ + "3.4" + ], + "filament_cooling_initial_speed": [ + "2.2" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_cost": [ + "25" + ], + "filament_density": [ + "1.22" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_is_support": [ + "0" + ], + "filament_loading_speed": [ + "28" + ], + "filament_loading_speed_start": [ + "3" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_notes": [ + "" + ], + "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": [ + "0%" + ], + "filament_retract_length_toolchange": [ + "10" + ], + "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.5" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "50" + ], + "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" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_vendor": [ + "Snapmaker" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "idle_temperature": [ + "0" + ], + "nozzle_temperature": [ + "220" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "200" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "pressure_advance": [ + "0.02" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "0" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "8" + ], + "slow_down_min_speed": [ + "20" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.8 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.8 nozzle.json new file mode 100644 index 0000000000..a10a4b2fb1 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 0.8 nozzle.json @@ -0,0 +1,284 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Translucent @U1 0.8 nozzle", + "inherits": "Snapmaker PLA Translucent @U1 base", + "from": "system", + "setting_id": "IPehCg9fKawLorB5", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.8 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": [ + "100" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "compatible_printers_condition": "", + "compatible_prints": [], + "compatible_prints_condition": "", + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "0" + ], + "eng_plate_temp": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "60" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cooling_final_speed": [ + "3.4" + ], + "filament_cooling_initial_speed": [ + "2.2" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_cost": [ + "25" + ], + "filament_density": [ + "1.22" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_is_support": [ + "0" + ], + "filament_loading_speed": [ + "28" + ], + "filament_loading_speed_start": [ + "3" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_notes": [ + "" + ], + "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": [ + "0%" + ], + "filament_retract_length_toolchange": [ + "10" + ], + "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" + ], + "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" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_vendor": [ + "Snapmaker" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "idle_temperature": [ + "0" + ], + "nozzle_temperature": [ + "220" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "200" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pellet_flow_coefficient": [ + "0.4157" + ], + "pressure_advance": [ + "0.02" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "0" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "8" + ], + "slow_down_min_speed": [ + "20" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "45" + ], + "textured_cool_plate_temp": [ + "40" + ], + "textured_cool_plate_temp_initial_layer": [ + "40" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 base.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 base.json new file mode 100644 index 0000000000..4f4842ae1d --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Translucent @U1 base.json @@ -0,0 +1,44 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Translucent @U1 base", + "inherits": "fdm_filament_pla", + "from": "system", + "filament_id": "SPTR001", + "instantiation": "false", + "filament_end_gcode": [ + "" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_loading_speed_start": [ + "35" + ], + "filament_loading_speed": [ + "35" + ], + "filament_unloading_speed_start": [ + "35" + ], + "filament_unloading_speed": [ + "35" + ], + "filament_load_time": [ + "2" + ], + "filament_unload_time": [ + "2" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_cooling_initial_speed": [ + "35" + ], + "filament_cooling_final_speed": [ + "60" + ], + "nozzle_temperature": [ + "220" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Wood @U1 0.4 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Wood @U1 0.4 nozzle.json new file mode 100644 index 0000000000..4768ac2783 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Wood @U1 0.4 nozzle.json @@ -0,0 +1,108 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Wood @U1 0.4 nozzle", + "inherits": "fdm_filament_pla", + "from": "system", + "setting_id": "XvizDDHbds3bVrzi", + "filament_id": "GFL9922", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.4 nozzle)" + ], + "filament_start_gcode": [ + "" + ], + "enable_pressure_advance": [ + "1" + ], + "filament_end_gcode": [ + "\n" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_vendor": [ + "Snapmaker" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "filament_flow_ratio": [ + "0.97" + ], + "filament_max_volumetric_speed": [ + "18" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_multitool_ramming_volume": [ + "10" + ], + "filament_retract_length_toolchange": [ + "5" + ], + "filament_retraction_length": [ + "0.6" + ], + "pressure_advance": [ + "0.025" + ], + "slow_down_layer_time": [ + "4" + ], + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "35" + ], + "cool_plate_temp_initial_layer": [ + "35" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "filament_cost": [ + "20" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "nozzle_temperature": [ + "220" + ], + "overhang_fan_threshold": [ + "50%" + ], + "slow_down_min_speed": [ + "20" + ], + "temperature_vitrification": [ + "45" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Wood @U1 0.6 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Wood @U1 0.6 nozzle.json new file mode 100644 index 0000000000..43d306ebae --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Wood @U1 0.6 nozzle.json @@ -0,0 +1,114 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Wood @U1 0.6 nozzle", + "inherits": "fdm_filament_pla", + "from": "system", + "setting_id": "Kp77DCcitdmoyjqm", + "filament_id": "GFL9922", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.6 nozzle)" + ], + "filament_start_gcode": [ + "" + ], + "enable_pressure_advance": [ + "0" + ], + "filament_end_gcode": [ + "\n" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_vendor": [ + "Snapmaker" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_max_volumetric_speed": [ + "18" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_multitool_ramming_volume": [ + "10" + ], + "filament_retract_length_toolchange": [ + "5" + ], + "filament_retraction_length": [ + "0.4" + ], + "pressure_advance": [ + "0.014" + ], + "slow_down_layer_time": [ + "4" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "35" + ], + "cool_plate_temp_initial_layer": [ + "35" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "filament_cost": [ + "20" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "nozzle_temperature": [ + "220" + ], + "overhang_fan_threshold": [ + "50%" + ], + "slow_down_min_speed": [ + "20" + ], + "temperature_vitrification": [ + "45" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA Wood @U1 0.8 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA Wood @U1 0.8 nozzle.json new file mode 100644 index 0000000000..da788a35fb --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA Wood @U1 0.8 nozzle.json @@ -0,0 +1,114 @@ +{ + "type": "filament", + "name": "Snapmaker PLA Wood @U1 0.8 nozzle", + "inherits": "fdm_filament_pla", + "from": "system", + "setting_id": "nBYnNiqwLo6nAsqi", + "filament_id": "GFL9922", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.8 nozzle)" + ], + "filament_start_gcode": [ + "" + ], + "enable_pressure_advance": [ + "0" + ], + "filament_end_gcode": [ + "\n" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_vendor": [ + "Snapmaker" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "filament_flow_ratio": [ + "0.965" + ], + "filament_max_volumetric_speed": [ + "20" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_multitool_ramming_volume": [ + "10" + ], + "filament_retract_length_toolchange": [ + "5" + ], + "filament_retraction_length": [ + "0.4" + ], + "pressure_advance": [ + "0.007" + ], + "slow_down_layer_time": [ + "4" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "35" + ], + "cool_plate_temp_initial_layer": [ + "35" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "filament_cost": [ + "20" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "nozzle_temperature": [ + "220" + ], + "overhang_fan_threshold": [ + "50%" + ], + "slow_down_min_speed": [ + "20" + ], + "temperature_vitrification": [ + "45" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 0.4 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 0.4 nozzle.json new file mode 100644 index 0000000000..b986a7244a --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 0.4 nozzle.json @@ -0,0 +1,132 @@ +{ + "type": "filament", + "name": "Snapmaker PLA-CF @U1 0.4 nozzle", + "inherits": "fdm_filament_pla", + "from": "system", + "setting_id": "2INwruC3ZVkBTdUT", + "filament_id": "GFL98111", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.4 nozzle)" + ], + "enable_pressure_advance": [ + "1" + ], + "filament_end_gcode": [ + "" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_start_gcode": [ + "" + ], + "filament_vendor": [ + "Snapmaker" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_max_volumetric_speed": [ + "15" + ], + "filament_minimal_purge_on_wipe_tower": [ + "50" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_retract_length_toolchange": [ + "5" + ], + "filament_retraction_length": [ + "1" + ], + "filament_type": [ + "PLA-CF" + ], + "filament_z_hop": [ + "0.4" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "nozzle_temperature": [ + "240" + ], + "nozzle_temperature_initial_layer": [ + "240" + ], + "nozzle_temperature_range_high": [ + "250" + ], + "nozzle_temperature_range_low": [ + "200" + ], + "pressure_advance": [ + "0.01" + ], + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "45" + ], + "cool_plate_temp_initial_layer": [ + "45" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "filament_cost": [ + "20" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "overhang_fan_threshold": [ + "50%" + ], + "required_nozzle_HRC": [ + "40" + ], + "slow_down_layer_time": [ + "7" + ], + "slow_down_min_speed": [ + "20" + ], + "temperature_vitrification": [ + "45" + ], + "additional_cooling_fan_speed": [ + "0" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 0.6 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 0.6 nozzle.json new file mode 100644 index 0000000000..dcb6392634 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 0.6 nozzle.json @@ -0,0 +1,138 @@ +{ + "type": "filament", + "name": "Snapmaker PLA-CF @U1 0.6 nozzle", + "inherits": "fdm_filament_pla", + "from": "system", + "setting_id": "CKfdL85SvbOLzMuP", + "filament_id": "GFL98111", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.6 nozzle)" + ], + "enable_pressure_advance": [ + "0" + ], + "filament_end_gcode": [ + "" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "25" + ], + "filament_start_gcode": [ + "" + ], + "filament_vendor": [ + "Snapmaker" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_max_volumetric_speed": [ + "18" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_retract_length_toolchange": [ + "10" + ], + "filament_retraction_length": [ + "2" + ], + "filament_type": [ + "PLA-CF" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "nozzle_temperature": [ + "220" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature_range_high": [ + "250" + ], + "nozzle_temperature_range_low": [ + "210" + ], + "pressure_advance": [ + "0.015" + ], + "filament_cost": [ + "35" + ], + "filament_density": [ + "1.22" + ], + "slow_down_layer_time": [ + "8" + ], + "filament_wipe_distance": [ + "2" + ], + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "45" + ], + "cool_plate_temp_initial_layer": [ + "45" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "overhang_fan_threshold": [ + "50%" + ], + "required_nozzle_HRC": [ + "40" + ], + "slow_down_min_speed": [ + "20" + ], + "temperature_vitrification": [ + "45" + ], + "additional_cooling_fan_speed": [ + "0" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 0.8 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 0.8 nozzle.json new file mode 100644 index 0000000000..1e6e961497 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 0.8 nozzle.json @@ -0,0 +1,135 @@ +{ + "type": "filament", + "name": "Snapmaker PLA-CF @U1 0.8 nozzle", + "inherits": "fdm_filament_pla", + "from": "system", + "setting_id": "fhhnfJm4dN9FXpWQ", + "filament_id": "GFL98111", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.8 nozzle)" + ], + "enable_pressure_advance": [ + "0" + ], + "filament_end_gcode": [ + "" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "25" + ], + "filament_start_gcode": [ + "" + ], + "filament_vendor": [ + "Snapmaker" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_max_volumetric_speed": [ + "18" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_retract_length_toolchange": [ + "10" + ], + "filament_retraction_length": [ + "3" + ], + "filament_type": [ + "PLA-CF" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "nozzle_temperature": [ + "220" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature_range_high": [ + "250" + ], + "nozzle_temperature_range_low": [ + "210" + ], + "pressure_advance": [ + "0.015" + ], + "filament_cost": [ + "35" + ], + "filament_density": [ + "1.22" + ], + "slow_down_layer_time": [ + "8" + ], + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "45" + ], + "cool_plate_temp_initial_layer": [ + "45" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "overhang_fan_threshold": [ + "50%" + ], + "required_nozzle_HRC": [ + "40" + ], + "slow_down_min_speed": [ + "20" + ], + "temperature_vitrification": [ + "45" + ], + "additional_cooling_fan_speed": [ + "0" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 base.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 base.json index 617a8c23ea..63f877d965 100644 --- a/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 base.json +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1 base.json @@ -59,9 +59,6 @@ "temperature_vitrification": [ "150" ], - "default_filament_colour": [ - "" - ], "filament_type": [ "PLA-CF" ], diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1.json b/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1.json index ec04c8108d..9091258467 100644 --- a/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1.json +++ b/resources/profiles/Snapmaker/filament/Snapmaker PLA-CF @U1.json @@ -7,5 +7,8 @@ "instantiation": "true", "compatible_printers": [ "Snapmaker U1 (0.4 nozzle)" + ], + "filament_retract_length_toolchange": [ + "5" ] } diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PVA @U1 0.6 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PVA @U1 0.6 nozzle.json new file mode 100644 index 0000000000..b28e0627ad --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PVA @U1 0.6 nozzle.json @@ -0,0 +1,113 @@ +{ + "type": "filament", + "name": "Snapmaker PVA @U1 0.6 nozzle", + "inherits": "Snapmaker PVA @U1 base", + "from": "system", + "setting_id": "lIqgnfeZdAm8G0TH", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.6 nozzle)" + ], + "enable_pressure_advance": [ + "0" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "filament_cost": [ + "79.98" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_retract_length_toolchange": [ + "10" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "1" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_soluble": [ + "1" + ], + "filament_wipe_distance": [ + "2" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "nozzle_temperature": [ + "230" + ], + "nozzle_temperature_initial_layer": [ + "230" + ], + "nozzle_temperature_range_low": [ + "210" + ], + "pressure_advance": [ + "0.03" + ], + "slow_down_layer_time": [ + "7" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "filament_cooling_final_speed": [ + "3.4" + ], + "filament_cooling_initial_speed": [ + "2.2" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_loading_speed": [ + "28" + ], + "filament_loading_speed_start": [ + "3" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ], + "fan_min_speed": [ + "100" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PVA @U1 0.8 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker PVA @U1 0.8 nozzle.json new file mode 100644 index 0000000000..6572a60078 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker PVA @U1 0.8 nozzle.json @@ -0,0 +1,107 @@ +{ + "type": "filament", + "name": "Snapmaker PVA @U1 0.8 nozzle", + "inherits": "Snapmaker PVA @U1 base", + "from": "system", + "setting_id": "WxtuvwWxy73Gi0IK", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.8 nozzle)" + ], + "enable_pressure_advance": [ + "0" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "fan_min_speed": [ + "100" + ], + "filament_cost": [ + "79.98" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_flow_ratio": [ + "0.96" + ], + "filament_retract_length_toolchange": [ + "10" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_soluble": [ + "1" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "nozzle_temperature": [ + "225" + ], + "nozzle_temperature_initial_layer": [ + "225" + ], + "nozzle_temperature_range_low": [ + "205" + ], + "pressure_advance": [ + "0.03" + ], + "slow_down_layer_time": [ + "7" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "filament_cooling_final_speed": [ + "3.4" + ], + "filament_cooling_initial_speed": [ + "2.2" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_loading_speed": [ + "28" + ], + "filament_loading_speed_start": [ + "3" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker PVA @U1.json b/resources/profiles/Snapmaker/filament/Snapmaker PVA @U1.json index f9a33d7bcb..5ed5d243ac 100644 --- a/resources/profiles/Snapmaker/filament/Snapmaker PVA @U1.json +++ b/resources/profiles/Snapmaker/filament/Snapmaker PVA @U1.json @@ -7,5 +7,95 @@ "instantiation": "true", "compatible_printers": [ "Snapmaker U1 (0.4 nozzle)" + ], + "enable_pressure_advance": [ + "1" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "pressure_advance": [ + "0.03" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "fan_min_speed": [ + "100" + ], + "filament_cooling_final_speed": [ + "3.4" + ], + "filament_cooling_initial_speed": [ + "2.2" + ], + "filament_cooling_moves": [ + "4" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_loading_speed": [ + "28" + ], + "filament_loading_speed_start": [ + "3" + ], + "filament_max_volumetric_speed": [ + "5" + ], + "filament_minimal_purge_on_wipe_tower": [ + "20" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "0.1" + ], + "filament_retract_length_toolchange": [ + "4" + ], + "filament_retraction_length": [ + "0.4" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_unloading_speed": [ + "90" + ], + "filament_unloading_speed_start": [ + "100" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "nozzle_temperature": [ + "240" + ], + "nozzle_temperature_initial_layer": [ + "240" + ], + "slow_down_layer_time": [ + "10" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" ] } diff --git a/resources/profiles/Snapmaker/filament/Snapmaker TPU 90A @U1 0.6 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker TPU 90A @U1 0.6 nozzle.json new file mode 100644 index 0000000000..6ae8a5b675 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker TPU 90A @U1 0.6 nozzle.json @@ -0,0 +1,150 @@ +{ + "type": "filament", + "name": "Snapmaker TPU 90A @U1 0.6 nozzle", + "inherits": "fdm_filament_tpu", + "from": "system", + "setting_id": "uQCplebxmpBpzsnk", + "filament_id": "GFU99", + "instantiation": "true", + "filament_max_volumetric_speed": [ + "3.2" + ], + "compatible_printers": [ + "Snapmaker U1 (0.6 nozzle)" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ], + "filament_end_gcode": [ + "; filament end gcode \n\n" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "0.1" + ], + "pressure_advance": [ + "0.02" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_pressure_advance": [ + "0" + ], + "filament_deretraction_speed": [ + "20" + ], + "filament_flow_ratio": [ + "1.093" + ], + "filament_multitool_ramming_flow": [ + "5" + ], + "filament_retract_length_toolchange": [ + "4" + ], + "filament_retraction_length": [ + "0.6" + ], + "filament_retraction_speed": [ + "20" + ], + "filament_vendor": [ + "Snapmaker" + ], + "nozzle_temperature": [ + "220" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "slow_down_layer_time": [ + "14" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "filament_wipe": [ + "1" + ], + "filament_wipe_distance": [ + "0" + ], + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "cool_plate_temp": [ + "30" + ], + "cool_plate_temp_initial_layer": [ + "30" + ], + "eng_plate_temp": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "30" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cost": [ + "20" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "hot_plate_temp": [ + "35" + ], + "hot_plate_temp_initial_layer": [ + "35" + ], + "overhang_fan_speed": [ + "100" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "temperature_vitrification": [ + "30" + ], + "textured_plate_temp": [ + "35" + ], + "textured_plate_temp_initial_layer": [ + "35" + ], + "nozzle_temperature_range_low": [ + "200" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker TPU 90A @U1 0.8 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker TPU 90A @U1 0.8 nozzle.json new file mode 100644 index 0000000000..45f0f7a0e9 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker TPU 90A @U1 0.8 nozzle.json @@ -0,0 +1,144 @@ +{ + "type": "filament", + "name": "Snapmaker TPU 90A @U1 0.8 nozzle", + "inherits": "fdm_filament_tpu", + "from": "system", + "setting_id": "w4Hpl2qNPmgNvaeM", + "filament_id": "GFU99", + "instantiation": "true", + "filament_max_volumetric_speed": [ + "3.5" + ], + "compatible_printers": [ + "Snapmaker U1 (0.8 nozzle)" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ], + "filament_end_gcode": [ + "; filament end gcode \n\n" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "0.1" + ], + "pressure_advance": [ + "0.02" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "enable_pressure_advance": [ + "0" + ], + "filament_deretraction_speed": [ + "20" + ], + "filament_flow_ratio": [ + "1.095" + ], + "filament_multitool_ramming_flow": [ + "5" + ], + "filament_retract_length_toolchange": [ + "4" + ], + "filament_retraction_length": [ + "1.2" + ], + "filament_retraction_speed": [ + "20" + ], + "filament_vendor": [ + "Snapmaker" + ], + "nozzle_temperature": [ + "220" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "slow_down_layer_time": [ + "14" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "cool_plate_temp": [ + "30" + ], + "cool_plate_temp_initial_layer": [ + "30" + ], + "eng_plate_temp": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "30" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cost": [ + "20" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "hot_plate_temp": [ + "35" + ], + "hot_plate_temp_initial_layer": [ + "35" + ], + "overhang_fan_speed": [ + "100" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "temperature_vitrification": [ + "30" + ], + "textured_plate_temp": [ + "35" + ], + "textured_plate_temp_initial_layer": [ + "35" + ], + "nozzle_temperature_range_low": [ + "200" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker TPU 90A @U1.json b/resources/profiles/Snapmaker/filament/Snapmaker TPU 90A @U1.json new file mode 100644 index 0000000000..e89397849b --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker TPU 90A @U1.json @@ -0,0 +1,141 @@ +{ + "type": "filament", + "name": "Snapmaker TPU 90A @U1", + "inherits": "fdm_filament_tpu", + "from": "system", + "setting_id": "T4MmgICRrSzvmCZ5", + "filament_id": "GFU99", + "instantiation": "true", + "filament_max_volumetric_speed": [ + "3.2" + ], + "compatible_printers": [ + "Snapmaker U1 (0.4 nozzle)" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ], + "filament_end_gcode": [ + "; filament end gcode \n\n" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "0.1" + ], + "pressure_advance": [ + "0.4" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "complete_print_exhaust_fan_speed": [ + "100" + ], + "during_print_exhaust_fan_speed": [ + "100" + ], + "enable_pressure_advance": [ + "0" + ], + "filament_deretraction_speed": [ + "15" + ], + "filament_flow_ratio": [ + "1.045" + ], + "filament_multitool_ramming_flow": [ + "5" + ], + "filament_retract_length_toolchange": [ + "2" + ], + "filament_retraction_length": [ + "1.2" + ], + "filament_retraction_speed": [ + "15" + ], + "filament_vendor": [ + "Snapmaker" + ], + "nozzle_temperature": [ + "230" + ], + "nozzle_temperature_initial_layer": [ + "230" + ], + "slow_down_layer_time": [ + "14" + ], + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "cool_plate_temp": [ + "30" + ], + "cool_plate_temp_initial_layer": [ + "30" + ], + "eng_plate_temp": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "30" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cost": [ + "20" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "hot_plate_temp": [ + "35" + ], + "hot_plate_temp_initial_layer": [ + "35" + ], + "overhang_fan_speed": [ + "100" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "temperature_vitrification": [ + "30" + ], + "textured_plate_temp": [ + "35" + ], + "textured_plate_temp_initial_layer": [ + "35" + ], + "nozzle_temperature_range_low": [ + "200" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker TPU 95A @U1 base.json b/resources/profiles/Snapmaker/filament/Snapmaker TPU 95A @U1 base.json index a6d8c41b5d..3c51439206 100644 --- a/resources/profiles/Snapmaker/filament/Snapmaker TPU 95A @U1 base.json +++ b/resources/profiles/Snapmaker/filament/Snapmaker TPU 95A @U1 base.json @@ -43,9 +43,6 @@ "filament_retraction_speed": [ "nil" ], - "filament_settings_id": [ - "" - ], "filament_soluble": [ "0" ], diff --git a/resources/profiles/Snapmaker/filament/Snapmaker TPU 95A HF @U1 0.6 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker TPU 95A HF @U1 0.6 nozzle.json new file mode 100644 index 0000000000..1085c84e6f --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker TPU 95A HF @U1 0.6 nozzle.json @@ -0,0 +1,147 @@ +{ + "type": "filament", + "name": "Snapmaker TPU 95A HF @U1 0.6 nozzle", + "inherits": "fdm_filament_tpu", + "from": "system", + "setting_id": "Q2svXpkEqg0dCdq3", + "filament_id": "GFU99", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.6 nozzle)" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ], + "filament_end_gcode": [ + "; filament end gcode \n\n" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "0.1" + ], + "enable_pressure_advance": [ + "0" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_flow_ratio": [ + "1.067" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_multitool_ramming_flow": [ + "10" + ], + "filament_retract_length_toolchange": [ + "8" + ], + "filament_retraction_length": [ + "0.8" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_vendor": [ + "Snapmaker" + ], + "nozzle_temperature": [ + "215" + ], + "nozzle_temperature_initial_layer": [ + "215" + ], + "overhang_fan_threshold": [ + "95%" + ], + "pressure_advance": [ + "0.14" + ], + "slow_down_layer_time": [ + "8" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "30" + ], + "cool_plate_temp_initial_layer": [ + "30" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "30" + ], + "filament_cost": [ + "20" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "hot_plate_temp": [ + "35" + ], + "hot_plate_temp_initial_layer": [ + "35" + ], + "overhang_fan_speed": [ + "100" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "temperature_vitrification": [ + "30" + ], + "textured_plate_temp": [ + "35" + ], + "textured_plate_temp_initial_layer": [ + "35" + ], + "nozzle_temperature_range_low": [ + "200" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker TPU 95A HF @U1 0.8 nozzle.json b/resources/profiles/Snapmaker/filament/Snapmaker TPU 95A HF @U1 0.8 nozzle.json new file mode 100644 index 0000000000..bef4c7712f --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker TPU 95A HF @U1 0.8 nozzle.json @@ -0,0 +1,147 @@ +{ + "type": "filament", + "name": "Snapmaker TPU 95A HF @U1 0.8 nozzle", + "inherits": "fdm_filament_tpu", + "from": "system", + "setting_id": "RjsE08h3l37cAkAs", + "filament_id": "GFU99", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.8 nozzle)" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ], + "filament_end_gcode": [ + "; filament end gcode \n\n" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "0.1" + ], + "enable_pressure_advance": [ + "0" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_flow_ratio": [ + "1.045" + ], + "filament_max_volumetric_speed": [ + "16" + ], + "filament_multitool_ramming_flow": [ + "15" + ], + "filament_retract_length_toolchange": [ + "8" + ], + "filament_retraction_length": [ + "1" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_vendor": [ + "Snapmaker" + ], + "nozzle_temperature": [ + "215" + ], + "nozzle_temperature_initial_layer": [ + "215" + ], + "overhang_fan_threshold": [ + "95%" + ], + "pressure_advance": [ + "0.12" + ], + "slow_down_layer_time": [ + "12" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "filament_z_hop_types": [ + "Slope Lift" + ], + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "30" + ], + "cool_plate_temp_initial_layer": [ + "30" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "30" + ], + "filament_cost": [ + "20" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "hot_plate_temp": [ + "35" + ], + "hot_plate_temp_initial_layer": [ + "35" + ], + "overhang_fan_speed": [ + "100" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "temperature_vitrification": [ + "30" + ], + "textured_plate_temp": [ + "35" + ], + "textured_plate_temp_initial_layer": [ + "35" + ], + "nozzle_temperature_range_low": [ + "200" + ] +} diff --git a/resources/profiles/Snapmaker/filament/Snapmaker TPU 95A HF @U1.json b/resources/profiles/Snapmaker/filament/Snapmaker TPU 95A HF @U1.json new file mode 100644 index 0000000000..5e0696d906 --- /dev/null +++ b/resources/profiles/Snapmaker/filament/Snapmaker TPU 95A HF @U1.json @@ -0,0 +1,144 @@ +{ + "type": "filament", + "name": "Snapmaker TPU 95A HF @U1", + "inherits": "fdm_filament_tpu", + "from": "system", + "setting_id": "KwcwmV2UmZUgCBoz", + "filament_id": "GFU99", + "instantiation": "true", + "compatible_printers": [ + "Snapmaker U1 (0.4 nozzle)" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ], + "filament_end_gcode": [ + "; filament end gcode \n\n" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "0.1" + ], + "enable_pressure_advance": [ + "0" + ], + "fan_cooling_layer_time": [ + "40" + ], + "fan_max_speed": [ + "50" + ], + "fan_min_speed": [ + "10" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_flow_ratio": [ + "1.067" + ], + "filament_max_volumetric_speed": [ + "9" + ], + "filament_multitool_ramming_flow": [ + "10" + ], + "filament_retract_length_toolchange": [ + "6" + ], + "filament_retraction_length": [ + "1" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_vendor": [ + "Snapmaker" + ], + "nozzle_temperature": [ + "230" + ], + "nozzle_temperature_initial_layer": [ + "230" + ], + "overhang_fan_threshold": [ + "25%" + ], + "pressure_advance": [ + "0.23" + ], + "slow_down_layer_time": [ + "10" + ], + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "30" + ], + "cool_plate_temp_initial_layer": [ + "30" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "30" + ], + "filament_cost": [ + "20" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "hot_plate_temp": [ + "35" + ], + "hot_plate_temp_initial_layer": [ + "35" + ], + "overhang_fan_speed": [ + "100" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "temperature_vitrification": [ + "30" + ], + "textured_plate_temp": [ + "35" + ], + "textured_plate_temp_initial_layer": [ + "35" + ], + "nozzle_temperature_range_low": [ + "200" + ] +} diff --git a/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.2 nozzle).json b/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.2 nozzle).json index 8a5cbc56d8..183e125c73 100644 --- a/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.2 nozzle).json +++ b/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.2 nozzle).json @@ -1,13 +1,54 @@ { "type": "machine", - "setting_id": "CwJeuh1rxZcjvkXh", "name": "Snapmaker U1 (0.2 nozzle)", - "from": "system", - "instantiation": "true", "inherits": "fdm_U1", + "from": "system", + "setting_id": "CwJeuh1rxZcjvkXh", + "instantiation": "true", "printer_model": "Snapmaker U1", "printer_variant": "0.2", - "default_print_profile": "0.10 Standard @Snapmaker U1 (0.2 nozzle)", + "auxiliary_fan": "1", + "change_filament_gcode": ";===== date: 20260607 =====================\n; Change Tool[previous_extruder] -> Tool[next_extruder] (layer [layer_num])\n; max_layer_z [max_layer_z]\n; max_print_height [max_print_height]\n; print_sequence [print_sequence]\n\n{\nlocal move_z = 1.5;\nlocal max_speed_toolchange = 350.0;\nlocal wait_for_extruder_temp = true;\nposition[2] = position[2] + 2.0;\nlocal speed_toolchange = max_speed_toolchange;\n\nif travel_speed < max_speed_toolchange then\n speed_toolchange = travel_speed;\nendif\n\nif print_sequence == \"by object\" then\n\n if max_layer_z < ((max_print_height - z_offset) - 2) then\n move_z = z_offset + min(((max_layer_z - z_offset) + 2), max_print_height);\n endif\n\nendif\n\n\"G91\nG1 Z\" + move_z + \" F600\nG90\n\";\n\"G1 F\" + (speed_toolchange * 60) + \"\n\";\nif wait_for_extruder_temp and not((layer_num < 0) and (next_extruder == initial_tool)) then\n \"\n\";\n \"; \" + layer_num + \"\n\";\n if layer_num == 0 then\n \"M109 S\" + first_layer_temperature[next_extruder] + \" T\" + next_extruder + \"\n\";\n else\n \"M109 S\" + temperature[next_extruder] + \" T\" + next_extruder + \"\n\";\n endif\nendif\n\"M400\" + \"\n\";\n\"T\" + next_extruder + \"\n\";\nif filament_type[next_extruder] == \"PVA\" then\n\"SET_VELOCITY_LIMIT ACCEL=3000\n\";\nelse\nendif\nif previous_extruder != next_extruder and initial_extruder != next_extruder then\n\"SM_PRINT_PREEXTRUDE_FILAMENT INDEX=\" + next_extruder + \"\n\";\nendif\n\"G90\n\";\n}\n", + "deretraction_speed": [ + "30", + "30", + "30", + "30" + ], + "extruder_colour": [ + "#FCE94F", + "#FCE94F", + "#FCE94F", + "#FCE94F" + ], + "extruder_offset": [ + "0x0", + "0x0", + "0x0", + "0x0" + ], + "host_type": "octoprint", + "long_retractions_when_cut": [ + "0", + "0", + "0", + "0" + ], + "machine_end_gcode": ";===== date: 20260605 =====================\n; layer [layer_num]\n; max_layer_z [max_layer_z]\n; print_sequence [print_sequence]\n\n{if print_sequence == \"by object\"}\n{\nlocal move_z = max_print_height;\n\nif max_layer_z < ((max_print_height - z_offset) - 2) then\n move_z = z_offset + min(((max_layer_z - z_offset) + 2), max_print_height);\nendif\n}\n\nG91\nG1 X2 Y2 Z1 F24000\nG90\nG1 Z{move_z} F600\n{endif}\n\nPRINT_END\nTIMELAPSE_STOP\n", + "machine_max_jerk_z": [ + "3", + "0.4" + ], + "machine_max_speed_e": [ + "30", + "25" + ], + "machine_max_speed_z": [ + "20", + "12" + ], + "machine_start_gcode": "SET_PRINT_AUTO_BED_LEVELING ENABLE=1\nSET_TIME_LAPSE_CAMERA ENABLE=1\n;===== date: 20260128 =====================\n\nPRINT_START\nDEFECT_DETECTION_START\nSET_PRINT_STATS_INFO TOTAL_LAYER={total_layer_count} CURRENT_LAYER=0\nTIMELAPSE_START\nM140 S{bed_temperature_initial_layer_single}\nM104 T{initial_extruder} S140\nM204 S10000\nG28 X Y\nDEFECT_DETECT_NOODLE_FIRST\n;===== 床面异物检测 ========\nT{initial_extruder}\nG90\nDEFECT_DETECTION_DETECT_BED\n;===== 取放头检测 =================\nSM_PRINT_CHECK_SWITCH_EXTRUDER\n\n;===== 自动进料 & 挤出流量 & 预挤出 ======================\nSM_PRINT_EXTRUDER_PREHEAT EXTRUDER=1 TEMP=140\nSM_PRINT_AUTO_FEED EXTRUDER=0\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=0\nSM_PRINT_EXTRUDER_PREHEAT EXTRUDER=2 TEMP=140\nSM_PRINT_AUTO_FEED EXTRUDER=1\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=1\nSM_PRINT_EXTRUDER_PREHEAT EXTRUDER=3 TEMP=140\nSM_PRINT_AUTO_FEED EXTRUDER=2\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=2\nSM_PRINT_AUTO_FEED EXTRUDER=3\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=3\nM104 S0 T0 A0\nM104 S0 T1 A0\nM104 S0 T2 A0\nM104 S0 T3 A0\nM104 T{initial_extruder} S{nozzle_temperature[initial_extruder] - 90}\n\n;===== 粗回零 =================\nT{initial_extruder}\nM106 S255\nM106 P2 S0\nMOVE_TO_DISCARD_FILAMENT_POSITION\nM109 T{initial_extruder} S{nozzle_temperature[initial_extruder] - 90}\nROUGHLY_CLEAN_NOZZLE_WITH_DISCARD\nMOVE_TO_XY_IDLE_POSITION_EXTRUDER\nG28 Z I140 J140\n\n;===== 检测钢板 =================\nDETECT_BED_PLATE\n\n;===== 深度清洁喷嘴 =================\nG90\nG0 Z5 F10000\nMOVE_TO_DISCARD_FILAMENT_POSITION\nM109 S{nozzle_temperature[initial_extruder] - 50}\nROUGHLY_CLEAN_NOZZLE\nMOVE_TO_XY_IDLE_POSITION_EXTRUDER\nFINELY_CLEAN_NOZZLE_STAGE_1\nM104 S{nozzle_temperature[initial_extruder] - 90}\nG0 Z5 F10000\nMOVE_TO_DISCARD_FILAMENT_POSITION\nROUGHLY_CLEAN_NOZZLE\nMOVE_TO_XY_IDLE_POSITION_EXTRUDER\nFINELY_CLEAN_NOZZLE_STAGE_2\n\n;===== 精回零 =================\nM106 S255\nM109 S{nozzle_temperature[initial_extruder] - 90}\nM190 S{bed_temperature_initial_layer_single}\nM107 P2\nG90\nG0 Z5 F10000\nWAIT_CHAMBER_TEMP TIMEOUT=180\n{if curr_bed_type==\"High Temp Plate\"} \nG28 Z Z_OFFSET -0.07 \n{else} \nG28 Z \n{endif} \n\n\n;===== 热床调平 =================\n{if curr_bed_type==\"High Temp Plate\"} \n; Always pass `ADAPTIVE_MARGIN=0` because Orca has already handled `adaptive_bed_mesh_margin` internally\n; Make sure to set ADAPTIVE to 0 otherwise Klipper will use it's own adaptive bed mesh logic\nBED_MESH_CALIBRATE mesh_min={adaptive_bed_mesh_min[0]},{adaptive_bed_mesh_min[1]} mesh_max={adaptive_bed_mesh_max[0]},{adaptive_bed_mesh_max[1]} ALGORITHM=[bed_mesh_algo] PROBE_COUNT={bed_mesh_probe_count[0]},{bed_mesh_probe_count[1]} ADAPTIVE=0 ADAPTIVE_MARGIN=0 Z_OFFSET=-0.07\n{else} \n; Always pass `ADAPTIVE_MARGIN=0` because Orca has already handled `adaptive_bed_mesh_margin` internally\n; Make sure to set ADAPTIVE to 0 otherwise Klipper will use it's own adaptive bed mesh logic\nBED_MESH_CALIBRATE mesh_min={adaptive_bed_mesh_min[0]},{adaptive_bed_mesh_min[1]} mesh_max={adaptive_bed_mesh_max[0]},{adaptive_bed_mesh_max[1]} ALGORITHM=[bed_mesh_algo] PROBE_COUNT={bed_mesh_probe_count[0]},{bed_mesh_probe_count[1]} ADAPTIVE=0 ADAPTIVE_MARGIN=0\n{endif} \n\n\n;===== 画起始线 =================\nG90\nG1 Z1.5\nG0 X85 Y1 Z2 F18000\nM109 S{nozzle_temperature_initial_layer[initial_extruder]}\nG1 Z0.2\nM83\nG1 X185 E15 F360\nG1 Z1.5\n\nG90\nM106 S0", + "machine_tool_change_time": "5", "max_layer_height": [ "0.14", "0.14", @@ -26,5 +67,125 @@ "0.2", "0.2" ], - "nozzle_type": "hardened_steel" + "nozzle_type": "hardened_steel", + "printable_area": [ + "0.5x1", + "270.5x1", + "270.5x271", + "0.5x271" + ], + "printable_height": "270.05", + "retract_before_wipe": [ + "0%", + "0%", + "0%", + "0%" + ], + "retract_length_toolchange": [ + "10", + "10", + "10", + "10" + ], + "retract_lift_above": [ + "0", + "0", + "0", + "0" + ], + "retract_lift_below": [ + "269", + "269", + "269", + "269" + ], + "retract_lift_enforce": [ + "All Surfaces", + "All Surfaces", + "All Surfaces", + "All Surfaces" + ], + "retract_restart_extra": [ + "0", + "0", + "0", + "0" + ], + "retract_restart_extra_toolchange": [ + "0", + "0", + "0", + "0" + ], + "retract_when_changing_layer": [ + "1", + "1", + "1", + "1" + ], + "retraction_distances_when_cut": [ + "18", + "18", + "18", + "18" + ], + "retraction_length": [ + "0.4", + "0.4", + "0.4", + "0.4" + ], + "retraction_minimum_travel": [ + "1", + "1", + "1", + "1" + ], + "retraction_speed": [ + "30", + "30", + "30", + "30" + ], + "thumbnails": "48x48/PNG, 300x300/PNG", + "travel_slope": [ + "3", + "3", + "3", + "3" + ], + "wipe": [ + "1", + "1", + "1", + "1" + ], + "wipe_distance": [ + "2", + "2", + "2", + "2" + ], + "z_hop": [ + "0.4", + "0.4", + "0.4", + "0.4" + ], + "z_hop_types": [ + "Auto Lift", + "Auto Lift", + "Auto Lift", + "Auto Lift" + ], + "enable_filament_ramming": "0", + "extruder_clearance_height_to_rod": "27.5", + "extruder_clearance_radius": "72.5", + "machine_load_filament_time": "0", + "machine_unload_filament_time": "0", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\nTIMELAPSE_TAKE_FRAME\nDEFECT_DETECTION_DETECT", + "machine_pause_gcode": "M600", + "nozzle_volume": "143", + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]\nSET_PRINT_STATS_INFO TOTAL_LAYER={total_layer_count} CURRENT_LAYER={layer_num+1}", + "default_print_profile": "0.10 Standard @Snapmaker U1 (0.2 nozzle)" } diff --git a/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.4 nozzle).json b/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.4 nozzle).json index 1105a7ec1d..6d2ec2cfe6 100644 --- a/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.4 nozzle).json +++ b/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.4 nozzle).json @@ -1,14 +1,20 @@ { "type": "machine", - "setting_id": "UeTP4RqAd7xAMHVE", "name": "Snapmaker U1 (0.4 nozzle)", - "from": "system", - "instantiation": "true", "inherits": "fdm_U1", + "from": "system", + "setting_id": "UeTP4RqAd7xAMHVE", + "instantiation": "true", "printer_model": "Snapmaker U1", "printer_variant": "0.4", "auxiliary_fan": "1", "change_filament_gcode": ";===== date: 20260607 =====================\n; Change Tool[previous_extruder] -> Tool[next_extruder] (layer [layer_num])\n; max_layer_z [max_layer_z]\n; max_print_height [max_print_height]\n; print_sequence [print_sequence]\n\n{\nlocal move_z = 1.5;\nlocal max_speed_toolchange = 350.0;\nlocal wait_for_extruder_temp = true;\nposition[2] = position[2] + 2.0;\nlocal speed_toolchange = max_speed_toolchange;\n\nif travel_speed < max_speed_toolchange then\n speed_toolchange = travel_speed;\nendif\n\nif print_sequence == \"by object\" then\n\n if max_layer_z < ((max_print_height - z_offset) - 2) then\n move_z = z_offset + min(((max_layer_z - z_offset) + 2), max_print_height);\n endif\n\nendif\n\n\"G91\nG1 Z\" + move_z + \" F600\nG90\n\";\n\"G1 F\" + (speed_toolchange * 60) + \"\n\";\nif wait_for_extruder_temp and not((layer_num < 0) and (next_extruder == initial_tool)) then\n \"\n\";\n \"; \" + layer_num + \"\n\";\n if layer_num == 0 then\n \"M109 S\" + first_layer_temperature[next_extruder] + \" T\" + next_extruder + \"\n\";\n else\n \"M109 S\" + temperature[next_extruder] + \" T\" + next_extruder + \"\n\";\n endif\nendif\n\"M400\" + \"\n\";\n\"T\" + next_extruder + \"\n\";\nif filament_type[next_extruder] == \"PVA\" then\n\"SET_VELOCITY_LIMIT ACCEL=3000\n\";\nelse\nendif\nif previous_extruder != next_extruder and initial_extruder != next_extruder then\n\"SM_PRINT_PREEXTRUDE_FILAMENT INDEX=\" + next_extruder + \"\n\";\nendif\n\"G90\n\";\n}\n", + "deretraction_speed": [ + "30", + "30", + "30", + "30" + ], "extruder_colour": [ "#FCE94F", "#FCE94F", @@ -29,38 +35,6 @@ "0" ], "machine_end_gcode": ";===== date: 20260605 =====================\n; layer [layer_num]\n; max_layer_z [max_layer_z]\n; print_sequence [print_sequence]\n\n{if print_sequence == \"by object\"}\n{\nlocal move_z = max_print_height;\n\nif max_layer_z < ((max_print_height - z_offset) - 2) then\n move_z = z_offset + min(((max_layer_z - z_offset) + 2), max_print_height);\nendif\n}\n\nG91\nG1 X2 Y2 Z1 F24000\nG90\nG1 Z{move_z} F600\n{endif}\n\nPRINT_END\nTIMELAPSE_STOP\n", - "machine_max_acceleration_extruding": [ - "25000", - "25000" - ], - "machine_max_acceleration_retracting": [ - "5000", - "5000" - ], - "machine_max_acceleration_travel": [ - "25000", - "25000" - ], - "machine_max_acceleration_x": [ - "25000", - "25000" - ], - "machine_max_acceleration_y": [ - "25000", - "25000" - ], - "machine_max_acceleration_z": [ - "500", - "200" - ], - "machine_max_jerk_x": [ - "9", - "9" - ], - "machine_max_jerk_y": [ - "9", - "9" - ], "machine_max_jerk_z": [ "3", "0.4" @@ -69,22 +43,11 @@ "30", "25" ], - "machine_max_speed_x": [ - "1000", - "200" - ], - "machine_max_speed_y": [ - "1000", - "200" - ], "machine_max_speed_z": [ "20", "12" ], - "resonance_avoidance": "1", - "min_resonance_avoidance_speed": "40", - "max_resonance_avoidance_speed": "90", - "machine_start_gcode": "SET_PRINT_AUTO_BED_LEVELING ENABLE=1\nSET_TIME_LAPSE_CAMERA ENABLE=1\n;===== date: 20251222 =====================\n\nPRINT_START\nDEFECT_DETECTION_START\nSET_PRINT_STATS_INFO TOTAL_LAYER={total_layer_count}\nSET_PRINT_STATS_INFO CURRENT_LAYER=0\nTIMELAPSE_START\nM140 S{bed_temperature_initial_layer_single}\nM104 T{initial_extruder} S140\nM204 S10000\n\nG28 X Y\n;===== 床面异物检测 ========\nT{initial_extruder}\nG90\nDEFECT_DETECTION_DETECT_BED\n;===== 取放头检测 =================\nSM_PRINT_CHECK_SWITCH_EXTRUDER\n\n;===== 自动进料 & 挤出流量 & 预挤出 ======================\nSM_PRINT_EXTRUDER_PREHEAT EXTRUDER=1 TEMP=140\nSM_PRINT_AUTO_FEED EXTRUDER=0\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=0\nSM_PRINT_EXTRUDER_PREHEAT EXTRUDER=2 TEMP=140\nSM_PRINT_AUTO_FEED EXTRUDER=1\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=1\nSM_PRINT_EXTRUDER_PREHEAT EXTRUDER=3 TEMP=140\nSM_PRINT_AUTO_FEED EXTRUDER=2\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=2\nSM_PRINT_AUTO_FEED EXTRUDER=3\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=3\nM104 S0 T0 A0\nM104 S0 T1 A0\nM104 S0 T2 A0\nM104 S0 T3 A0\nM104 T{initial_extruder} S{nozzle_temperature[initial_extruder] - 90}\n\n;===== 粗回零 =================\nT{initial_extruder}\nM106 S255\nM106 P2 S0\nMOVE_TO_DISCARD_FILAMENT_POSITION\nM109 T{initial_extruder} S{nozzle_temperature[initial_extruder] - 90}\nROUGHLY_CLEAN_NOZZLE_WITH_DISCARD\nMOVE_TO_XY_IDLE_POSITION_EXTRUDER\nG28 Z I140 J140\n\n;===== 检测钢板 =================\nDETECT_BED_PLATE\n\n;===== 深度清洁喷嘴 =================\nG90\nG0 Z5 F10000\nMOVE_TO_DISCARD_FILAMENT_POSITION\nM109 S{nozzle_temperature[initial_extruder] - 50}\nROUGHLY_CLEAN_NOZZLE\nMOVE_TO_XY_IDLE_POSITION_EXTRUDER\nFINELY_CLEAN_NOZZLE_STAGE_1\nM104 S{nozzle_temperature[initial_extruder] - 90}\nG0 Z5 F10000\nMOVE_TO_DISCARD_FILAMENT_POSITION\nROUGHLY_CLEAN_NOZZLE\nMOVE_TO_XY_IDLE_POSITION_EXTRUDER\nFINELY_CLEAN_NOZZLE_STAGE_2\n\n;===== 精回零 =================\nM106 S255\nM109 S{nozzle_temperature[initial_extruder] - 90}\nM190 S{bed_temperature_initial_layer_single}\nM107 P2\nG90\nG0 Z5 F10000\nG28 Z\n\n;===== 热床调平 =================\n; Always pass `ADAPTIVE_MARGIN=0` because Orca has already handled `adaptive_bed_mesh_margin` internally\n; Make sure to set ADAPTIVE to 0 otherwise Klipper will use it's own adaptive bed mesh logic\nBED_MESH_CALIBRATE mesh_min={adaptive_bed_mesh_min[0]},{adaptive_bed_mesh_min[1]} mesh_max={adaptive_bed_mesh_max[0]},{adaptive_bed_mesh_max[1]} ALGORITHM=[bed_mesh_algo] PROBE_COUNT={bed_mesh_probe_count[0]},{bed_mesh_probe_count[1]} ADAPTIVE=0 ADAPTIVE_MARGIN=0\n; Original upstream: BED_MESH_CALIBRATE PROBE_COUNT=11,11\n\n;===== 画起始线 =================\nG90\nG1 Z1.5\nG0 X10 Y3 Z2 F18000\nM109 S{nozzle_temperature_initial_layer[initial_extruder]}\nG1 Z0.2\nM83\nG1 X110 E15 F360\nG1 Z1.5\n\nG90\nM106 S0", + "machine_start_gcode": "SET_PRINT_AUTO_BED_LEVELING ENABLE=1\nSET_TIME_LAPSE_CAMERA ENABLE=1\n;===== date: 20260128 =====================\n\nPRINT_START\nDEFECT_DETECTION_START\nSET_PRINT_STATS_INFO TOTAL_LAYER={total_layer_count} CURRENT_LAYER=0\nTIMELAPSE_START\nM140 S{bed_temperature_initial_layer_single}\nM104 T{initial_extruder} S140\nM204 S10000\nG28 X Y\nDEFECT_DETECT_NOODLE_FIRST\n;===== 床面异物检测 ========\nT{initial_extruder}\nG90\nDEFECT_DETECTION_DETECT_BED\n;===== 取放头检测 =================\nSM_PRINT_CHECK_SWITCH_EXTRUDER\n\n;===== 自动进料 & 挤出流量 & 预挤出 ======================\nSM_PRINT_EXTRUDER_PREHEAT EXTRUDER=1 TEMP=140\nSM_PRINT_AUTO_FEED EXTRUDER=0\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=0\nSM_PRINT_EXTRUDER_PREHEAT EXTRUDER=2 TEMP=140\nSM_PRINT_AUTO_FEED EXTRUDER=1\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=1\nSM_PRINT_EXTRUDER_PREHEAT EXTRUDER=3 TEMP=140\nSM_PRINT_AUTO_FEED EXTRUDER=2\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=2\nSM_PRINT_AUTO_FEED EXTRUDER=3\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=3\nM104 S0 T0 A0\nM104 S0 T1 A0\nM104 S0 T2 A0\nM104 S0 T3 A0\nM104 T{initial_extruder} S{nozzle_temperature[initial_extruder] - 90}\n\n;===== 粗回零 =================\nT{initial_extruder}\nM106 S255\nM106 P2 S0\nMOVE_TO_DISCARD_FILAMENT_POSITION\nM109 T{initial_extruder} S{nozzle_temperature[initial_extruder] - 90}\nROUGHLY_CLEAN_NOZZLE_WITH_DISCARD\nMOVE_TO_XY_IDLE_POSITION_EXTRUDER\nG28 Z I140 J140\n\n;===== 检测钢板 =================\nDETECT_BED_PLATE\n\n;===== 深度清洁喷嘴 =================\nG90\nG0 Z5 F10000\nMOVE_TO_DISCARD_FILAMENT_POSITION\nM109 S{nozzle_temperature[initial_extruder] - 50}\nROUGHLY_CLEAN_NOZZLE\nMOVE_TO_XY_IDLE_POSITION_EXTRUDER\nFINELY_CLEAN_NOZZLE_STAGE_1\nM104 S{nozzle_temperature[initial_extruder] - 90}\nG0 Z5 F10000\nMOVE_TO_DISCARD_FILAMENT_POSITION\nROUGHLY_CLEAN_NOZZLE\nMOVE_TO_XY_IDLE_POSITION_EXTRUDER\nFINELY_CLEAN_NOZZLE_STAGE_2\n\n;===== 精回零 =================\nM106 S255\nM109 S{nozzle_temperature[initial_extruder] - 90}\nM190 S{bed_temperature_initial_layer_single}\nM107 P2\nG90\nG0 Z5 F10000\nWAIT_CHAMBER_TEMP TIMEOUT=180\n{if curr_bed_type==\"High Temp Plate\"} \nG28 Z Z_OFFSET -0.07 \n{else} \nG28 Z \n{endif} \n\n\n;===== 热床调平 =================\n{if curr_bed_type==\"High Temp Plate\"} \n; Always pass `ADAPTIVE_MARGIN=0` because Orca has already handled `adaptive_bed_mesh_margin` internally\n; Make sure to set ADAPTIVE to 0 otherwise Klipper will use it's own adaptive bed mesh logic\nBED_MESH_CALIBRATE mesh_min={adaptive_bed_mesh_min[0]},{adaptive_bed_mesh_min[1]} mesh_max={adaptive_bed_mesh_max[0]},{adaptive_bed_mesh_max[1]} ALGORITHM=[bed_mesh_algo] PROBE_COUNT={bed_mesh_probe_count[0]},{bed_mesh_probe_count[1]} ADAPTIVE=0 ADAPTIVE_MARGIN=0 Z_OFFSET=-0.07\n{else} \n; Always pass `ADAPTIVE_MARGIN=0` because Orca has already handled `adaptive_bed_mesh_margin` internally\n; Make sure to set ADAPTIVE to 0 otherwise Klipper will use it's own adaptive bed mesh logic\nBED_MESH_CALIBRATE mesh_min={adaptive_bed_mesh_min[0]},{adaptive_bed_mesh_min[1]} mesh_max={adaptive_bed_mesh_max[0]},{adaptive_bed_mesh_max[1]} ALGORITHM=[bed_mesh_algo] PROBE_COUNT={bed_mesh_probe_count[0]},{bed_mesh_probe_count[1]} ADAPTIVE=0 ADAPTIVE_MARGIN=0\n{endif} \n\n\n;===== 画起始线 =================\nG90\nG1 Z1.5\nG0 X85 Y1 Z2 F18000\nM109 S{nozzle_temperature_initial_layer[initial_extruder]}\nG1 Z0.2\nM83\nG1 X185 E15 F360\nG1 Z1.5\n\nG90\nM106 S0", "machine_tool_change_time": "5", "max_layer_height": [ "0.32", @@ -104,7 +67,7 @@ "0.4", "0.4" ], - "nozzle_type": "stainless_steel", + "nozzle_type": "hardened_steel", "printable_area": [ "0.5x1", "270.5x1", @@ -112,7 +75,6 @@ "0.5x271" ], "printable_height": "270.05", - "printer_settings_id": "MyToolChanger 0.4 nozzle - Copy", "retract_before_wipe": [ "0%", "0%", @@ -168,10 +130,10 @@ "18" ], "retraction_length": [ - "0.8", - "0.8", - "0.8", - "0.8" + "1.5", + "1.5", + "1.5", + "1.5" ], "retraction_minimum_travel": [ "1", @@ -180,16 +142,10 @@ "1" ], "retraction_speed": [ - "40", - "40", - "40", - "40" - ], - "deretraction_speed": [ - "35", - "35", - "35", - "35" + "30", + "30", + "30", + "30" ], "thumbnails": "48x48/PNG, 300x300/PNG", "travel_slope": [ @@ -228,17 +184,11 @@ "machine_load_filament_time": "0", "machine_unload_filament_time": "0", "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\nTIMELAPSE_TAKE_FRAME\nDEFECT_DETECTION_DETECT", - "z_hop_when_prime": [ - "0", - "0", - "0", - "0" - ], - "ramming_pressure_advance_value": "0.02", - "tool_change_temprature_wait": "0", - "printer_notes": "", + "default_print_profile": "0.20 Standard @Snapmaker U1 (0.4 nozzle)", "machine_pause_gcode": "M600", - "default_bed_type": "Textured PEI Plate", - "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]\nSET_PRINT_STATS_INFO TOTAL_LAYER={total_layer_count}\nSET_PRINT_STATS_INFO CURRENT_LAYER={layer_num+1}", - "nozzle_volume": "143" + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]\nSET_PRINT_STATS_INFO TOTAL_LAYER={total_layer_count} CURRENT_LAYER={layer_num+1}", + "nozzle_volume": "143", + "resonance_avoidance": "1", + "min_resonance_avoidance_speed": "40", + "max_resonance_avoidance_speed": "90" } diff --git a/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.4+0.6 nozzle).json b/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.4+0.6 nozzle).json index f637b2a592..c9866329bd 100644 --- a/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.4+0.6 nozzle).json +++ b/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.4+0.6 nozzle).json @@ -1,10 +1,10 @@ { "type": "machine", - "setting_id": "O6AMxX1Ptbtv4zCK", "name": "Snapmaker U1 (0.4+0.6 nozzle)", - "from": "system", - "instantiation": "true", "inherits": "fdm_U1", + "from": "system", + "setting_id": "O6AMxX1Ptbtv4zCK", + "instantiation": "true", "printer_model": "Snapmaker U1", "printer_variant": "0.4+0.6", "default_print_profile": "0.20 Standard @Snapmaker U1 (0.4+0.6 nozzle)", diff --git a/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.6 nozzle).json b/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.6 nozzle).json index 60e699d108..a6cb0d0bd3 100644 --- a/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.6 nozzle).json +++ b/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.6 nozzle).json @@ -1,18 +1,59 @@ { "type": "machine", - "setting_id": "1OseO7RSPgE4CRKO", "name": "Snapmaker U1 (0.6 nozzle)", - "from": "system", - "instantiation": "true", "inherits": "fdm_U1", + "from": "system", + "setting_id": "1OseO7RSPgE4CRKO", + "instantiation": "true", "printer_model": "Snapmaker U1", "printer_variant": "0.6", - "default_print_profile": "0.20 Standard @Snapmaker U1 (0.6 nozzle)", + "auxiliary_fan": "1", + "change_filament_gcode": ";===== date: 20260607 =====================\n; Change Tool[previous_extruder] -> Tool[next_extruder] (layer [layer_num])\n; max_layer_z [max_layer_z]\n; max_print_height [max_print_height]\n; print_sequence [print_sequence]\n\n{\nlocal move_z = 1.5;\nlocal max_speed_toolchange = 350.0;\nlocal wait_for_extruder_temp = true;\nposition[2] = position[2] + 2.0;\nlocal speed_toolchange = max_speed_toolchange;\n\nif travel_speed < max_speed_toolchange then\n speed_toolchange = travel_speed;\nendif\n\nif print_sequence == \"by object\" then\n\n if max_layer_z < ((max_print_height - z_offset) - 2) then\n move_z = z_offset + min(((max_layer_z - z_offset) + 2), max_print_height);\n endif\n\nendif\n\n\"G91\nG1 Z\" + move_z + \" F600\nG90\n\";\n\"G1 F\" + (speed_toolchange * 60) + \"\n\";\nif wait_for_extruder_temp and not((layer_num < 0) and (next_extruder == initial_tool)) then\n \"\n\";\n \"; \" + layer_num + \"\n\";\n if layer_num == 0 then\n \"M109 S\" + first_layer_temperature[next_extruder] + \" T\" + next_extruder + \"\n\";\n else\n \"M109 S\" + temperature[next_extruder] + \" T\" + next_extruder + \"\n\";\n endif\nendif\n\"M400\" + \"\n\";\n\"T\" + next_extruder + \"\n\";\nif filament_type[next_extruder] == \"PVA\" then\n\"SET_VELOCITY_LIMIT ACCEL=3000\n\";\nelse\nendif\nif previous_extruder != next_extruder and initial_extruder != next_extruder then\n\"SM_PRINT_PREEXTRUDE_FILAMENT INDEX=\" + next_extruder + \"\n\";\nendif\n\"G90\n\";\n}\n", + "deretraction_speed": [ + "30", + "30", + "30", + "30" + ], + "extruder_colour": [ + "#FCE94F", + "#FCE94F", + "#FCE94F", + "#FCE94F" + ], + "extruder_offset": [ + "0x0", + "0x0", + "0x0", + "0x0" + ], + "host_type": "octoprint", + "long_retractions_when_cut": [ + "0", + "0", + "0", + "0" + ], + "machine_end_gcode": ";===== date: 20260605 =====================\n; layer [layer_num]\n; max_layer_z [max_layer_z]\n; print_sequence [print_sequence]\n\n{if print_sequence == \"by object\"}\n{\nlocal move_z = max_print_height;\n\nif max_layer_z < ((max_print_height - z_offset) - 2) then\n move_z = z_offset + min(((max_layer_z - z_offset) + 2), max_print_height);\nendif\n}\n\nG91\nG1 X2 Y2 Z1 F24000\nG90\nG1 Z{move_z} F600\n{endif}\n\nPRINT_END\nTIMELAPSE_STOP\n", + "machine_max_jerk_z": [ + "3", + "0.4" + ], + "machine_max_speed_e": [ + "30", + "25" + ], + "machine_max_speed_z": [ + "20", + "12" + ], + "machine_start_gcode": "SET_PRINT_AUTO_BED_LEVELING ENABLE=1\nSET_TIME_LAPSE_CAMERA ENABLE=1\n;===== date: 20260128 =====================\n\nPRINT_START\nDEFECT_DETECTION_START\nSET_PRINT_STATS_INFO TOTAL_LAYER={total_layer_count} CURRENT_LAYER=0\nTIMELAPSE_START\nM140 S{bed_temperature_initial_layer_single}\nM104 T{initial_extruder} S140\nM204 S10000\nG28 X Y\nDEFECT_DETECT_NOODLE_FIRST\n;===== 床面异物检测 ========\nT{initial_extruder}\nG90\nDEFECT_DETECTION_DETECT_BED\n;===== 取放头检测 =================\nSM_PRINT_CHECK_SWITCH_EXTRUDER\n\n;===== 自动进料 & 挤出流量 & 预挤出 ======================\nSM_PRINT_EXTRUDER_PREHEAT EXTRUDER=1 TEMP=140\nSM_PRINT_AUTO_FEED EXTRUDER=0\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=0\nSM_PRINT_EXTRUDER_PREHEAT EXTRUDER=2 TEMP=140\nSM_PRINT_AUTO_FEED EXTRUDER=1\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=1\nSM_PRINT_EXTRUDER_PREHEAT EXTRUDER=3 TEMP=140\nSM_PRINT_AUTO_FEED EXTRUDER=2\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=2\nSM_PRINT_AUTO_FEED EXTRUDER=3\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=3\nM104 S0 T0 A0\nM104 S0 T1 A0\nM104 S0 T2 A0\nM104 S0 T3 A0\nM104 T{initial_extruder} S{nozzle_temperature[initial_extruder] - 90}\n\n;===== 粗回零 =================\nT{initial_extruder}\nM106 S255\nM106 P2 S0\nMOVE_TO_DISCARD_FILAMENT_POSITION\nM109 T{initial_extruder} S{nozzle_temperature[initial_extruder] - 90}\nROUGHLY_CLEAN_NOZZLE_WITH_DISCARD\nMOVE_TO_XY_IDLE_POSITION_EXTRUDER\nG28 Z I140 J140\n\n;===== 检测钢板 =================\nDETECT_BED_PLATE\n\n;===== 深度清洁喷嘴 =================\nG90\nG0 Z5 F10000\nMOVE_TO_DISCARD_FILAMENT_POSITION\nM109 S{nozzle_temperature[initial_extruder] - 50}\nROUGHLY_CLEAN_NOZZLE\nMOVE_TO_XY_IDLE_POSITION_EXTRUDER\nFINELY_CLEAN_NOZZLE_STAGE_1\nM104 S{nozzle_temperature[initial_extruder] - 90}\nG0 Z5 F10000\nMOVE_TO_DISCARD_FILAMENT_POSITION\nROUGHLY_CLEAN_NOZZLE\nMOVE_TO_XY_IDLE_POSITION_EXTRUDER\nFINELY_CLEAN_NOZZLE_STAGE_2\n\n;===== 精回零 =================\nM106 S255\nM109 S{nozzle_temperature[initial_extruder] - 90}\nM190 S{bed_temperature_initial_layer_single}\nM107 P2\nG90\nG0 Z5 F10000\nWAIT_CHAMBER_TEMP TIMEOUT=180\n{if curr_bed_type==\"High Temp Plate\"} \nG28 Z Z_OFFSET -0.07 \n{else} \nG28 Z \n{endif} \n\n\n;===== 热床调平 =================\n{if curr_bed_type==\"High Temp Plate\"} \n; Always pass `ADAPTIVE_MARGIN=0` because Orca has already handled `adaptive_bed_mesh_margin` internally\n; Make sure to set ADAPTIVE to 0 otherwise Klipper will use it's own adaptive bed mesh logic\nBED_MESH_CALIBRATE mesh_min={adaptive_bed_mesh_min[0]},{adaptive_bed_mesh_min[1]} mesh_max={adaptive_bed_mesh_max[0]},{adaptive_bed_mesh_max[1]} ALGORITHM=[bed_mesh_algo] PROBE_COUNT={bed_mesh_probe_count[0]},{bed_mesh_probe_count[1]} ADAPTIVE=0 ADAPTIVE_MARGIN=0 Z_OFFSET=-0.07\n{else} \n; Always pass `ADAPTIVE_MARGIN=0` because Orca has already handled `adaptive_bed_mesh_margin` internally\n; Make sure to set ADAPTIVE to 0 otherwise Klipper will use it's own adaptive bed mesh logic\nBED_MESH_CALIBRATE mesh_min={adaptive_bed_mesh_min[0]},{adaptive_bed_mesh_min[1]} mesh_max={adaptive_bed_mesh_max[0]},{adaptive_bed_mesh_max[1]} ALGORITHM=[bed_mesh_algo] PROBE_COUNT={bed_mesh_probe_count[0]},{bed_mesh_probe_count[1]} ADAPTIVE=0 ADAPTIVE_MARGIN=0\n{endif} \n\n\n;===== 画起始线 =================\nG90\nG1 Z1.5\nG0 X85 Y1 Z2 F18000\nM109 S{nozzle_temperature_initial_layer[initial_extruder]}\nG1 Z0.2\nM83\nG1 X185 E15 F360\nG1 Z1.5\n\nG90\nM106 S0", + "machine_tool_change_time": "5", "max_layer_height": [ - "0.48", - "0.48", - "0.48", - "0.48" + "0.42", + "0.42", + "0.42", + "0.42" ], "min_layer_height": [ "0.12", @@ -26,5 +67,125 @@ "0.6", "0.6" ], - "nozzle_type": "stainless_steel" + "nozzle_type": "stainless_steel", + "printable_area": [ + "0.5x1", + "270.5x1", + "270.5x271", + "0.5x271" + ], + "printable_height": "270.05", + "retract_before_wipe": [ + "0%", + "0%", + "0%", + "0%" + ], + "retract_length_toolchange": [ + "10", + "10", + "10", + "10" + ], + "retract_lift_above": [ + "0", + "0", + "0", + "0" + ], + "retract_lift_below": [ + "269", + "269", + "269", + "269" + ], + "retract_lift_enforce": [ + "All Surfaces", + "All Surfaces", + "All Surfaces", + "All Surfaces" + ], + "retract_restart_extra": [ + "0", + "0", + "0", + "0" + ], + "retract_restart_extra_toolchange": [ + "0", + "0", + "0", + "0" + ], + "retract_when_changing_layer": [ + "1", + "1", + "1", + "1" + ], + "retraction_distances_when_cut": [ + "18", + "18", + "18", + "18" + ], + "retraction_length": [ + "1.4", + "1.4", + "1.4", + "1.4" + ], + "retraction_minimum_travel": [ + "3", + "3", + "3", + "3" + ], + "retraction_speed": [ + "30", + "30", + "30", + "30" + ], + "thumbnails": "48x48/PNG, 300x300/PNG", + "travel_slope": [ + "3", + "3", + "3", + "3" + ], + "wipe": [ + "1", + "1", + "1", + "1" + ], + "wipe_distance": [ + "1", + "1", + "1", + "1" + ], + "z_hop": [ + "0.4", + "0.4", + "0.4", + "0.4" + ], + "z_hop_types": [ + "Auto Lift", + "Auto Lift", + "Auto Lift", + "Auto Lift" + ], + "enable_filament_ramming": "0", + "extruder_clearance_height_to_rod": "27.5", + "extruder_clearance_radius": "72.5", + "machine_load_filament_time": "0", + "machine_unload_filament_time": "0", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\nTIMELAPSE_TAKE_FRAME\nDEFECT_DETECTION_DETECT", + "machine_pause_gcode": "M600", + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]\nSET_PRINT_STATS_INFO TOTAL_LAYER={total_layer_count} CURRENT_LAYER={layer_num+1}", + "nozzle_volume": "143", + "default_print_profile": "0.30 Standard @Snapmaker U1 (0.6 nozzle)" } diff --git a/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.8 nozzle).json b/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.8 nozzle).json index b775c2c964..ef4da1a516 100644 --- a/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.8 nozzle).json +++ b/resources/profiles/Snapmaker/machine/Snapmaker U1 (0.8 nozzle).json @@ -1,13 +1,54 @@ { "type": "machine", - "setting_id": "WTkhQtyDO06YY6AG", "name": "Snapmaker U1 (0.8 nozzle)", - "from": "system", - "instantiation": "true", "inherits": "fdm_U1", + "from": "system", + "setting_id": "WTkhQtyDO06YY6AG", + "instantiation": "true", "printer_model": "Snapmaker U1", "printer_variant": "0.8", - "default_print_profile": "0.40 Standard @Snapmaker U1 (0.8 nozzle)", + "auxiliary_fan": "1", + "change_filament_gcode": ";===== date: 20260607 =====================\n; Change Tool[previous_extruder] -> Tool[next_extruder] (layer [layer_num])\n; max_layer_z [max_layer_z]\n; max_print_height [max_print_height]\n; print_sequence [print_sequence]\n\n{\nlocal move_z = 1.5;\nlocal max_speed_toolchange = 350.0;\nlocal wait_for_extruder_temp = true;\nposition[2] = position[2] + 2.0;\nlocal speed_toolchange = max_speed_toolchange;\n\nif travel_speed < max_speed_toolchange then\n speed_toolchange = travel_speed;\nendif\n\nif print_sequence == \"by object\" then\n\n if max_layer_z < ((max_print_height - z_offset) - 2) then\n move_z = z_offset + min(((max_layer_z - z_offset) + 2), max_print_height);\n endif\n\nendif\n\n\"G91\nG1 Z\" + move_z + \" F600\nG90\n\";\n\"G1 F\" + (speed_toolchange * 60) + \"\n\";\nif wait_for_extruder_temp and not((layer_num < 0) and (next_extruder == initial_tool)) then\n \"\n\";\n \"; \" + layer_num + \"\n\";\n if layer_num == 0 then\n \"M109 S\" + first_layer_temperature[next_extruder] + \" T\" + next_extruder + \"\n\";\n else\n \"M109 S\" + temperature[next_extruder] + \" T\" + next_extruder + \"\n\";\n endif\nendif\n\"M400\" + \"\n\";\n\"T\" + next_extruder + \"\n\";\nif filament_type[next_extruder] == \"PVA\" then\n\"SET_VELOCITY_LIMIT ACCEL=3000\n\";\nelse\nendif\nif previous_extruder != next_extruder and initial_extruder != next_extruder then\n\"SM_PRINT_PREEXTRUDE_FILAMENT INDEX=\" + next_extruder + \"\n\";\nendif\n\"G90\n\";\n}\n", + "deretraction_speed": [ + "30", + "30", + "30", + "30" + ], + "extruder_colour": [ + "#FCE94F", + "#FCE94F", + "#FCE94F", + "#FCE94F" + ], + "extruder_offset": [ + "0x0", + "0x0", + "0x0", + "0x0" + ], + "host_type": "octoprint", + "long_retractions_when_cut": [ + "0", + "0", + "0", + "0" + ], + "machine_end_gcode": ";===== date: 20260605 =====================\n; layer [layer_num]\n; max_layer_z [max_layer_z]\n; print_sequence [print_sequence]\n\n{if print_sequence == \"by object\"}\n{\nlocal move_z = max_print_height;\n\nif max_layer_z < ((max_print_height - z_offset) - 2) then\n move_z = z_offset + min(((max_layer_z - z_offset) + 2), max_print_height);\nendif\n}\n\nG91\nG1 X2 Y2 Z1 F24000\nG90\nG1 Z{move_z} F600\n{endif}\n\nPRINT_END\nTIMELAPSE_STOP\n", + "machine_max_jerk_z": [ + "3", + "0.4" + ], + "machine_max_speed_e": [ + "30", + "25" + ], + "machine_max_speed_z": [ + "20", + "12" + ], + "machine_start_gcode": "SET_PRINT_AUTO_BED_LEVELING ENABLE=1\nSET_TIME_LAPSE_CAMERA ENABLE=1\n;===== date: 20260128 =====================\n\nPRINT_START\nDEFECT_DETECTION_START\nSET_PRINT_STATS_INFO TOTAL_LAYER={total_layer_count} CURRENT_LAYER=0\nTIMELAPSE_START\nM140 S{bed_temperature_initial_layer_single}\nM104 T{initial_extruder} S140\nM204 S10000\nG28 X Y\nDEFECT_DETECT_NOODLE_FIRST\n;===== 床面异物检测 ========\nT{initial_extruder}\nG90\nDEFECT_DETECTION_DETECT_BED\n;===== 取放头检测 =================\nSM_PRINT_CHECK_SWITCH_EXTRUDER\n\n;===== 自动进料 & 挤出流量 & 预挤出 ======================\nSM_PRINT_EXTRUDER_PREHEAT EXTRUDER=1 TEMP=140\nSM_PRINT_AUTO_FEED EXTRUDER=0\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=0\nSM_PRINT_EXTRUDER_PREHEAT EXTRUDER=2 TEMP=140\nSM_PRINT_AUTO_FEED EXTRUDER=1\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=1\nSM_PRINT_EXTRUDER_PREHEAT EXTRUDER=3 TEMP=140\nSM_PRINT_AUTO_FEED EXTRUDER=2\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=2\nSM_PRINT_AUTO_FEED EXTRUDER=3\nSM_PRINT_FLOW_CALIBRATE EXTRUDER=3\nM104 S0 T0 A0\nM104 S0 T1 A0\nM104 S0 T2 A0\nM104 S0 T3 A0\nM104 T{initial_extruder} S{nozzle_temperature[initial_extruder] - 90}\n\n;===== 粗回零 =================\nT{initial_extruder}\nM106 S255\nM106 P2 S0\nMOVE_TO_DISCARD_FILAMENT_POSITION\nM109 T{initial_extruder} S{nozzle_temperature[initial_extruder] - 90}\nROUGHLY_CLEAN_NOZZLE_WITH_DISCARD\nMOVE_TO_XY_IDLE_POSITION_EXTRUDER\nG28 Z I140 J140\n\n;===== 检测钢板 =================\nDETECT_BED_PLATE\n\n;===== 深度清洁喷嘴 =================\nG90\nG0 Z5 F10000\nMOVE_TO_DISCARD_FILAMENT_POSITION\nM109 S{nozzle_temperature[initial_extruder] - 50}\nROUGHLY_CLEAN_NOZZLE\nMOVE_TO_XY_IDLE_POSITION_EXTRUDER\nFINELY_CLEAN_NOZZLE_STAGE_1\nM104 S{nozzle_temperature[initial_extruder] - 90}\nG0 Z5 F10000\nMOVE_TO_DISCARD_FILAMENT_POSITION\nROUGHLY_CLEAN_NOZZLE\nMOVE_TO_XY_IDLE_POSITION_EXTRUDER\nFINELY_CLEAN_NOZZLE_STAGE_2\n\n;===== 精回零 =================\nM106 S255\nM109 S{nozzle_temperature[initial_extruder] - 90}\nM190 S{bed_temperature_initial_layer_single}\nM107 P2\nG90\nG0 Z5 F10000\nWAIT_CHAMBER_TEMP TIMEOUT=180\n{if curr_bed_type==\"High Temp Plate\"} \nG28 Z Z_OFFSET -0.07 \n{else} \nG28 Z \n{endif} \n\n\n;===== 热床调平 =================\n{if curr_bed_type==\"High Temp Plate\"} \n; Always pass `ADAPTIVE_MARGIN=0` because Orca has already handled `adaptive_bed_mesh_margin` internally\n; Make sure to set ADAPTIVE to 0 otherwise Klipper will use it's own adaptive bed mesh logic\nBED_MESH_CALIBRATE mesh_min={adaptive_bed_mesh_min[0]},{adaptive_bed_mesh_min[1]} mesh_max={adaptive_bed_mesh_max[0]},{adaptive_bed_mesh_max[1]} ALGORITHM=[bed_mesh_algo] PROBE_COUNT={bed_mesh_probe_count[0]},{bed_mesh_probe_count[1]} ADAPTIVE=0 ADAPTIVE_MARGIN=0 Z_OFFSET=-0.07\n{else} \n; Always pass `ADAPTIVE_MARGIN=0` because Orca has already handled `adaptive_bed_mesh_margin` internally\n; Make sure to set ADAPTIVE to 0 otherwise Klipper will use it's own adaptive bed mesh logic\nBED_MESH_CALIBRATE mesh_min={adaptive_bed_mesh_min[0]},{adaptive_bed_mesh_min[1]} mesh_max={adaptive_bed_mesh_max[0]},{adaptive_bed_mesh_max[1]} ALGORITHM=[bed_mesh_algo] PROBE_COUNT={bed_mesh_probe_count[0]},{bed_mesh_probe_count[1]} ADAPTIVE=0 ADAPTIVE_MARGIN=0\n{endif} \n\n\n;===== 画起始线 =================\nG90\nG1 Z1.5\nG0 X85 Y1 Z2 F18000\nM109 S{nozzle_temperature_initial_layer[initial_extruder]}\nG1 Z0.2\nM83\nG1 X185 E15 F360\nG1 Z1.5\n\nG90\nM106 S0", + "machine_tool_change_time": "5", "max_layer_height": [ "0.56", "0.56", @@ -26,5 +67,125 @@ "0.8", "0.8" ], - "nozzle_type": "hardened_steel" + "nozzle_type": "hardened_steel", + "printable_area": [ + "0.5x1", + "270.5x1", + "270.5x271", + "0.5x271" + ], + "printable_height": "270.05", + "retract_before_wipe": [ + "0%", + "0%", + "0%", + "0%" + ], + "retract_length_toolchange": [ + "10", + "10", + "10", + "10" + ], + "retract_lift_above": [ + "0", + "0", + "0", + "0" + ], + "retract_lift_below": [ + "269", + "269", + "269", + "269" + ], + "retract_lift_enforce": [ + "All Surfaces", + "All Surfaces", + "All Surfaces", + "All Surfaces" + ], + "retract_restart_extra": [ + "0", + "0", + "0", + "0" + ], + "retract_restart_extra_toolchange": [ + "0", + "0", + "0", + "0" + ], + "retract_when_changing_layer": [ + "1", + "1", + "1", + "1" + ], + "retraction_distances_when_cut": [ + "18", + "18", + "18", + "18" + ], + "retraction_length": [ + "1.5", + "1.5", + "1.5", + "1.5" + ], + "retraction_minimum_travel": [ + "1", + "1", + "1", + "1" + ], + "retraction_speed": [ + "30", + "30", + "30", + "30" + ], + "thumbnails": "48x48/PNG, 300x300/PNG", + "travel_slope": [ + "3", + "3", + "3", + "3" + ], + "wipe": [ + "1", + "1", + "1", + "1" + ], + "wipe_distance": [ + "2", + "2", + "2", + "2" + ], + "z_hop": [ + "0.4", + "0.4", + "0.4", + "0.4" + ], + "z_hop_types": [ + "Auto Lift", + "Auto Lift", + "Auto Lift", + "Auto Lift" + ], + "enable_filament_ramming": "0", + "extruder_clearance_height_to_rod": "27.5", + "extruder_clearance_radius": "72.5", + "machine_load_filament_time": "0", + "machine_unload_filament_time": "0", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\nTIMELAPSE_TAKE_FRAME\nDEFECT_DETECTION_DETECT", + "machine_pause_gcode": "M600", + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]\nSET_PRINT_STATS_INFO TOTAL_LAYER={total_layer_count} CURRENT_LAYER={layer_num+1}", + "nozzle_volume": "143", + "default_print_profile": "0.40 Standard @Snapmaker U1 (0.8 nozzle)" } diff --git a/resources/profiles/Snapmaker/machine/fdm_U1.json b/resources/profiles/Snapmaker/machine/fdm_U1.json index 73fe5b74ef..717215b507 100644 --- a/resources/profiles/Snapmaker/machine/fdm_U1.json +++ b/resources/profiles/Snapmaker/machine/fdm_U1.json @@ -176,8 +176,6 @@ "Normal Lift", "Normal Lift" ], - "bed_mesh_max": "267,267", - "bed_mesh_min": "3,3", "purge_in_prime_tower": "0", "machine_pause_gcode": "M601", "change_filament_gcode": "", @@ -185,13 +183,16 @@ "scan_first_layer": "0", "nozzle_type": "undefine", "auxiliary_fan": "0", - "default_bed_type": "Textured PEI Plate", - "printer_agent": "snapmaker", + "support_multi_bed_types": "1", + "default_bed_type": "4", "printable_area": [ "0.5x1", "270.5x1", "270.5x271", "0.5x271" ], - "printable_height": "270.05" + "printable_height": "270.05", + "bed_mesh_min": "3,3", + "bed_mesh_max": "267,267", + "printer_agent": "snapmaker" } diff --git a/resources/profiles/Snapmaker/process/0.06 High Quality @Snapmaker U1 (0.2 nozzle).json b/resources/profiles/Snapmaker/process/0.06 High Quality @Snapmaker U1 (0.2 nozzle).json index 996b127b77..3dec06228e 100644 --- a/resources/profiles/Snapmaker/process/0.06 High Quality @Snapmaker U1 (0.2 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.06 High Quality @Snapmaker U1 (0.2 nozzle).json @@ -1,43 +1,31 @@ { - "type": "process", - "name": "0.06 High Quality @Snapmaker U1 (0.2 nozzle)", - "inherits": "fdm_process_U1_0.2_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.06", - "initial_layer_print_height": "0.1", - "wall_loops": "4", - "bottom_shell_layers": "5", - "top_shell_layers": "7", - "bridge_flow": "1", - "initial_layer_speed": "40", - "initial_layer_infill_speed": "70", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "support_top_z_distance": "0.06", - "support_bottom_z_distance": "0.06", - "setting_id": "3SCofR6VrVyo3vJp", - "description": "Compared with the default profile of a 0.2 mm nozzle, it has a smaller layer lines, lower speeds and acceleration, and the sparse infill pattern is Gyroid. So, it results in minimal layer lines and much higher printing quality, but much longer printing time.", - "default_acceleration": "4000", - "elefant_foot_compensation": "0.15", - "outer_wall_acceleration": "2000", - "outer_wall_speed": "60", - "sparse_infill_pattern": "gyroid", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.2 nozzle)" - ], - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "prime_tower_brim_width": "5", - "prime_tower_width": "30", - "prime_volume": "13.5", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_type": "tree(auto)", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib" + "type": "process", + "name": "0.06 High Quality @Snapmaker U1 (0.2 nozzle)", + "inherits": "fdm_process_U1_0.06_nozzle_0.2", + "from": "system", + "setting_id": "3SCofR6VrVyo3vJp", + "instantiation": "true", + "description": "Compared with the default profile of a 0.2 mm nozzle, it has a smaller layer lines, lower speeds and acceleration, and the sparse infill pattern is Gyroid. So, it results in minimal layer lines and much higher printing quality, but much longer printing time.", + "default_acceleration": "4000", + "elefant_foot_compensation": "0.15", + "outer_wall_acceleration": "2000", + "outer_wall_speed": "60", + "sparse_infill_pattern": "gyroid", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.2 nozzle)" + ], + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "13.5", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib" } diff --git a/resources/profiles/Snapmaker/process/0.06 Standard @Snapmaker U1 (0.2 nozzle).json b/resources/profiles/Snapmaker/process/0.06 Standard @Snapmaker U1 (0.2 nozzle).json index 85e50ec87f..7c80e048f6 100644 --- a/resources/profiles/Snapmaker/process/0.06 Standard @Snapmaker U1 (0.2 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.06 Standard @Snapmaker U1 (0.2 nozzle).json @@ -1,39 +1,27 @@ { - "type": "process", - "name": "0.06 Standard @Snapmaker U1 (0.2 nozzle)", - "inherits": "fdm_process_U1_0.2_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.06", - "initial_layer_print_height": "0.1", - "wall_loops": "4", - "bottom_shell_layers": "5", - "top_shell_layers": "7", - "bridge_flow": "1", - "initial_layer_speed": "40", - "initial_layer_infill_speed": "70", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "support_top_z_distance": "0.06", - "support_bottom_z_distance": "0.06", - "setting_id": "997RaiNHd2YhpaRB", - "description": "Compared with the default profile of 0.2 mm nozzle, it has a smaller layer height, and results in minimal layer lines and higher printing quality, but shorter printing time.", - "elefant_foot_compensation": "0.15", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.2 nozzle)" - ], - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "prime_tower_brim_width": "5", - "prime_tower_width": "30", - "prime_volume": "13.5", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_type": "tree(auto)", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib" + "type": "process", + "name": "0.06 Standard @Snapmaker U1 (0.2 nozzle)", + "inherits": "fdm_process_U1_0.06_nozzle_0.2", + "from": "system", + "setting_id": "997RaiNHd2YhpaRB", + "instantiation": "true", + "description": "Compared with the default profile of 0.2 mm nozzle, it has a smaller layer height, and results in minimal layer lines and higher printing quality, but shorter printing time.", + "elefant_foot_compensation": "0.15", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.2 nozzle)" + ], + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "13.5", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib" } diff --git a/resources/profiles/Snapmaker/process/0.08 Extra Fine @Snapmaker U1 (0.4 nozzle).json b/resources/profiles/Snapmaker/process/0.08 Extra Fine @Snapmaker U1 (0.4 nozzle).json index aeffe99f2a..b8a8e126aa 100644 --- a/resources/profiles/Snapmaker/process/0.08 Extra Fine @Snapmaker U1 (0.4 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.08 Extra Fine @Snapmaker U1 (0.4 nozzle).json @@ -12,6 +12,19 @@ "Snapmaker U1 (0.4 nozzle)" ], "ooze_prevention": "1", + "prime_tower_width": "30", + "prime_volume": "18", "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150" + "standby_temperature_delta": "-150", + "wipe_tower_filament": "0", + "prime_tower_brim_width": "5", + "wipe_tower_cone_angle": "15", + "wipe_tower_extra_spacing": "120%", + "enable_arc_fitting": "0", + "outer_wall_speed": "100", + "precise_outer_wall": "1", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_wall_type": "rib", + "gap_fill_target": "topbottom" } diff --git a/resources/profiles/Snapmaker/process/0.08 High Quality @Snapmaker U1 (0.2 nozzle).json b/resources/profiles/Snapmaker/process/0.08 High Quality @Snapmaker U1 (0.2 nozzle).json index fe0fc0e87d..27d3903f06 100644 --- a/resources/profiles/Snapmaker/process/0.08 High Quality @Snapmaker U1 (0.2 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.08 High Quality @Snapmaker U1 (0.2 nozzle).json @@ -1,43 +1,31 @@ { - "type": "process", - "name": "0.08 High Quality @Snapmaker U1 (0.2 nozzle)", - "inherits": "fdm_process_U1_0.2_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.08", - "initial_layer_print_height": "0.1", - "wall_loops": "4", - "bottom_shell_layers": "5", - "top_shell_layers": "7", - "bridge_flow": "1", - "initial_layer_speed": "40", - "initial_layer_infill_speed": "70", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "support_top_z_distance": "0.08", - "support_bottom_z_distance": "0.08", - "setting_id": "6ExpMU3Wq4J1R7wy", - "description": "Compared with the default profile of a 0.2 mm nozzle, it has a smaller layer lines, lower speeds and acceleration, and the sparse infill pattern is Gyroid. So, it results in almost invisible layer lines and much higher printing quality, but much longer printing time.", - "default_acceleration": "4000", - "elefant_foot_compensation": "0.15", - "outer_wall_acceleration": "2000", - "outer_wall_speed": "60", - "sparse_infill_pattern": "gyroid", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.2 nozzle)" - ], - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "prime_tower_brim_width": "5", - "prime_tower_width": "30", - "prime_volume": "18", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_type": "tree(auto)", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib" + "type": "process", + "name": "0.08 High Quality @Snapmaker U1 (0.2 nozzle)", + "inherits": "fdm_process_U1_0.08_nozzle_0.2", + "from": "system", + "setting_id": "6ExpMU3Wq4J1R7wy", + "instantiation": "true", + "description": "Compared with the default profile of a 0.2 mm nozzle, it has a smaller layer lines, lower speeds and acceleration, and the sparse infill pattern is Gyroid. So, it results in almost invisible layer lines and much higher printing quality, but much longer printing time.", + "default_acceleration": "4000", + "elefant_foot_compensation": "0.15", + "outer_wall_acceleration": "2000", + "outer_wall_speed": "60", + "sparse_infill_pattern": "gyroid", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.2 nozzle)" + ], + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "18", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib" } diff --git a/resources/profiles/Snapmaker/process/0.08 High Quality @Snapmaker U1 (0.4 nozzle).json b/resources/profiles/Snapmaker/process/0.08 High Quality @Snapmaker U1 (0.4 nozzle).json index b86156d841..677e6742d9 100644 --- a/resources/profiles/Snapmaker/process/0.08 High Quality @Snapmaker U1 (0.4 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.08 High Quality @Snapmaker U1 (0.4 nozzle).json @@ -21,6 +21,18 @@ "Snapmaker U1 (0.4 nozzle)" ], "ooze_prevention": "1", + "prime_tower_width": "30", + "prime_volume": "18", "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150" + "standby_temperature_delta": "-150", + "wipe_tower_filament": "0", + "prime_tower_brim_width": "5", + "wipe_tower_cone_angle": "15", + "wipe_tower_extra_spacing": "120%", + "enable_arc_fitting": "0", + "precise_outer_wall": "1", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_wall_type": "rib", + "gap_fill_target": "topbottom" } diff --git a/resources/profiles/Snapmaker/process/0.08 Standard @Snapmaker U1 (0.2 nozzle).json b/resources/profiles/Snapmaker/process/0.08 Standard @Snapmaker U1 (0.2 nozzle).json index 472176ff40..b4728bd60f 100644 --- a/resources/profiles/Snapmaker/process/0.08 Standard @Snapmaker U1 (0.2 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.08 Standard @Snapmaker U1 (0.2 nozzle).json @@ -1,39 +1,27 @@ { - "type": "process", - "name": "0.08 Standard @Snapmaker U1 (0.2 nozzle)", - "inherits": "fdm_process_U1_0.2_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.08", - "initial_layer_print_height": "0.1", - "wall_loops": "4", - "bottom_shell_layers": "5", - "top_shell_layers": "7", - "bridge_flow": "1", - "initial_layer_speed": "40", - "initial_layer_infill_speed": "70", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "support_top_z_distance": "0.08", - "support_bottom_z_distance": "0.08", - "setting_id": "loFrCYH9ux2L5JpZ", - "description": "Compared with the default profile of a 0.2 mm nozzle, it has a smaller layer height, and results in almost invisible layer lines and higher printing quality, but shorter printing time.", - "elefant_foot_compensation": "0.15", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.2 nozzle)" - ], - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "prime_tower_brim_width": "5", - "prime_tower_width": "30", - "prime_volume": "18", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_type": "tree(auto)", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib" + "type": "process", + "name": "0.08 Standard @Snapmaker U1 (0.2 nozzle)", + "inherits": "fdm_process_U1_0.08_nozzle_0.2", + "from": "system", + "setting_id": "loFrCYH9ux2L5JpZ", + "instantiation": "true", + "description": "Compared with the default profile of a 0.2 mm nozzle, it has a smaller layer height, and results in almost invisible layer lines and higher printing quality, but shorter printing time.", + "elefant_foot_compensation": "0.15", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.2 nozzle)" + ], + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "18", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib" } diff --git a/resources/profiles/Snapmaker/process/0.10 High Quality @Snapmaker U1 (0.2 nozzle).json b/resources/profiles/Snapmaker/process/0.10 High Quality @Snapmaker U1 (0.2 nozzle).json index 0f15ce7c5f..80b2120807 100644 --- a/resources/profiles/Snapmaker/process/0.10 High Quality @Snapmaker U1 (0.2 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.10 High Quality @Snapmaker U1 (0.2 nozzle).json @@ -1,43 +1,31 @@ { - "type": "process", - "name": "0.10 High Quality @Snapmaker U1 (0.2 nozzle)", - "inherits": "fdm_process_U1_0.2_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.1", - "initial_layer_print_height": "0.1", - "wall_loops": "4", - "bottom_shell_layers": "5", - "top_shell_layers": "7", - "bridge_flow": "1", - "initial_layer_speed": "40", - "initial_layer_infill_speed": "70", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "support_top_z_distance": "0.1", - "support_bottom_z_distance": "0.1", - "setting_id": "BfLpmnJnSBYBFInR", - "description": "Compared with the default profile of a 0.2 mm nozzle, it has lower speeds and acceleration, and the sparse infill pattern is Gyroid. So, it results in much higher printing quality, but a much longer printing time.", - "default_acceleration": "4000", - "elefant_foot_compensation": "0.15", - "outer_wall_acceleration": "2000", - "outer_wall_speed": "60", - "sparse_infill_pattern": "gyroid", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.2 nozzle)" - ], - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "prime_tower_brim_width": "5", - "prime_tower_width": "28", - "prime_volume": "25", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_type": "tree(auto)", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib" + "type": "process", + "name": "0.10 High Quality @Snapmaker U1 (0.2 nozzle)", + "inherits": "fdm_process_U1_0.10_nozzle_0.2", + "from": "system", + "setting_id": "BfLpmnJnSBYBFInR", + "instantiation": "true", + "description": "Compared with the default profile of a 0.2 mm nozzle, it has lower speeds and acceleration, and the sparse infill pattern is Gyroid. So, it results in much higher printing quality, but a much longer printing time.", + "default_acceleration": "4000", + "elefant_foot_compensation": "0.15", + "outer_wall_acceleration": "2000", + "outer_wall_speed": "60", + "sparse_infill_pattern": "gyroid", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.2 nozzle)" + ], + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "prime_tower_brim_width": "5", + "prime_tower_width": "28", + "prime_volume": "25", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib" } diff --git a/resources/profiles/Snapmaker/process/0.10 Standard @Snapmaker U1 (0.2 nozzle).json b/resources/profiles/Snapmaker/process/0.10 Standard @Snapmaker U1 (0.2 nozzle).json index 460bf8b6fd..80739205ac 100644 --- a/resources/profiles/Snapmaker/process/0.10 Standard @Snapmaker U1 (0.2 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.10 Standard @Snapmaker U1 (0.2 nozzle).json @@ -1,41 +1,29 @@ { - "type": "process", - "name": "0.10 Standard @Snapmaker U1 (0.2 nozzle)", - "inherits": "fdm_process_U1_0.2_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.1", - "initial_layer_print_height": "0.1", - "wall_loops": "4", - "bottom_shell_layers": "5", - "top_shell_layers": "7", - "bridge_flow": "1", - "initial_layer_speed": "40", - "initial_layer_infill_speed": "70", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "support_top_z_distance": "0.1", - "support_bottom_z_distance": "0.1", - "setting_id": "SOq962UWv1ml1Mk0", - "description": "It has a small layer height, and results in almost negligible layer lines and high printing quality. It is suitable for most general printing cases.", - "elefant_foot_compensation": "0.15", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.2 nozzle)" - ], - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "preheat_time": "31", - "prime_tower_brim_width": "6", - "prime_tower_width": "28", - "prime_volume": "25", - "standby_temperature_delta": "-150", - "support_threshold_angle": "35", - "support_type": "tree(auto)", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib", - "slowdown_for_curled_perimeters": "0" + "type": "process", + "name": "0.10 Standard @Snapmaker U1 (0.2 nozzle)", + "inherits": "fdm_process_U1_0.10_nozzle_0.2", + "from": "system", + "setting_id": "SOq962UWv1ml1Mk0", + "instantiation": "true", + "description": "It has a small layer height, and results in almost negligible layer lines and high printing quality. It is suitable for most general printing cases.", + "elefant_foot_compensation": "0.15", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.2 nozzle)" + ], + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "preheat_time": "31", + "prime_tower_brim_width": "6", + "prime_tower_width": "28", + "prime_volume": "25", + "standby_temperature_delta": "-150", + "support_threshold_angle": "35", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib", + "slowdown_for_curled_perimeters": "0" } diff --git a/resources/profiles/Snapmaker/process/0.12 Fine @Snapmaker U1 (0.4 nozzle).json b/resources/profiles/Snapmaker/process/0.12 Fine @Snapmaker U1 (0.4 nozzle).json index 42823b3f0b..2da54a6dc3 100644 --- a/resources/profiles/Snapmaker/process/0.12 Fine @Snapmaker U1 (0.4 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.12 Fine @Snapmaker U1 (0.4 nozzle).json @@ -13,5 +13,18 @@ ], "ooze_prevention": "1", "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150" + "standby_temperature_delta": "-150", + "wipe_tower_filament": "0", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "27", + "wipe_tower_cone_angle": "15", + "wipe_tower_extra_spacing": "120%", + "enable_arc_fitting": "0", + "precise_outer_wall": "1", + "support_threshold_angle": "25", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_wall_type": "rib", + "gap_fill_target": "topbottom" } diff --git a/resources/profiles/Snapmaker/process/0.12 High Quality @Snapmaker U1 (0.4 nozzle).json b/resources/profiles/Snapmaker/process/0.12 High Quality @Snapmaker U1 (0.4 nozzle).json index 8564a41b24..9302a40421 100644 --- a/resources/profiles/Snapmaker/process/0.12 High Quality @Snapmaker U1 (0.4 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.12 High Quality @Snapmaker U1 (0.4 nozzle).json @@ -20,5 +20,20 @@ "compatible_printers": [ "Snapmaker U1 (0.4 nozzle)" ], - "slowdown_for_curled_perimeters": "0" + "prime_tower_width": "30", + "prime_volume": "27", + "slowdown_for_curled_perimeters": "0", + "wipe_tower_filament": "0", + "prime_tower_brim_width": "5", + "wipe_tower_cone_angle": "15", + "wipe_tower_extra_spacing": "120%", + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "standby_temperature_delta": "-150", + "support_threshold_angle": "25", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_wall_type": "rib", + "gap_fill_target": "topbottom" } diff --git a/resources/profiles/Snapmaker/process/0.12 Standard @Snapmaker U1 (0.2 nozzle).json b/resources/profiles/Snapmaker/process/0.12 Standard @Snapmaker U1 (0.2 nozzle).json index de68cc0dd0..cc93a97e99 100644 --- a/resources/profiles/Snapmaker/process/0.12 Standard @Snapmaker U1 (0.2 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.12 Standard @Snapmaker U1 (0.2 nozzle).json @@ -1,39 +1,27 @@ { - "type": "process", - "name": "0.12 Standard @Snapmaker U1 (0.2 nozzle)", - "inherits": "fdm_process_U1_0.2_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.12", - "initial_layer_print_height": "0.1", - "wall_loops": "4", - "bottom_shell_layers": "5", - "top_shell_layers": "7", - "bridge_flow": "1", - "initial_layer_speed": "40", - "initial_layer_infill_speed": "70", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "support_top_z_distance": "0.12", - "support_bottom_z_distance": "0.12", - "setting_id": "KHC1zpxpuvaUEzvf", - "description": "Compared with the default profile of a 0.2 mm nozzle, it has a slightly bigger layer height, and results in almost negligible layer lines, and slightly shorter printing time.", - "elefant_foot_compensation": "0.15", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.2 nozzle)" - ], - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "prime_tower_brim_width": "5", - "prime_tower_width": "28", - "prime_volume": "27", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_type": "tree(auto)", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib" + "type": "process", + "name": "0.12 Standard @Snapmaker U1 (0.2 nozzle)", + "inherits": "fdm_process_U1_0.12_nozzle_0.2", + "from": "system", + "setting_id": "KHC1zpxpuvaUEzvf", + "instantiation": "true", + "description": "Compared with the default profile of a 0.2 mm nozzle, it has a slightly bigger layer height, and results in almost negligible layer lines, and slightly shorter printing time.", + "elefant_foot_compensation": "0.15", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.2 nozzle)" + ], + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "prime_tower_brim_width": "5", + "prime_tower_width": "28", + "prime_volume": "27", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib" } diff --git a/resources/profiles/Snapmaker/process/0.14 Standard @Snapmaker U1 (0.2 nozzle).json b/resources/profiles/Snapmaker/process/0.14 Standard @Snapmaker U1 (0.2 nozzle).json index c265d55e67..54513eb14b 100644 --- a/resources/profiles/Snapmaker/process/0.14 Standard @Snapmaker U1 (0.2 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.14 Standard @Snapmaker U1 (0.2 nozzle).json @@ -1,39 +1,27 @@ { - "type": "process", - "name": "0.14 Standard @Snapmaker U1 (0.2 nozzle)", - "inherits": "fdm_process_U1_0.2_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.14", - "initial_layer_print_height": "0.1", - "wall_loops": "4", - "bottom_shell_layers": "5", - "top_shell_layers": "7", - "bridge_flow": "1", - "initial_layer_speed": "40", - "initial_layer_infill_speed": "70", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "support_top_z_distance": "0.14", - "support_bottom_z_distance": "0.14", - "setting_id": "NGJoV0n6T510y9wM", - "description": "Compared with the default profile of a 0.2 mm nozzle, it has a bigger layer height, and results in slightly visible layer lines, but shorter printing time.", - "elefant_foot_compensation": "0.15", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.2 nozzle)" - ], - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "prime_tower_brim_width": "5", - "prime_tower_width": "30", - "prime_volume": "32", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_type": "tree(auto)", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib" + "type": "process", + "name": "0.14 Standard @Snapmaker U1 (0.2 nozzle)", + "inherits": "fdm_process_U1_0.14_nozzle_0.2", + "from": "system", + "setting_id": "NGJoV0n6T510y9wM", + "instantiation": "true", + "description": "Compared with the default profile of a 0.2 mm nozzle, it has a bigger layer height, and results in slightly visible layer lines, but shorter printing time.", + "elefant_foot_compensation": "0.15", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.2 nozzle)" + ], + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "32", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib" } diff --git a/resources/profiles/Snapmaker/process/0.16 High Quality @Snapmaker U1 (0.4 nozzle).json b/resources/profiles/Snapmaker/process/0.16 High Quality @Snapmaker U1 (0.4 nozzle).json index e66f9f3beb..416d85881c 100644 --- a/resources/profiles/Snapmaker/process/0.16 High Quality @Snapmaker U1 (0.4 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.16 High Quality @Snapmaker U1 (0.4 nozzle).json @@ -21,6 +21,19 @@ "Snapmaker U1 (0.4 nozzle)" ], "ooze_prevention": "1", + "prime_tower_width": "30", + "prime_volume": "36", "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150" + "standby_temperature_delta": "-150", + "wipe_tower_filament": "0", + "prime_tower_brim_width": "5", + "wipe_tower_cone_angle": "15", + "wipe_tower_extra_spacing": "120%", + "enable_arc_fitting": "0", + "precise_outer_wall": "1", + "support_threshold_angle": "30", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_wall_type": "rib", + "gap_fill_target": "topbottom" } diff --git a/resources/profiles/Snapmaker/process/0.16 Optimal @Snapmaker U1 (0.4 nozzle).json b/resources/profiles/Snapmaker/process/0.16 Optimal @Snapmaker U1 (0.4 nozzle).json index 2817871fad..6871a3e120 100644 --- a/resources/profiles/Snapmaker/process/0.16 Optimal @Snapmaker U1 (0.4 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.16 Optimal @Snapmaker U1 (0.4 nozzle).json @@ -12,6 +12,18 @@ "Snapmaker U1 (0.4 nozzle)" ], "ooze_prevention": "1", + "prime_tower_width": "30", + "prime_volume": "36", "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150" + "standby_temperature_delta": "-150", + "wipe_tower_filament": "0", + "prime_tower_brim_width": "5", + "wipe_tower_cone_angle": "15", + "wipe_tower_extra_spacing": "120%", + "enable_arc_fitting": "0", + "precise_outer_wall": "1", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_wall_type": "rib", + "gap_fill_target": "topbottom" } diff --git a/resources/profiles/Snapmaker/process/0.18 Standard @Snapmaker U1 (0.6 nozzle).json b/resources/profiles/Snapmaker/process/0.18 Standard @Snapmaker U1 (0.6 nozzle).json index e68cf86d75..77b756bffc 100644 --- a/resources/profiles/Snapmaker/process/0.18 Standard @Snapmaker U1 (0.6 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.18 Standard @Snapmaker U1 (0.6 nozzle).json @@ -1,42 +1,32 @@ { - "type": "process", - "name": "0.18 Standard @Snapmaker U1 (0.6 nozzle)", - "inherits": "fdm_process_U1_0.6_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.25", - "initial_layer_print_height": "0.3", - "bridge_flow": "1", - "initial_layer_speed": "35", - "initial_layer_infill_speed": "55", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "bridge_speed": "30", - "overhang_3_4_speed": "15", - "support_top_z_distance": "0.18", - "support_bottom_z_distance": "0.18", - "setting_id": "XGSrVgnsUFv6uCRs", - "description": "Compared with the default profile of a 0.6 mm nozzle, it has a smaller layer height, and results in less apparent layer lines and higher printing quality, but longer printing time.", - "elefant_foot_compensation": "0.15", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.6 nozzle)" - ], - "filter_out_gap_fill": "1", - "gap_fill_target": "topbottom", - "internal_bridge_speed": "100%", - "prime_tower_brim_width": "5", - "prime_tower_width": "30", - "prime_volume": "41", - "seam_gap": "15%", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib", - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_type": "tree(auto)" + "type": "process", + "name": "0.18 Standard @Snapmaker U1 (0.6 nozzle)", + "inherits": "fdm_process_U1_0.18_nozzle_0.6", + "from": "system", + "setting_id": "XGSrVgnsUFv6uCRs", + "instantiation": "true", + "description": "Compared with the default profile of a 0.6 mm nozzle, it has a smaller layer height, and results in less apparent layer lines and higher printing quality, but longer printing time.", + "elefant_foot_compensation": "0.15", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.6 nozzle)" + ], + "filter_out_gap_fill": "1", + "gap_fill_target": "topbottom", + "internal_bridge_speed": "100%", + "layer_height": "0.25", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "41", + "seam_gap": "15%", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib", + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_type": "tree(auto)" } diff --git a/resources/profiles/Snapmaker/process/0.20 Bambu Support W @Snapmaker U1 (0.4 nozzle).json b/resources/profiles/Snapmaker/process/0.20 Bambu Support W @Snapmaker U1 (0.4 nozzle).json deleted file mode 100644 index 5de608c68d..0000000000 --- a/resources/profiles/Snapmaker/process/0.20 Bambu Support W @Snapmaker U1 (0.4 nozzle).json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "type": "process", - "name": "0.20 Bambu Support W @Snapmaker U1 (0.4 nozzle)", - "inherits": "fdm_process_U1_0.20", - "from": "system", - "setting_id": "8OkVMuElKExBdftG", - "instantiation": "true", - "enable_support": "1", - "support_interface_top_layers": "3", - "support_top_z_distance": "0.2", - "support_interface_loop_pattern": "1", - "support_interface_spacing": "0", - "support_interface_speed": "80", - "support_filament": "0", - "support_interface_filament": "0", - "enable_prime_tower": "1", - "compatible_printers": [ - "Snapmaker U1 (0.4 nozzle)" - ], - "ooze_prevention": "1", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150" -} diff --git a/resources/profiles/Snapmaker/process/0.20 Quality @Snapmaker U1 (0.4 nozzle).json b/resources/profiles/Snapmaker/process/0.20 Quality @Snapmaker U1 (0.4 nozzle).json index ac7fc102bc..da92006d49 100644 --- a/resources/profiles/Snapmaker/process/0.20 Quality @Snapmaker U1 (0.4 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.20 Quality @Snapmaker U1 (0.4 nozzle).json @@ -12,6 +12,7 @@ "Snapmaker U1 (0.4 nozzle)" ], "ooze_prevention": "1", + "prime_tower_width": "30", "slowdown_for_curled_perimeters": "0", "standby_temperature_delta": "-150", "wipe_tower_filament": "0", diff --git a/resources/profiles/Snapmaker/process/0.20 Standard @Snapmaker U1 (0.4 nozzle).json b/resources/profiles/Snapmaker/process/0.20 Standard @Snapmaker U1 (0.4 nozzle).json index 243718507b..5d873d5efd 100644 --- a/resources/profiles/Snapmaker/process/0.20 Standard @Snapmaker U1 (0.4 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.20 Standard @Snapmaker U1 (0.4 nozzle).json @@ -12,6 +12,8 @@ "Snapmaker U1 (0.4 nozzle)" ], "ooze_prevention": "1", + "prime_tower_width": "30", + "prime_volume": "45", "slowdown_for_curled_perimeters": "0", "standby_temperature_delta": "-150", "wipe_tower_filament": "0", diff --git a/resources/profiles/Snapmaker/process/0.20 Standard @Snapmaker U1 (0.4+0.6 nozzle).json b/resources/profiles/Snapmaker/process/0.20 Standard @Snapmaker U1 (0.4+0.6 nozzle).json index 52e1aa9349..63bb6ea170 100644 --- a/resources/profiles/Snapmaker/process/0.20 Standard @Snapmaker U1 (0.4+0.6 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.20 Standard @Snapmaker U1 (0.4+0.6 nozzle).json @@ -20,6 +20,7 @@ "smooth_coefficient": "150", "overhang_totally_speed": "50", "ooze_prevention": "1", + "prime_tower_width": "30", "slowdown_for_curled_perimeters": "0", "standby_temperature_delta": "-150", "wipe_tower_filament": "0", diff --git a/resources/profiles/Snapmaker/process/0.20 Standard @Snapmaker U1 (0.6 nozzle).json b/resources/profiles/Snapmaker/process/0.20 Standard @Snapmaker U1 (0.6 nozzle).json index f5ab699928..d1bb174a62 100644 --- a/resources/profiles/Snapmaker/process/0.20 Standard @Snapmaker U1 (0.6 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.20 Standard @Snapmaker U1 (0.6 nozzle).json @@ -13,6 +13,7 @@ "Snapmaker U1 (0.6 nozzle)" ], "ooze_prevention": "1", + "prime_tower_width": "30", "slowdown_for_curled_perimeters": "0", "standby_temperature_delta": "-150", "wipe_tower_filament": "0", diff --git a/resources/profiles/Snapmaker/process/0.20 Strength @Snapmaker U1 (0.4 nozzle).json b/resources/profiles/Snapmaker/process/0.20 Strength @Snapmaker U1 (0.4 nozzle).json index 4defa45a16..91c5995b92 100644 --- a/resources/profiles/Snapmaker/process/0.20 Strength @Snapmaker U1 (0.4 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.20 Strength @Snapmaker U1 (0.4 nozzle).json @@ -15,6 +15,18 @@ "Snapmaker U1 (0.4 nozzle)" ], "ooze_prevention": "1", + "prime_tower_width": "30", + "prime_volume": "45", "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150" + "standby_temperature_delta": "-150", + "wipe_tower_filament": "0", + "prime_tower_brim_width": "5", + "wipe_tower_cone_angle": "15", + "wipe_tower_extra_spacing": "120%", + "enable_arc_fitting": "0", + "precise_outer_wall": "1", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_wall_type": "rib", + "gap_fill_target": "topbottom" } diff --git a/resources/profiles/Snapmaker/process/0.20 Support @Snapmaker U1 (0.4 nozzle).json b/resources/profiles/Snapmaker/process/0.20 Support @Snapmaker U1 (0.4 nozzle).json index 36a3172b48..0cb85cc26d 100644 --- a/resources/profiles/Snapmaker/process/0.20 Support @Snapmaker U1 (0.4 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.20 Support @Snapmaker U1 (0.4 nozzle).json @@ -12,6 +12,8 @@ "Snapmaker U1 (0.4 nozzle)" ], "ooze_prevention": "1", + "prime_tower_width": "40", + "prime_volume": "15", "slowdown_for_curled_perimeters": "0", "standby_temperature_delta": "-150", "wipe_tower_filament": "0", diff --git a/resources/profiles/Snapmaker/process/0.20 Support W @Snapmaker U1 (0.4 nozzle).json b/resources/profiles/Snapmaker/process/0.20 Support W @Snapmaker U1 (0.4 nozzle).json index 37ba596b63..3d1887bea9 100644 --- a/resources/profiles/Snapmaker/process/0.20 Support W @Snapmaker U1 (0.4 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.20 Support W @Snapmaker U1 (0.4 nozzle).json @@ -18,6 +18,8 @@ "Snapmaker U1 (0.4 nozzle)" ], "ooze_prevention": "1", + "prime_tower_width": "50", + "prime_volume": "38", "slowdown_for_curled_perimeters": "0", "standby_temperature_delta": "-150" } diff --git a/resources/profiles/Snapmaker/process/0.24 Draft @Snapmaker U1 (0.4 nozzle).json b/resources/profiles/Snapmaker/process/0.24 Draft @Snapmaker U1 (0.4 nozzle).json index a4c10a8ad1..f98007b6e1 100644 --- a/resources/profiles/Snapmaker/process/0.24 Draft @Snapmaker U1 (0.4 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.24 Draft @Snapmaker U1 (0.4 nozzle).json @@ -12,6 +12,18 @@ "Snapmaker U1 (0.4 nozzle)" ], "ooze_prevention": "1", + "prime_tower_width": "30", + "prime_volume": "54", "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150" + "standby_temperature_delta": "-150", + "wipe_tower_filament": "0", + "prime_tower_brim_width": "5", + "wipe_tower_cone_angle": "15", + "wipe_tower_extra_spacing": "120%", + "enable_arc_fitting": "0", + "precise_outer_wall": "1", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_wall_type": "rib", + "gap_fill_target": "topbottom" } diff --git a/resources/profiles/Snapmaker/process/0.24 Standard @Snapmaker U1 (0.6 nozzle).json b/resources/profiles/Snapmaker/process/0.24 Standard @Snapmaker U1 (0.6 nozzle).json index b8a8427baf..7a9f4e2154 100644 --- a/resources/profiles/Snapmaker/process/0.24 Standard @Snapmaker U1 (0.6 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.24 Standard @Snapmaker U1 (0.6 nozzle).json @@ -1,41 +1,32 @@ { - "type": "process", - "name": "0.24 Standard @Snapmaker U1 (0.6 nozzle)", - "inherits": "fdm_process_U1_0.6_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.24", - "initial_layer_print_height": "0.3", - "bridge_flow": "1", - "initial_layer_speed": "35", - "initial_layer_infill_speed": "55", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "bridge_speed": "30", - "overhang_3_4_speed": "15", - "setting_id": "BziJYuA5U5gWm6FM", - "description": "Compared with the default profile of a 0.6 mm nozzle, it has a smaller layer height, and results in less apparent layer lines and slight higher printing quality, but longer printing time.", - "elefant_foot_compensation": "0.15", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.6 nozzle)" - ], - "filter_out_gap_fill": "1", - "gap_fill_target": "topbottom", - "internal_bridge_speed": "100%", - "prime_tower_brim_width": "5", - "prime_tower_width": "30", - "prime_volume": "55", - "seam_gap": "15%", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib", - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_threshold_angle": "35", - "support_type": "tree(auto)" + "type": "process", + "name": "0.24 Standard @Snapmaker U1 (0.6 nozzle)", + "inherits": "fdm_process_U1_0.24_nozzle_0.6", + "from": "system", + "setting_id": "BziJYuA5U5gWm6FM", + "instantiation": "true", + "description": "Compared with the default profile of a 0.6 mm nozzle, it has a smaller layer height, and results in less apparent layer lines and slight higher printing quality, but longer printing time.", + "elefant_foot_compensation": "0.15", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.6 nozzle)" + ], + "filter_out_gap_fill": "1", + "gap_fill_target": "topbottom", + "internal_bridge_speed": "100%", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "55", + "seam_gap": "15%", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib", + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_threshold_angle": "35", + "support_type": "tree(auto)" } diff --git a/resources/profiles/Snapmaker/process/0.24 Standard @Snapmaker U1 (0.8 nozzle).json b/resources/profiles/Snapmaker/process/0.24 Standard @Snapmaker U1 (0.8 nozzle).json index 1b13e745d2..d9e1a2bf94 100644 --- a/resources/profiles/Snapmaker/process/0.24 Standard @Snapmaker U1 (0.8 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.24 Standard @Snapmaker U1 (0.8 nozzle).json @@ -1,43 +1,32 @@ { - "type": "process", - "name": "0.24 Standard @Snapmaker U1 (0.8 nozzle)", - "inherits": "fdm_process_U1_0.8_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.24", - "initial_layer_print_height": "0.4", - "bridge_flow": "1", - "top_surface_pattern": "monotonic", - "initial_layer_speed": "35", - "initial_layer_infill_speed": "55", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "bridge_speed": "30", - "overhang_3_4_speed": "25", - "overhang_4_4_speed": "5", - "setting_id": "QcJ5p9h0eYUb91ak", - "description": "Compared with the default profile of a 0.6 mm nozzle, it has a smaller layer height, and results in less apparent layer lines and slight higher printing quality, but longer printing time.", - "elefant_foot_compensation": "0.15", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.8 nozzle)" - ], - "filter_out_gap_fill": "1", - "gap_fill_target": "topbottom", - "internal_bridge_speed": "100%", - "min_width_top_surface": "90", - "prime_tower_brim_width": "5", - "prime_tower_width": "30", - "prime_volume": "54", - "seam_gap": "15%", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib", - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_type": "tree(auto)" + "type": "process", + "name": "0.24 Standard @Snapmaker U1 (0.8 nozzle)", + "inherits": "fdm_process_U1_0.24_nozzle_0.8", + "from": "system", + "setting_id": "QcJ5p9h0eYUb91ak", + "instantiation": "true", + "description": "Compared with the default profile of a 0.6 mm nozzle, it has a smaller layer height, and results in less apparent layer lines and slight higher printing quality, but longer printing time.", + "elefant_foot_compensation": "0.15", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.8 nozzle)" + ], + "filter_out_gap_fill": "1", + "gap_fill_target": "topbottom", + "internal_bridge_speed": "100%", + "min_width_top_surface": "90", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "54", + "seam_gap": "15%", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib", + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_type": "tree(auto)" } diff --git a/resources/profiles/Snapmaker/process/0.28 Extra Draft @Snapmaker U1 (0.4 nozzle).json b/resources/profiles/Snapmaker/process/0.28 Extra Draft @Snapmaker U1 (0.4 nozzle).json index 4adf06f100..4382b11e41 100644 --- a/resources/profiles/Snapmaker/process/0.28 Extra Draft @Snapmaker U1 (0.4 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.28 Extra Draft @Snapmaker U1 (0.4 nozzle).json @@ -11,5 +11,19 @@ "compatible_printers": [ "Snapmaker U1 (0.4 nozzle)" ], - "slowdown_for_curled_perimeters": "0" + "prime_tower_width": "30", + "prime_volume": "63", + "slowdown_for_curled_perimeters": "0", + "wipe_tower_filament": "0", + "prime_tower_brim_width": "5", + "wipe_tower_cone_angle": "15", + "wipe_tower_extra_spacing": "120%", + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "standby_temperature_delta": "-150", + "support_type": "tree(auto)", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_wall_type": "rib", + "gap_fill_target": "topbottom" } diff --git a/resources/profiles/Snapmaker/process/0.30 Draft @Snapmaker U1 (0.6 nozzle).json b/resources/profiles/Snapmaker/process/0.30 Draft @Snapmaker U1 (0.6 nozzle).json index 8f8e6a1d15..52eb63a64d 100644 --- a/resources/profiles/Snapmaker/process/0.30 Draft @Snapmaker U1 (0.6 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.30 Draft @Snapmaker U1 (0.6 nozzle).json @@ -13,6 +13,8 @@ "Snapmaker U1 (0.6 nozzle)" ], "ooze_prevention": "1", + "prime_tower_width": "30", + "prime_volume": "68", "slowdown_for_curled_perimeters": "0", "standby_temperature_delta": "-150", "wipe_tower_filament": "0", diff --git a/resources/profiles/Snapmaker/process/0.30 Standard @Snapmaker U1 (0.6 nozzle).json b/resources/profiles/Snapmaker/process/0.30 Standard @Snapmaker U1 (0.6 nozzle).json index 3ed454a7d5..e2d5c192bb 100644 --- a/resources/profiles/Snapmaker/process/0.30 Standard @Snapmaker U1 (0.6 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.30 Standard @Snapmaker U1 (0.6 nozzle).json @@ -1,40 +1,31 @@ { - "type": "process", - "name": "0.30 Standard @Snapmaker U1 (0.6 nozzle)", - "inherits": "fdm_process_U1_0.6_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.3", - "initial_layer_print_height": "0.3", - "bridge_flow": "1", - "initial_layer_speed": "35", - "initial_layer_infill_speed": "55", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "bridge_speed": "30", - "overhang_3_4_speed": "15", - "setting_id": "TWxp6qgz1DJa8Ngo", - "description": "It has a big layer height, and results in apparent layer lines and ordinary printing quality and printing time.", - "elefant_foot_compensation": "0.15", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.6 nozzle)" - ], - "filter_out_gap_fill": "1", - "gap_fill_target": "topbottom", - "internal_bridge_speed": "100%", - "prime_tower_brim_width": "5", - "prime_tower_width": "30", - "prime_volume": "68", - "seam_gap": "15%", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_threshold_angle": "35", - "support_type": "tree(auto)" + "type": "process", + "name": "0.30 Standard @Snapmaker U1 (0.6 nozzle)", + "inherits": "fdm_process_U1_0.30_nozzle_0.6", + "from": "system", + "setting_id": "TWxp6qgz1DJa8Ngo", + "instantiation": "true", + "description": "It has a big layer height, and results in apparent layer lines and ordinary printing quality and printing time.", + "elefant_foot_compensation": "0.15", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.6 nozzle)" + ], + "filter_out_gap_fill": "1", + "gap_fill_target": "topbottom", + "internal_bridge_speed": "100%", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "68", + "seam_gap": "15%", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_threshold_angle": "35", + "support_type": "tree(auto)" } diff --git a/resources/profiles/Snapmaker/process/0.30 Strength @Snapmaker U1 (0.6 nozzle).json b/resources/profiles/Snapmaker/process/0.30 Strength @Snapmaker U1 (0.6 nozzle).json index ce6563d960..c216eb09d2 100644 --- a/resources/profiles/Snapmaker/process/0.30 Strength @Snapmaker U1 (0.6 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.30 Strength @Snapmaker U1 (0.6 nozzle).json @@ -1,42 +1,33 @@ { - "type": "process", - "name": "0.30 Strength @Snapmaker U1 (0.6 nozzle)", - "inherits": "fdm_process_U1_0.6_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.3", - "initial_layer_print_height": "0.3", - "bridge_flow": "1", - "initial_layer_speed": "35", - "initial_layer_infill_speed": "55", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "bridge_speed": "30", - "overhang_3_4_speed": "15", - "setting_id": "CBaL0vgwtgsd6Snj", - "description": "Compared with the default profile of a 0.6 mm nozzle, it has more wall loops and a higher sparse infill density. So, it results in higher strength of the prints, but more filament consumption and longer printing time.", - "elefant_foot_compensation": "0.15", - "sparse_infill_density": "25%", - "wall_loops": "4", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.6 nozzle)" - ], - "filter_out_gap_fill": "1", - "gap_fill_target": "topbottom", - "internal_bridge_speed": "100%", - "prime_tower_width": "30", - "prime_volume": "68", - "seam_gap": "15%", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_wall_type": "rib", - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "prime_tower_brim_width": "5", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_type": "tree(auto)", - "wipe_tower_extra_spacing": "120%" + "type": "process", + "name": "0.30 Strength @Snapmaker U1 (0.6 nozzle)", + "inherits": "fdm_process_U1_0.30_nozzle_0.6", + "from": "system", + "setting_id": "CBaL0vgwtgsd6Snj", + "instantiation": "true", + "description": "Compared with the default profile of a 0.6 mm nozzle, it has more wall loops and a higher sparse infill density. So, it results in higher strength of the prints, but more filament consumption and longer printing time.", + "elefant_foot_compensation": "0.15", + "sparse_infill_density": "25%", + "wall_loops": "4", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.6 nozzle)" + ], + "filter_out_gap_fill": "1", + "gap_fill_target": "topbottom", + "internal_bridge_speed": "100%", + "prime_tower_width": "30", + "prime_volume": "68", + "seam_gap": "15%", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_wall_type": "rib", + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "prime_tower_brim_width": "5", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_type": "tree(auto)", + "wipe_tower_extra_spacing": "120%" } diff --git a/resources/profiles/Snapmaker/process/0.32 Standard @Snapmaker U1 (0.8 nozzle).json b/resources/profiles/Snapmaker/process/0.32 Standard @Snapmaker U1 (0.8 nozzle).json index 47ac276acc..d2c20559fd 100644 --- a/resources/profiles/Snapmaker/process/0.32 Standard @Snapmaker U1 (0.8 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.32 Standard @Snapmaker U1 (0.8 nozzle).json @@ -1,44 +1,34 @@ { - "type": "process", - "name": "0.32 Standard @Snapmaker U1 (0.8 nozzle)", - "inherits": "fdm_process_U1_0.8_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.32", - "initial_layer_print_height": "0.4", - "bridge_flow": "0.7", - "top_surface_pattern": "monotonic", - "initial_layer_speed": "35", - "initial_layer_infill_speed": "55", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "bridge_speed": "30", - "overhang_3_4_speed": "25", - "overhang_4_4_speed": "5", - "setting_id": "iVRz2B0VBIBL1xVd", - "description": "Compared with the default profile of a 0.8 mm nozzle, it has a slightly smaller layer height, and results in slightly less but still apparent layer lines and slightly higher printing quality, but longer printing time in some printing cases.", - "elefant_foot_compensation": "0.15", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.8 nozzle)" - ], - "filter_out_gap_fill": "1", - "gap_fill_target": "topbottom", - "internal_bridge_speed": "100%", - "prime_tower_brim_width": "5", - "prime_tower_width": "30", - "prime_volume": "72", - "seam_gap": "15%", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib", - "bridge_density": "70%", - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_threshold_angle": "35", - "support_type": "tree(auto)" + "type": "process", + "name": "0.32 Standard @Snapmaker U1 (0.8 nozzle)", + "inherits": "fdm_process_U1_0.32_nozzle_0.8", + "from": "system", + "setting_id": "iVRz2B0VBIBL1xVd", + "instantiation": "true", + "description": "Compared with the default profile of a 0.8 mm nozzle, it has a slightly smaller layer height, and results in slightly less but still apparent layer lines and slightly higher printing quality, but longer printing time in some printing cases.", + "elefant_foot_compensation": "0.15", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.8 nozzle)" + ], + "filter_out_gap_fill": "1", + "gap_fill_target": "topbottom", + "internal_bridge_speed": "100%", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "72", + "seam_gap": "15%", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib", + "bridge_density": "70%", + "bridge_flow": "0.7", + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_threshold_angle": "35", + "support_type": "tree(auto)" } diff --git a/resources/profiles/Snapmaker/process/0.36 Standard @Snapmaker U1 (0.6 nozzle).json b/resources/profiles/Snapmaker/process/0.36 Standard @Snapmaker U1 (0.6 nozzle).json index ddd97a76c3..44ea3bb3f4 100644 --- a/resources/profiles/Snapmaker/process/0.36 Standard @Snapmaker U1 (0.6 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.36 Standard @Snapmaker U1 (0.6 nozzle).json @@ -1,41 +1,32 @@ { - "type": "process", - "name": "0.36 Standard @Snapmaker U1 (0.6 nozzle)", - "inherits": "fdm_process_U1_0.6_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.36", - "initial_layer_print_height": "0.3", - "bridge_flow": "1", - "initial_layer_speed": "35", - "initial_layer_infill_speed": "55", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "bridge_speed": "30", - "overhang_3_4_speed": "15", - "setting_id": "C0PiCFd3P222knX9", - "description": "Compared with the default profile of a 0.6 mm nozzle, it has a bigger layer height, and results in more apparent layer lines and lower printing quality, but shorter printing time in some printing cases.", - "elefant_foot_compensation": "0.15", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.6 nozzle)" - ], - "filter_out_gap_fill": "1", - "gap_fill_target": "topbottom", - "internal_bridge_speed": "100%", - "prime_tower_brim_width": "5", - "prime_tower_width": "30", - "prime_volume": "81", - "seam_gap": "15%", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib", - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_threshold_angle": "35", - "support_type": "tree(auto)" + "type": "process", + "name": "0.36 Standard @Snapmaker U1 (0.6 nozzle)", + "inherits": "fdm_process_U1_0.36_nozzle_0.6", + "from": "system", + "setting_id": "C0PiCFd3P222knX9", + "instantiation": "true", + "description": "Compared with the default profile of a 0.6 mm nozzle, it has a bigger layer height, and results in more apparent layer lines and lower printing quality, but shorter printing time in some printing cases.", + "elefant_foot_compensation": "0.15", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.6 nozzle)" + ], + "filter_out_gap_fill": "1", + "gap_fill_target": "topbottom", + "internal_bridge_speed": "100%", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "81", + "seam_gap": "15%", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib", + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_threshold_angle": "35", + "support_type": "tree(auto)" } diff --git a/resources/profiles/Snapmaker/process/0.40 Extra Draft @Snapmaker U1 (0.6 nozzle).json b/resources/profiles/Snapmaker/process/0.40 Extra Draft @Snapmaker U1 (0.6 nozzle).json index 265c91eb35..37238fb0ea 100644 --- a/resources/profiles/Snapmaker/process/0.40 Extra Draft @Snapmaker U1 (0.6 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.40 Extra Draft @Snapmaker U1 (0.6 nozzle).json @@ -13,6 +13,8 @@ "Snapmaker U1 (0.6 nozzle)" ], "ooze_prevention": "1", + "prime_tower_width": "30", + "prime_volume": "90", "slowdown_for_curled_perimeters": "0", "standby_temperature_delta": "-150", "wipe_tower_filament": "0", diff --git a/resources/profiles/Snapmaker/process/0.40 Standard @Snapmaker U1 (0.8 nozzle).json b/resources/profiles/Snapmaker/process/0.40 Standard @Snapmaker U1 (0.8 nozzle).json index 24edfabf6d..8d00eb9fab 100644 --- a/resources/profiles/Snapmaker/process/0.40 Standard @Snapmaker U1 (0.8 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.40 Standard @Snapmaker U1 (0.8 nozzle).json @@ -1,45 +1,35 @@ { - "type": "process", - "name": "0.40 Standard @Snapmaker U1 (0.8 nozzle)", - "inherits": "fdm_process_U1_0.8_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.4", - "initial_layer_print_height": "0.4", - "bridge_flow": "0.8", - "top_surface_pattern": "monotonic", - "initial_layer_speed": "35", - "initial_layer_infill_speed": "55", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "bridge_speed": "30", - "overhang_3_4_speed": "25", - "overhang_4_4_speed": "5", - "setting_id": "VqkPgUtZi159BKpJ", - "description": "It has a very big layer height, and results in very apparent layer lines, low printing quality and general printing time.", - "elefant_foot_compensation": "0.15", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.8 nozzle)" - ], - "filter_out_gap_fill": "1", - "gap_fill_target": "topbottom", - "internal_bridge_speed": "100%", - "prime_tower_brim_width": "5", - "prime_tower_width": "30", - "prime_volume": "90", - "seam_gap": "15%", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib", - "bridge_density": "60%", - "enable_arc_fitting": "0", - "min_width_top_surface": "200%", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_threshold_angle": "40", - "support_type": "tree(auto)" + "type": "process", + "name": "0.40 Standard @Snapmaker U1 (0.8 nozzle)", + "inherits": "fdm_process_U1_0.40_nozzle_0.8", + "from": "system", + "setting_id": "VqkPgUtZi159BKpJ", + "instantiation": "true", + "description": "It has a very big layer height, and results in very apparent layer lines, low printing quality and general printing time.", + "elefant_foot_compensation": "0.15", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.8 nozzle)" + ], + "filter_out_gap_fill": "1", + "gap_fill_target": "topbottom", + "internal_bridge_speed": "100%", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "90", + "seam_gap": "15%", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib", + "bridge_density": "60%", + "bridge_flow": "0.8", + "enable_arc_fitting": "0", + "min_width_top_surface": "200%", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_threshold_angle": "40", + "support_type": "tree(auto)" } diff --git a/resources/profiles/Snapmaker/process/0.42 Standard @Snapmaker U1 (0.6 nozzle).json b/resources/profiles/Snapmaker/process/0.42 Standard @Snapmaker U1 (0.6 nozzle).json index d65ba8e688..d3e4bf7f07 100644 --- a/resources/profiles/Snapmaker/process/0.42 Standard @Snapmaker U1 (0.6 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.42 Standard @Snapmaker U1 (0.6 nozzle).json @@ -1,41 +1,32 @@ { - "type": "process", - "name": "0.42 Standard @Snapmaker U1 (0.6 nozzle)", - "inherits": "fdm_process_U1_0.6_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.42", - "initial_layer_print_height": "0.3", - "bridge_flow": "1", - "initial_layer_speed": "35", - "initial_layer_infill_speed": "55", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "bridge_speed": "30", - "overhang_3_4_speed": "15", - "setting_id": "SVJzhQA3KQetRZmo", - "description": "Compared with the default profile of a 0.6 mm nozzle, it has a bigger layer height, and results in much more apparent layer lines and much lower printing quality, but shorter printing time in some printing cases.", - "elefant_foot_compensation": "0.15", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.6 nozzle)" - ], - "filter_out_gap_fill": "1", - "gap_fill_target": "topbottom", - "internal_bridge_speed": "100%", - "precise_z_height": "0", - "prime_tower_brim_width": "5", - "prime_tower_width": "30", - "prime_volume": "95", - "seam_gap": "15%", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib", - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_threshold_angle": "35", - "support_type": "tree(auto)" + "type": "process", + "name": "0.42 Standard @Snapmaker U1 (0.6 nozzle)", + "inherits": "fdm_process_U1_0.42_nozzle_0.6", + "from": "system", + "setting_id": "SVJzhQA3KQetRZmo", + "instantiation": "true", + "description": "Compared with the default profile of a 0.6 mm nozzle, it has a bigger layer height, and results in much more apparent layer lines and much lower printing quality, but shorter printing time in some printing cases.", + "elefant_foot_compensation": "0.15", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.6 nozzle)" + ], + "filter_out_gap_fill": "1", + "gap_fill_target": "topbottom", + "internal_bridge_speed": "100%", + "precise_z_height": "0", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "95", + "seam_gap": "15%", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib", + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_threshold_angle": "35", + "support_type": "tree(auto)" } diff --git a/resources/profiles/Snapmaker/process/0.48 Standard @Snapmaker U1 (0.8 nozzle).json b/resources/profiles/Snapmaker/process/0.48 Standard @Snapmaker U1 (0.8 nozzle).json index 08e054619e..d6cdf607dd 100644 --- a/resources/profiles/Snapmaker/process/0.48 Standard @Snapmaker U1 (0.8 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.48 Standard @Snapmaker U1 (0.8 nozzle).json @@ -1,43 +1,32 @@ { - "type": "process", - "name": "0.48 Standard @Snapmaker U1 (0.8 nozzle)", - "inherits": "fdm_process_U1_0.8_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.48", - "initial_layer_print_height": "0.4", - "bridge_flow": "1", - "top_surface_pattern": "monotonic", - "initial_layer_speed": "35", - "initial_layer_infill_speed": "55", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "bridge_speed": "30", - "overhang_3_4_speed": "25", - "overhang_4_4_speed": "5", - "setting_id": "5H6JWChFEo3zqoHQ", - "description": "Compared with the default profile of a 0.8 mm nozzle, it has a bigger layer height, and results in very apparent layer lines and much lower printing quality, but shorter printing time in some printing cases.", - "elefant_foot_compensation": "0.15", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.8 nozzle)" - ], - "filter_out_gap_fill": "1", - "gap_fill_target": "topbottom", - "internal_bridge_speed": "100%", - "prime_tower_brim_width": "5", - "prime_tower_width": "30", - "prime_volume": "108", - "seam_gap": "15%", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib", - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_threshold_angle": "35", - "support_type": "tree(auto)" + "type": "process", + "name": "0.48 Standard @Snapmaker U1 (0.8 nozzle)", + "inherits": "fdm_process_U1_0.48_nozzle_0.8", + "from": "system", + "setting_id": "5H6JWChFEo3zqoHQ", + "instantiation": "true", + "description": "Compared with the default profile of a 0.8 mm nozzle, it has a bigger layer height, and results in very apparent layer lines and much lower printing quality, but shorter printing time in some printing cases.", + "elefant_foot_compensation": "0.15", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.8 nozzle)" + ], + "filter_out_gap_fill": "1", + "gap_fill_target": "topbottom", + "internal_bridge_speed": "100%", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "108", + "seam_gap": "15%", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib", + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_threshold_angle": "35", + "support_type": "tree(auto)" } diff --git a/resources/profiles/Snapmaker/process/0.56 Standard @Snapmaker U1 (0.8 nozzle).json b/resources/profiles/Snapmaker/process/0.56 Standard @Snapmaker U1 (0.8 nozzle).json index 86b571d1f5..9f67114c20 100644 --- a/resources/profiles/Snapmaker/process/0.56 Standard @Snapmaker U1 (0.8 nozzle).json +++ b/resources/profiles/Snapmaker/process/0.56 Standard @Snapmaker U1 (0.8 nozzle).json @@ -1,41 +1,31 @@ { - "type": "process", - "name": "0.56 Standard @Snapmaker U1 (0.8 nozzle)", - "inherits": "fdm_process_U1_0.8_common", - "from": "system", - "instantiation": "true", - "layer_height": "0.56", - "initial_layer_print_height": "0.4", - "bridge_flow": "1", - "top_surface_pattern": "monotonic", - "initial_layer_speed": "35", - "initial_layer_infill_speed": "55", - "sparse_infill_speed": "100", - "top_surface_speed": "150", - "bridge_speed": "30", - "overhang_3_4_speed": "25", - "overhang_4_4_speed": "5", - "setting_id": "JZEIXOUT33c7MrZj", - "description": "Compared with the default profile of a 0.8 mm nozzle, it has a much bigger layer height, and results in extremely apparent layer lines and much lower printing quality, but much shorter printing time in some printing cases.", - "elefant_foot_compensation": "0.15", - "smooth_coefficient": "150", - "overhang_totally_speed": "50", - "compatible_printers": [ - "Snapmaker U1 (0.8 nozzle)" - ], - "filter_out_gap_fill": "1", - "gap_fill_target": "topbottom", - "prime_tower_brim_width": "5", - "prime_tower_width": "30", - "prime_volume": "126", - "wipe_tower_extra_rib_length": "8", - "wipe_tower_extra_spacing": "120%", - "wipe_tower_wall_type": "rib", - "enable_arc_fitting": "0", - "ooze_prevention": "1", - "precise_outer_wall": "0", - "slowdown_for_curled_perimeters": "0", - "standby_temperature_delta": "-150", - "support_threshold_angle": "35", - "support_type": "tree(auto)" + "type": "process", + "name": "0.56 Standard @Snapmaker U1 (0.8 nozzle)", + "inherits": "fdm_process_U1_0.56_nozzle_0.8", + "from": "system", + "setting_id": "JZEIXOUT33c7MrZj", + "instantiation": "true", + "description": "Compared with the default profile of a 0.8 mm nozzle, it has a much bigger layer height, and results in extremely apparent layer lines and much lower printing quality, but much shorter printing time in some printing cases.", + "elefant_foot_compensation": "0.15", + "smooth_coefficient": "150", + "overhang_totally_speed": "50", + "compatible_printers": [ + "Snapmaker U1 (0.8 nozzle)" + ], + "filter_out_gap_fill": "1", + "gap_fill_target": "topbottom", + "layer_height": "0.56", + "prime_tower_brim_width": "5", + "prime_tower_width": "30", + "prime_volume": "126", + "wipe_tower_extra_rib_length": "8", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_wall_type": "rib", + "enable_arc_fitting": "0", + "ooze_prevention": "1", + "precise_outer_wall": "1", + "slowdown_for_curled_perimeters": "0", + "standby_temperature_delta": "-150", + "support_threshold_angle": "35", + "support_type": "tree(auto)" } diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1.json b/resources/profiles/Snapmaker/process/fdm_process_U1.json index 5d89a91866..72dab0c16b 100644 --- a/resources/profiles/Snapmaker/process/fdm_process_U1.json +++ b/resources/profiles/Snapmaker/process/fdm_process_U1.json @@ -33,7 +33,6 @@ "wall_loops": "2", "inner_wall_line_width": "0.45", "inner_wall_speed": "40", - "print_settings_id": "", "raft_layers": "0", "seam_position": "nearest", "skirt_distance": "2", diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.06_nozzle_0.2.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.06_nozzle_0.2.json new file mode 100644 index 0000000000..240fd4f425 --- /dev/null +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.06_nozzle_0.2.json @@ -0,0 +1,27 @@ +{ + "type": "process", + "name": "fdm_process_U1_0.06_nozzle_0.2", + "inherits": "fdm_process_U1_common", + "from": "system", + "instantiation": "false", + "layer_height": "0.06", + "initial_layer_print_height": "0.1", + "wall_loops": "4", + "bottom_shell_layers": "5", + "top_shell_layers": "7", + "bridge_flow": "1", + "line_width": "0.22", + "outer_wall_line_width": "0.22", + "initial_layer_line_width": "0.25", + "sparse_infill_line_width": "0.22", + "inner_wall_line_width": "0.22", + "internal_solid_infill_line_width": "0.22", + "support_line_width": "0.22", + "top_surface_line_width": "0.22", + "initial_layer_speed": "40", + "initial_layer_infill_speed": "70", + "sparse_infill_speed": "100", + "top_surface_speed": "150", + "support_top_z_distance": "0.06", + "support_bottom_z_distance": "0.06" +} diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.08_nozzle_0.2.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.08_nozzle_0.2.json new file mode 100644 index 0000000000..41a824fa3a --- /dev/null +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.08_nozzle_0.2.json @@ -0,0 +1,27 @@ +{ + "type": "process", + "name": "fdm_process_U1_0.08_nozzle_0.2", + "inherits": "fdm_process_U1_common", + "from": "system", + "instantiation": "false", + "layer_height": "0.08", + "initial_layer_print_height": "0.1", + "wall_loops": "4", + "bottom_shell_layers": "5", + "top_shell_layers": "7", + "bridge_flow": "1", + "line_width": "0.22", + "outer_wall_line_width": "0.22", + "initial_layer_line_width": "0.25", + "sparse_infill_line_width": "0.22", + "inner_wall_line_width": "0.22", + "internal_solid_infill_line_width": "0.22", + "support_line_width": "0.22", + "top_surface_line_width": "0.22", + "initial_layer_speed": "40", + "initial_layer_infill_speed": "70", + "sparse_infill_speed": "100", + "top_surface_speed": "150", + "support_top_z_distance": "0.08", + "support_bottom_z_distance": "0.08" +} diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.10_nozzle_0.2.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.10_nozzle_0.2.json new file mode 100644 index 0000000000..5ca58d7bd1 --- /dev/null +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.10_nozzle_0.2.json @@ -0,0 +1,27 @@ +{ + "type": "process", + "name": "fdm_process_U1_0.10_nozzle_0.2", + "inherits": "fdm_process_U1_common", + "from": "system", + "instantiation": "false", + "layer_height": "0.1", + "initial_layer_print_height": "0.1", + "wall_loops": "4", + "bottom_shell_layers": "5", + "top_shell_layers": "7", + "bridge_flow": "1", + "line_width": "0.22", + "outer_wall_line_width": "0.22", + "initial_layer_line_width": "0.25", + "sparse_infill_line_width": "0.22", + "inner_wall_line_width": "0.22", + "internal_solid_infill_line_width": "0.22", + "support_line_width": "0.22", + "top_surface_line_width": "0.22", + "initial_layer_speed": "40", + "initial_layer_infill_speed": "70", + "sparse_infill_speed": "100", + "top_surface_speed": "150", + "support_top_z_distance": "0.1", + "support_bottom_z_distance": "0.1" +} diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.12_nozzle_0.2.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.12_nozzle_0.2.json new file mode 100644 index 0000000000..8c70dd9dee --- /dev/null +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.12_nozzle_0.2.json @@ -0,0 +1,27 @@ +{ + "type": "process", + "name": "fdm_process_U1_0.12_nozzle_0.2", + "inherits": "fdm_process_U1_common", + "from": "system", + "instantiation": "false", + "layer_height": "0.12", + "initial_layer_print_height": "0.1", + "wall_loops": "4", + "bottom_shell_layers": "5", + "top_shell_layers": "7", + "bridge_flow": "1", + "line_width": "0.22", + "outer_wall_line_width": "0.22", + "initial_layer_line_width": "0.25", + "sparse_infill_line_width": "0.22", + "inner_wall_line_width": "0.22", + "internal_solid_infill_line_width": "0.22", + "support_line_width": "0.22", + "top_surface_line_width": "0.22", + "initial_layer_speed": "40", + "initial_layer_infill_speed": "70", + "sparse_infill_speed": "100", + "top_surface_speed": "150", + "support_top_z_distance": "0.12", + "support_bottom_z_distance": "0.12" +} diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.14_nozzle_0.2.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.14_nozzle_0.2.json new file mode 100644 index 0000000000..1ac42c9ffa --- /dev/null +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.14_nozzle_0.2.json @@ -0,0 +1,27 @@ +{ + "type": "process", + "name": "fdm_process_U1_0.14_nozzle_0.2", + "inherits": "fdm_process_U1_common", + "from": "system", + "instantiation": "false", + "layer_height": "0.14", + "initial_layer_print_height": "0.1", + "wall_loops": "4", + "bottom_shell_layers": "5", + "top_shell_layers": "7", + "bridge_flow": "1", + "line_width": "0.22", + "outer_wall_line_width": "0.22", + "initial_layer_line_width": "0.25", + "sparse_infill_line_width": "0.22", + "inner_wall_line_width": "0.22", + "internal_solid_infill_line_width": "0.22", + "support_line_width": "0.22", + "top_surface_line_width": "0.22", + "initial_layer_speed": "40", + "initial_layer_infill_speed": "70", + "sparse_infill_speed": "100", + "top_surface_speed": "150", + "support_top_z_distance": "0.14", + "support_bottom_z_distance": "0.14" +} diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.18_nozzle_0.6.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.18_nozzle_0.6.json new file mode 100644 index 0000000000..f4725a73c7 --- /dev/null +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.18_nozzle_0.6.json @@ -0,0 +1,26 @@ +{ + "type": "process", + "name": "fdm_process_U1_0.18_nozzle_0.6", + "inherits": "fdm_process_U1_common", + "from": "system", + "instantiation": "false", + "layer_height": "0.18", + "initial_layer_print_height": "0.3", + "bridge_flow": "1", + "line_width": "0.62", + "outer_wall_line_width": "0.62", + "initial_layer_line_width": "0.62", + "sparse_infill_line_width": "0.62", + "inner_wall_line_width": "0.62", + "internal_solid_infill_line_width": "0.62", + "support_line_width": "0.62", + "top_surface_line_width": "0.62", + "initial_layer_speed": "35", + "initial_layer_infill_speed": "55", + "sparse_infill_speed": "100", + "top_surface_speed": "150", + "bridge_speed": "30", + "overhang_3_4_speed": "15", + "support_top_z_distance": "0.18", + "support_bottom_z_distance": "0.18" +} diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.24_nozzle_0.6.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.24_nozzle_0.6.json new file mode 100644 index 0000000000..a014a375b3 --- /dev/null +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.24_nozzle_0.6.json @@ -0,0 +1,24 @@ +{ + "type": "process", + "name": "fdm_process_U1_0.24_nozzle_0.6", + "inherits": "fdm_process_U1_common", + "from": "system", + "instantiation": "false", + "layer_height": "0.24", + "initial_layer_print_height": "0.3", + "bridge_flow": "1", + "line_width": "0.62", + "outer_wall_line_width": "0.62", + "initial_layer_line_width": "0.62", + "sparse_infill_line_width": "0.62", + "inner_wall_line_width": "0.62", + "internal_solid_infill_line_width": "0.62", + "support_line_width": "0.62", + "top_surface_line_width": "0.62", + "initial_layer_speed": "35", + "initial_layer_infill_speed": "55", + "sparse_infill_speed": "100", + "top_surface_speed": "150", + "bridge_speed": "30", + "overhang_3_4_speed": "15" +} diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.24_nozzle_0.8.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.24_nozzle_0.8.json new file mode 100644 index 0000000000..e958e9a2ee --- /dev/null +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.24_nozzle_0.8.json @@ -0,0 +1,26 @@ +{ + "type": "process", + "name": "fdm_process_U1_0.24_nozzle_0.8", + "inherits": "fdm_process_U1_common", + "from": "system", + "instantiation": "false", + "layer_height": "0.24", + "initial_layer_print_height": "0.4", + "bridge_flow": "1", + "line_width": "0.82", + "outer_wall_line_width": "0.82", + "initial_layer_line_width": "0.82", + "sparse_infill_line_width": "0.82", + "inner_wall_line_width": "0.82", + "internal_solid_infill_line_width": "0.82", + "support_line_width": "0.82", + "top_surface_line_width": "0.82", + "top_surface_pattern": "monotonic", + "initial_layer_speed": "35", + "initial_layer_infill_speed": "55", + "sparse_infill_speed": "100", + "top_surface_speed": "150", + "bridge_speed": "30", + "overhang_3_4_speed": "25", + "overhang_4_4_speed": "5" +} diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.30_nozzle_0.6.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.30_nozzle_0.6.json new file mode 100644 index 0000000000..a44a9ca05a --- /dev/null +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.30_nozzle_0.6.json @@ -0,0 +1,24 @@ +{ + "type": "process", + "name": "fdm_process_U1_0.30_nozzle_0.6", + "inherits": "fdm_process_U1_common", + "from": "system", + "instantiation": "false", + "layer_height": "0.3", + "initial_layer_print_height": "0.3", + "bridge_flow": "1", + "line_width": "0.62", + "outer_wall_line_width": "0.62", + "initial_layer_line_width": "0.62", + "sparse_infill_line_width": "0.62", + "inner_wall_line_width": "0.62", + "internal_solid_infill_line_width": "0.62", + "support_line_width": "0.62", + "top_surface_line_width": "0.62", + "initial_layer_speed": "35", + "initial_layer_infill_speed": "55", + "sparse_infill_speed": "100", + "top_surface_speed": "150", + "bridge_speed": "30", + "overhang_3_4_speed": "15" +} diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.32_nozzle_0.8.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.32_nozzle_0.8.json new file mode 100644 index 0000000000..67d9ecdb62 --- /dev/null +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.32_nozzle_0.8.json @@ -0,0 +1,26 @@ +{ + "type": "process", + "name": "fdm_process_U1_0.32_nozzle_0.8", + "inherits": "fdm_process_U1_common", + "from": "system", + "instantiation": "false", + "layer_height": "0.32", + "initial_layer_print_height": "0.4", + "bridge_flow": "1", + "line_width": "0.82", + "outer_wall_line_width": "0.82", + "initial_layer_line_width": "0.82", + "sparse_infill_line_width": "0.82", + "inner_wall_line_width": "0.82", + "internal_solid_infill_line_width": "0.82", + "support_line_width": "0.82", + "top_surface_line_width": "0.82", + "top_surface_pattern": "monotonic", + "initial_layer_speed": "35", + "initial_layer_infill_speed": "55", + "sparse_infill_speed": "100", + "top_surface_speed": "150", + "bridge_speed": "30", + "overhang_3_4_speed": "25", + "overhang_4_4_speed": "5" +} diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.36_nozzle_0.6.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.36_nozzle_0.6.json new file mode 100644 index 0000000000..314965b603 --- /dev/null +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.36_nozzle_0.6.json @@ -0,0 +1,24 @@ +{ + "type": "process", + "name": "fdm_process_U1_0.36_nozzle_0.6", + "inherits": "fdm_process_U1_common", + "from": "system", + "instantiation": "false", + "layer_height": "0.36", + "initial_layer_print_height": "0.3", + "bridge_flow": "1", + "line_width": "0.62", + "outer_wall_line_width": "0.62", + "initial_layer_line_width": "0.62", + "sparse_infill_line_width": "0.62", + "inner_wall_line_width": "0.62", + "internal_solid_infill_line_width": "0.62", + "support_line_width": "0.62", + "top_surface_line_width": "0.62", + "initial_layer_speed": "35", + "initial_layer_infill_speed": "55", + "sparse_infill_speed": "100", + "top_surface_speed": "150", + "bridge_speed": "30", + "overhang_3_4_speed": "15" +} diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.40_nozzle_0.8.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.40_nozzle_0.8.json new file mode 100644 index 0000000000..ec19b56fa5 --- /dev/null +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.40_nozzle_0.8.json @@ -0,0 +1,26 @@ +{ + "type": "process", + "name": "fdm_process_U1_0.40_nozzle_0.8", + "inherits": "fdm_process_U1_common", + "from": "system", + "instantiation": "false", + "layer_height": "0.4", + "initial_layer_print_height": "0.4", + "bridge_flow": "1", + "line_width": "0.82", + "outer_wall_line_width": "0.82", + "initial_layer_line_width": "0.82", + "sparse_infill_line_width": "0.82", + "inner_wall_line_width": "0.82", + "internal_solid_infill_line_width": "0.82", + "support_line_width": "0.82", + "top_surface_line_width": "0.82", + "top_surface_pattern": "monotonic", + "initial_layer_speed": "35", + "initial_layer_infill_speed": "55", + "sparse_infill_speed": "100", + "top_surface_speed": "150", + "bridge_speed": "30", + "overhang_3_4_speed": "25", + "overhang_4_4_speed": "5" +} diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.42_nozzle_0.6.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.42_nozzle_0.6.json new file mode 100644 index 0000000000..18c1e7d79b --- /dev/null +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.42_nozzle_0.6.json @@ -0,0 +1,24 @@ +{ + "type": "process", + "name": "fdm_process_U1_0.42_nozzle_0.6", + "inherits": "fdm_process_U1_common", + "from": "system", + "instantiation": "false", + "layer_height": "0.42", + "initial_layer_print_height": "0.3", + "bridge_flow": "1", + "line_width": "0.62", + "outer_wall_line_width": "0.62", + "initial_layer_line_width": "0.62", + "sparse_infill_line_width": "0.62", + "inner_wall_line_width": "0.62", + "internal_solid_infill_line_width": "0.62", + "support_line_width": "0.62", + "top_surface_line_width": "0.62", + "initial_layer_speed": "35", + "initial_layer_infill_speed": "55", + "sparse_infill_speed": "100", + "top_surface_speed": "150", + "bridge_speed": "30", + "overhang_3_4_speed": "15" +} diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.48_nozzle_0.8.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.48_nozzle_0.8.json new file mode 100644 index 0000000000..8d5632b790 --- /dev/null +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.48_nozzle_0.8.json @@ -0,0 +1,26 @@ +{ + "type": "process", + "name": "fdm_process_U1_0.48_nozzle_0.8", + "inherits": "fdm_process_U1_common", + "from": "system", + "instantiation": "false", + "layer_height": "0.48", + "initial_layer_print_height": "0.4", + "bridge_flow": "1", + "line_width": "0.82", + "outer_wall_line_width": "0.82", + "initial_layer_line_width": "0.82", + "sparse_infill_line_width": "0.82", + "inner_wall_line_width": "0.82", + "internal_solid_infill_line_width": "0.82", + "support_line_width": "0.82", + "top_surface_line_width": "0.82", + "top_surface_pattern": "monotonic", + "initial_layer_speed": "35", + "initial_layer_infill_speed": "55", + "sparse_infill_speed": "100", + "top_surface_speed": "150", + "bridge_speed": "30", + "overhang_3_4_speed": "25", + "overhang_4_4_speed": "5" +} diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.56_nozzle_0.8.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.56_nozzle_0.8.json new file mode 100644 index 0000000000..7a5c92932d --- /dev/null +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.56_nozzle_0.8.json @@ -0,0 +1,26 @@ +{ + "type": "process", + "name": "fdm_process_U1_0.56_nozzle_0.8", + "inherits": "fdm_process_U1_common", + "from": "system", + "instantiation": "false", + "layer_height": "0.56", + "initial_layer_print_height": "0.4", + "bridge_flow": "1", + "line_width": "0.82", + "outer_wall_line_width": "0.82", + "initial_layer_line_width": "0.82", + "sparse_infill_line_width": "0.82", + "inner_wall_line_width": "0.82", + "internal_solid_infill_line_width": "0.82", + "support_line_width": "0.82", + "top_surface_line_width": "0.82", + "top_surface_pattern": "monotonic", + "initial_layer_speed": "35", + "initial_layer_infill_speed": "55", + "sparse_infill_speed": "100", + "top_surface_speed": "150", + "bridge_speed": "30", + "overhang_3_4_speed": "25", + "overhang_4_4_speed": "5" +} diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_0.6_common.json b/resources/profiles/Snapmaker/process/fdm_process_U1_0.6_common.json index 93119a9370..40ea900ba2 100644 --- a/resources/profiles/Snapmaker/process/fdm_process_U1_0.6_common.json +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_0.6_common.json @@ -7,7 +7,7 @@ "line_width": "0.62", "outer_wall_line_width": "0.62", "inner_wall_line_width": "0.62", - "initial_layer_line_width": "0.72", + "initial_layer_line_width": "0.62", "sparse_infill_line_width": "0.62", "internal_solid_infill_line_width": "0.62", "support_line_width": "0.62", diff --git a/resources/profiles/Snapmaker/process/fdm_process_U1_common.json b/resources/profiles/Snapmaker/process/fdm_process_U1_common.json index 0af8c229a7..462ddb53ae 100644 --- a/resources/profiles/Snapmaker/process/fdm_process_U1_common.json +++ b/resources/profiles/Snapmaker/process/fdm_process_U1_common.json @@ -13,8 +13,7 @@ "compatible_printers_condition": "", "draft_shield": "disabled", "elefant_foot_compensation": "0", - "enable_arc_fitting": "1", - "exclude_object": "1", + "enable_arc_fitting": "0", "outer_wall_acceleration": "5000", "wall_infill_order": "inner wall/outer wall/infill", "line_width": "0.42", @@ -46,7 +45,7 @@ "internal_solid_infill_speed": "150", "initial_layer_infill_speed": "60", "resolution": "0.012", - "support_type": "normal(auto)", + "support_type": "tree(auto)", "support_style": "default", "support_top_z_distance": "0.2", "support_bottom_z_distance": "0.2", @@ -68,11 +67,9 @@ "travel_speed": "500", "enable_prime_tower": "1", "wipe_tower_no_sparse_layers": "0", - "wipe_tower_cone_angle": "30", - "wipe_tower_wall_type": "rib", - "wipe_tower_extra_rib_length": "0", "prime_tower_width": "35", - "prime_volume": "30", "wall_generator": "arachne", - "compatible_printers": [] + "compatible_printers": [], + "wipe_tower_extra_rib_length": "8", + "exclude_object": "1" } diff --git a/resources/profiles/Snapmaker/process/fdm_process_a400.json b/resources/profiles/Snapmaker/process/fdm_process_a400.json index 39e7565f0b..f8ca481f9f 100644 --- a/resources/profiles/Snapmaker/process/fdm_process_a400.json +++ b/resources/profiles/Snapmaker/process/fdm_process_a400.json @@ -5,7 +5,7 @@ "from": "system", "instantiation": "false", "initial_layer_print_height": "0.2", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "initial_layer_infill_speed": "75", "outer_wall_speed": "100", "inner_wall_speed": "160", diff --git a/resources/profiles/Snapmaker/process/fdm_process_common.json b/resources/profiles/Snapmaker/process/fdm_process_common.json index 6fb4fa2de4..458a0f6162 100644 --- a/resources/profiles/Snapmaker/process/fdm_process_common.json +++ b/resources/profiles/Snapmaker/process/fdm_process_common.json @@ -110,7 +110,7 @@ "top_surface_jerk": "2", "travel_jerk": "4", "enable_support": "0", - "support_type": "normal(auto)", + "support_type": "tree(auto)", "support_style": "snug", "support_threshold_angle": "30", "support_on_build_plate_only": "1", diff --git a/resources/profiles/Snapmaker/process/fdm_process_idex.json b/resources/profiles/Snapmaker/process/fdm_process_idex.json index 7e04710bd3..6aeabfdaa7 100644 --- a/resources/profiles/Snapmaker/process/fdm_process_idex.json +++ b/resources/profiles/Snapmaker/process/fdm_process_idex.json @@ -5,7 +5,7 @@ "from": "system", "instantiation": "false", "initial_layer_print_height": "0.2", - "enable_arc_fitting": "1", + "enable_arc_fitting": "0", "initial_layer_infill_speed": "75", "outer_wall_speed": "120", "inner_wall_speed": "250", diff --git a/resources/profiles/Voron/machine/fdm_klipper_common.json b/resources/profiles/Voron/machine/fdm_klipper_common.json index 4d40f3d168..b4ffd1a4bb 100644 --- a/resources/profiles/Voron/machine/fdm_klipper_common.json +++ b/resources/profiles/Voron/machine/fdm_klipper_common.json @@ -116,7 +116,7 @@ "deretraction_speed": [ "30" ], - "z_hop_types": "Normal Lift", + "z_hop_types": "Slope Lift", "silent_mode": "0", "single_extruder_multi_material": "1", "change_filament_gcode": "", diff --git a/resources/profiles/re3D.json b/resources/profiles/re3D.json index e0acc669d0..94cca3c2ef 100644 --- a/resources/profiles/re3D.json +++ b/resources/profiles/re3D.json @@ -1,214 +1,219 @@ { - "name": "re3D", - "version": "02.04.00.03", - "force_update": "0", - "description": "re3D configurations", - "machine_model_list": [ - { - "name": "re3D Gigabot 4", - "sub_path": "machine/re3D Gigabot 4.json" - }, - { - "name": "re3D Gigabot 4 XLT", - "sub_path": "machine/re3D Gigabot 4 XLT.json" - }, - { - "name": "re3D GigabotX 2", - "sub_path": "machine/re3D GigabotX 2.json" - }, - { - "name": "re3D GigabotX 2 XLT", - "sub_path": "machine/re3D GigabotX 2 XLT.json" - }, - { - "name": "re3D Terabot 4", - "sub_path": "machine/re3D Terabot 4.json" - }, - { - "name": "re3D TerabotX 2", - "sub_path": "machine/re3D TerabotX 2.json" - } - ], - "process_list": [ - { - "name": "fdm_process_common", - "sub_path": "process/fdm_process_common.json" - }, - { - "name": "fdm_process_re3D_common", - "sub_path": "process/fdm_process_re3D_common.json" - }, - { - "name": "fgf_process_re3D_common", - "sub_path": "process/fgf_process_re3D_common.json" - }, - { - "name": "0.2 Fine", - "sub_path": "process/0.2mm Fine @re3D fdm 0.4.json" - }, - { - "name": "0.26 Standard", - "sub_path": "process/0.26mm Standard @re3D fdm 0.4.json" - }, - { - "name": "0.3 Fine", - "sub_path": "process/0.3mm Fine @re3D fdm 0.8.json" - }, - { - "name": "0.32 Draft", - "sub_path": "process/0.32mm Draft @re3D fdm 0.4.json" - }, - { - "name": "0.4 Standard", - "sub_path": "process/0.4mm Draft @re3D fdm 0.8.json" - }, - { - "name": "0.6 Standard", - "sub_path": "process/0.6mm Standard @re3D fgf 0.8.json" - }, - { - "name": "1.0 Standard", - "sub_path": "process/1.0mm Standard @re3D fgf 1.75.json" - } - ], - "filament_list": [ - { - "name": "fdm_filament_common", - "sub_path": "filament/fdm_filament_common.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": "re3D PC", - "sub_path": "filament/re3D PC.json" - }, - { - "name": "re3D PC @0.4 nozzle", - "sub_path": "filament/re3D PC @0.4 nozzle.json" - }, - { - "name": "re3D PC @0.8 nozzle", - "sub_path": "filament/re3D PC @0.8 nozzle.json" - }, - { - "name": "re3D Greengate rPETG", - "sub_path": "filament/re3D Greengate rPETG.json" - }, - { - "name": "re3D Greengate rPETG @0.8 nozzle", - "sub_path": "filament/re3D Greengate rPETG @0.8 nozzle.json" - }, - { - "name": "re3D Greengate rPETG @1.75 nozzle", - "sub_path": "filament/re3D Greengate rPETG @1.75 nozzle.json" - }, - { - "name": "re3D PETG", - "sub_path": "filament/re3D PETG.json" - }, - { - "name": "re3D PETG @0.4 nozzle", - "sub_path": "filament/re3D PETG @0.4 nozzle.json" - }, - { - "name": "re3D PETG @0.8 nozzle", - "sub_path": "filament/re3D PETG @0.8 nozzle.json" - }, - { - "name": "re3D rPP", - "sub_path": "filament/re3D rPP.json" - }, - { - "name": "re3D rPP @0.8 nozzle", - "sub_path": "filament/re3D rPP @0.8 nozzle.json" - }, - { - "name": "re3D rPP @1.75 nozzle", - "sub_path": "filament/re3D rPP @1.75 nozzle.json" - }, - { - "name": "re3D PLA", - "sub_path": "filament/re3D PLA.json" - }, - { - "name": "re3D PLA @0.4 nozzle", - "sub_path": "filament/re3D PLA @0.4 nozzle.json" - }, - { - "name": "re3D PLA @0.8 nozzle", - "sub_path": "filament/re3D PLA @0.8 nozzle.json" - } - ], - "machine_list": [ - { - "name": "fdm_machine_common", - "sub_path": "machine/fdm_machine_common.json" - }, - { - "name": "fdm_re3D_common", - "sub_path": "machine/fdm_re3D_common.json" - }, - { - "name": "fgf_re3D_common", - "sub_path": "machine/fgf_re3D_common.json" - }, - { - "name": "re3D Gigabot 4 0.4 nozzle", - "sub_path": "machine/re3D Gigabot 4 0.4 nozzle.json" - }, - { - "name": "re3D Gigabot 4 0.8 nozzle", - "sub_path": "machine/re3D Gigabot 4 0.8 nozzle.json" - }, - { - "name": "re3D Gigabot 4 XLT 0.4 nozzle", - "sub_path": "machine/re3D Gigabot 4 XLT 0.4 nozzle.json" - }, - { - "name": "re3D Gigabot 4 XLT 0.8 nozzle", - "sub_path": "machine/re3D Gigabot 4 XLT 0.8 nozzle.json" - }, - { - "name": "re3D Terabot 4 0.4 nozzle", - "sub_path": "machine/re3D Terabot 4 0.4 nozzle.json" - }, - { - "name": "re3D Terabot 4 0.8 nozzle", - "sub_path": "machine/re3D Terabot 4 0.8 nozzle.json" - }, - { - "name": "re3D GigabotX 2 0.8 nozzle", - "sub_path": "machine/re3D GigabotX 2 0.8 nozzle.json" - }, - { - "name": "re3D GigabotX 2 1.75 nozzle", - "sub_path": "machine/re3D GigabotX 2 1.75 nozzle.json" - }, - { - "name": "re3D GigabotX 2 XLT 0.8 nozzle", - "sub_path": "machine/re3D GigabotX 2 XLT 0.8 nozzle.json" - }, - { - "name": "re3D GigabotX 2 XLT 1.75 nozzle", - "sub_path": "machine/re3D GigabotX 2 XLT 1.75 nozzle.json" - }, - { - "name": "re3D TerabotX 2 0.8 nozzle", - "sub_path": "machine/re3D TerabotX 2 0.8 nozzle.json" - }, - { - "name": "re3D TerabotX 2 1.75 nozzle", - "sub_path": "machine/re3D TerabotX 2 1.75 nozzle.json" - } - ] -} + "name": "re3D", + "url": "", + "version": "03.00.08", + "force_update": "0", + "description": "re3D configurations", + "machine_model_list": [ + { + "name": "re3D Gigabot 4", + "sub_path": "machine/re3D Gigabot 4.json" + }, + { + "name": "re3D Gigabot 4 XLT", + "sub_path": "machine/re3D Gigabot 4 XLT.json" + }, + { + "name": "re3D GigabotX 2", + "sub_path": "machine/re3D GigabotX 2.json" + }, + { + "name": "re3D GigabotX 2 XLT", + "sub_path": "machine/re3D GigabotX 2 XLT.json" + }, + { + "name": "re3D Terabot 4", + "sub_path": "machine/re3D Terabot 4.json" + }, + { + "name": "re3D TerabotX 2", + "sub_path": "machine/re3D TerabotX 2.json" + } + ], + "process_list": [ + { + "name": "fdm_process_common", + "sub_path": "process/fdm_process_common.json" + }, + { + "name": "fdm_process_re3D_common", + "sub_path": "process/fdm_process_re3D_common.json" + }, + { + "name": "fgf_process_re3D_common", + "sub_path": "process/fgf_process_re3D_common.json" + }, + { + "name": "0.2 Fine", + "sub_path": "process/0.2mm Fine @re3D fdm 0.4.json" + }, + { + "name": "0.26 Standard", + "sub_path": "process/0.26mm Standard @re3D fdm 0.4.json" + }, + { + "name": "0.32 Draft", + "sub_path": "process/0.32mm Draft @re3D fdm 0.4.json" + }, + { + "name": "0.3 Fine", + "sub_path": "process/0.3mm Fine @re3D fdm 0.8.json" + }, + { + "name": "0.4 Standard", + "sub_path": "process/0.4mm Draft @re3D fdm 0.8.json" + }, + { + "name": "1.0 Standard", + "sub_path": "process/1.0mm Standard @re3D fgf 1.75.json" + }, + { + "name": "0.6 Standard", + "sub_path": "process/0.6mm Standard @re3D fgf 0.8.json" + } + ], + "filament_list": [ + { + "name": "fdm_filament_common", + "sub_path": "filament/fdm_filament_common.json" + }, + { + "name": "fdm_filament_pla", + "sub_path": "filament/fdm_filament_pla.json" + }, + { + "name": "fdm_filament_pet", + "sub_path": "filament/fdm_filament_pet.json" + }, + { + "name": "fdm_filament_pp", + "sub_path": "filament/fdm_filament_pp.json" + }, + { + "name": "fdm_filament_pc", + "sub_path": "filament/fdm_filament_pc.json" + }, + { + "name": "re3D PLA", + "sub_path": "filament/re3D PLA.json" + }, + { + "name": "re3D PETG", + "sub_path": "filament/re3D PETG.json" + }, + { + "name": "re3D PC", + "sub_path": "filament/re3D PC.json" + }, + { + "name": "re3D rPETG", + "sub_path": "filament/re3D rPETG.json" + }, + { + "name": "re3D rPP", + "sub_path": "filament/re3D rPP.json" + }, + { + "name": "re3D PLA @0.4 nozzle", + "sub_path": "filament/re3D PLA @0.4 nozzle.json" + }, + { + "name": "re3D PLA @0.8 nozzle", + "sub_path": "filament/re3D PLA @0.8 nozzle.json" + }, + { + "name": "re3D PETG @0.4 nozzle", + "sub_path": "filament/re3D PETG @0.4 nozzle.json" + }, + { + "name": "re3D PETG @0.8 nozzle", + "sub_path": "filament/re3D PETG @0.8 nozzle.json" + }, + { + "name": "re3D PC @0.4 nozzle", + "sub_path": "filament/re3D PC @0.4 nozzle.json" + }, + { + "name": "re3D PC @0.8 nozzle", + "sub_path": "filament/re3D PC @0.8 nozzle.json" + }, + { + "name": "re3D rPETG @0.8 nozzle", + "sub_path": "filament/re3D rPETG @0.8 nozzle.json" + }, + { + "name": "re3D rPETG @1.75 nozzle", + "sub_path": "filament/re3D rPETG @1.75 nozzle.json" + }, + { + "name": "re3D rPP @0.8 nozzle", + "sub_path": "filament/re3D rPP @0.8 nozzle.json" + }, + { + "name": "re3D rPP @1.75 nozzle", + "sub_path": "filament/re3D rPP @1.75 nozzle.json" + } + ], + "machine_list": [ + { + "name": "fdm_machine_common", + "sub_path": "machine/fdm_machine_common.json" + }, + { + "name": "fdm_re3D_common", + "sub_path": "machine/fdm_re3D_common.json" + }, + { + "name": "fgf_re3D_common", + "sub_path": "machine/fgf_re3D_common.json" + }, + { + "name": "re3D Gigabot 4 0.4 nozzle", + "sub_path": "machine/re3D Gigabot 4 0.4 nozzle.json" + }, + { + "name": "re3D Gigabot 4 0.8 nozzle", + "sub_path": "machine/re3D Gigabot 4 0.8 nozzle.json" + }, + { + "name": "re3D Gigabot 4 XLT 0.4 nozzle", + "sub_path": "machine/re3D Gigabot 4 XLT 0.4 nozzle.json" + }, + { + "name": "re3D Gigabot 4 XLT 0.8 nozzle", + "sub_path": "machine/re3D Gigabot 4 XLT 0.8 nozzle.json" + }, + { + "name": "re3D GigabotX 2 0.8 nozzle", + "sub_path": "machine/re3D GigabotX 2 0.8 nozzle.json" + }, + { + "name": "re3D GigabotX 2 1.75 nozzle", + "sub_path": "machine/re3D GigabotX 2 1.75 nozzle.json" + }, + { + "name": "re3D GigabotX 2 XLT 0.8 nozzle", + "sub_path": "machine/re3D GigabotX 2 XLT 0.8 nozzle.json" + }, + { + "name": "re3D GigabotX 2 XLT 1.75 nozzle", + "sub_path": "machine/re3D GigabotX 2 XLT 1.75 nozzle.json" + }, + { + "name": "re3D Terabot 4 0.4 nozzle", + "sub_path": "machine/re3D Terabot 4 0.4 nozzle.json" + }, + { + "name": "re3D Terabot 4 0.8 nozzle", + "sub_path": "machine/re3D Terabot 4 0.8 nozzle.json" + }, + { + "name": "re3D TerabotX 2 0.8 nozzle", + "sub_path": "machine/re3D TerabotX 2 0.8 nozzle.json" + }, + { + "name": "re3D TerabotX 2 1.75 nozzle", + "sub_path": "machine/re3D TerabotX 2 1.75 nozzle.json" + } + ] +} \ No newline at end of file diff --git a/resources/profiles/re3D/filament/fdm_filament_pp.json b/resources/profiles/re3D/filament/fdm_filament_pp.json new file mode 100644 index 0000000000..16a1c9705d --- /dev/null +++ b/resources/profiles/re3D/filament/fdm_filament_pp.json @@ -0,0 +1,10 @@ +{ + "type": "filament", + "name": "fdm_filament_pp", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_common", + "filament_type": [ + "PP" + ] +} \ No newline at end of file diff --git a/resources/profiles/re3D/filament/re3D PC @0.4 nozzle.json b/resources/profiles/re3D/filament/re3D PC @0.4 nozzle.json index 47a3a44f34..d3ec58f07c 100644 --- a/resources/profiles/re3D/filament/re3D PC @0.4 nozzle.json +++ b/resources/profiles/re3D/filament/re3D PC @0.4 nozzle.json @@ -9,6 +9,9 @@ "filament_settings_id": [ "re3D PC @0.4 nozzle" ], + "filament_type": [ + "PC" + ], "compatible_printers": [ "re3D Gigabot 4 0.4 nozzle", "re3D Gigabot 4 XLT 0.4 nozzle", diff --git a/resources/profiles/re3D/filament/re3D PC @0.8 nozzle.json b/resources/profiles/re3D/filament/re3D PC @0.8 nozzle.json index c1f329f295..2f4f743d07 100644 --- a/resources/profiles/re3D/filament/re3D PC @0.8 nozzle.json +++ b/resources/profiles/re3D/filament/re3D PC @0.8 nozzle.json @@ -9,6 +9,9 @@ "filament_settings_id": [ "re3D PC @0.8 nozzle" ], + "filament_type": [ + "PC" + ], "compatible_printers": [ "re3D Gigabot 4 0.8 nozzle", "re3D Gigabot 4 XLT 0.8 nozzle", diff --git a/resources/profiles/re3D/filament/re3D PETG @0.4 nozzle.json b/resources/profiles/re3D/filament/re3D PETG @0.4 nozzle.json index c275a7517f..d85397a1c0 100644 --- a/resources/profiles/re3D/filament/re3D PETG @0.4 nozzle.json +++ b/resources/profiles/re3D/filament/re3D PETG @0.4 nozzle.json @@ -17,6 +17,9 @@ "filament_vendor": [ "re3D" ], + "filament_type": [ + "PETG" + ], "close_fan_the_first_x_layers": [ "2" ], diff --git a/resources/profiles/re3D/filament/re3D PETG @0.8 nozzle.json b/resources/profiles/re3D/filament/re3D PETG @0.8 nozzle.json index 148f6540fe..c45d4a84e5 100644 --- a/resources/profiles/re3D/filament/re3D PETG @0.8 nozzle.json +++ b/resources/profiles/re3D/filament/re3D PETG @0.8 nozzle.json @@ -14,6 +14,9 @@ "re3D Gigabot 4 XLT 0.8 nozzle", "re3D Terabot 4 0.8 nozzle" ], + "filament_type": [ + "PETG" + ], "filament_vendor": [ "re3D" ], diff --git a/resources/profiles/re3D/filament/re3D PLA @0.4 nozzle.json b/resources/profiles/re3D/filament/re3D PLA @0.4 nozzle.json index 1719807f7f..a3630d0111 100644 --- a/resources/profiles/re3D/filament/re3D PLA @0.4 nozzle.json +++ b/resources/profiles/re3D/filament/re3D PLA @0.4 nozzle.json @@ -9,6 +9,9 @@ "filament_settings_id": [ "re3D PLA @0.4 nozzle" ], + "filament_type": [ + "PLA" + ], "compatible_printers": [ "re3D Gigabot 4 0.4 nozzle", "re3D Gigabot 4 XLT 0.4 nozzle", diff --git a/resources/profiles/re3D/filament/re3D PLA @0.8 nozzle.json b/resources/profiles/re3D/filament/re3D PLA @0.8 nozzle.json index 01e7abbc9a..002e18f67c 100644 --- a/resources/profiles/re3D/filament/re3D PLA @0.8 nozzle.json +++ b/resources/profiles/re3D/filament/re3D PLA @0.8 nozzle.json @@ -9,6 +9,9 @@ "filament_settings_id": [ "re3D PLA @0.8 nozzle" ], + "filament_type": [ + "PLA" + ], "compatible_printers": [ "re3D Gigabot 4 0.8 nozzle", "re3D Gigabot 4 XLT 0.8 nozzle", diff --git a/resources/profiles/re3D/filament/re3D Greengate rPETG @0.8 nozzle.json b/resources/profiles/re3D/filament/re3D rPETG @0.8 nozzle.json similarity index 89% rename from resources/profiles/re3D/filament/re3D Greengate rPETG @0.8 nozzle.json rename to resources/profiles/re3D/filament/re3D rPETG @0.8 nozzle.json index 028bf042bb..0ac0d012f5 100644 --- a/resources/profiles/re3D/filament/re3D Greengate rPETG @0.8 nozzle.json +++ b/resources/profiles/re3D/filament/re3D rPETG @0.8 nozzle.json @@ -1,14 +1,21 @@ { "type": "filament", "filament_id": "GFG01", - "setting_id": "fRX555Prkdu5ESIp", - "name": "re3D Greengate rPETG @0.8 nozzle", + "setting_id": "WlELqPVnuL7DaTxs", + "name": "re3D rPETG @0.8 nozzle", "from": "system", + "renamed_from": "re3D Greengate rPETG @0.8 nozzle", "instantiation": "true", "inherits": "fdm_filament_pet", "nozzle_temperature_initial_layer": [ "0" ], + "filament_type": [ + "PETG" + ], + "filament_vendor": [ + "re3D" + ], "nozzle_temperature": [ "0" ], diff --git a/resources/profiles/re3D/filament/re3D Greengate rPETG @1.75 nozzle.json b/resources/profiles/re3D/filament/re3D rPETG @1.75 nozzle.json similarity index 89% rename from resources/profiles/re3D/filament/re3D Greengate rPETG @1.75 nozzle.json rename to resources/profiles/re3D/filament/re3D rPETG @1.75 nozzle.json index 5ae3d832ff..8cd090fc06 100644 --- a/resources/profiles/re3D/filament/re3D Greengate rPETG @1.75 nozzle.json +++ b/resources/profiles/re3D/filament/re3D rPETG @1.75 nozzle.json @@ -1,14 +1,21 @@ { "type": "filament", "filament_id": "GFG01", - "setting_id": "6aPU6CYS2cmODkok", - "name": "re3D Greengate rPETG @1.75 nozzle", + "setting_id": "sHzO2S3mmE6Iqs2O", + "name": "re3D rPETG @1.75 nozzle", "from": "system", + "renamed_from": "re3D Greengate rPETG @1.75 nozzle", "instantiation": "true", "inherits": "fdm_filament_pet", "nozzle_temperature_initial_layer": [ "0" ], + "filament_type": [ + "PETG" + ], + "filament_vendor": [ + "re3D" + ], "nozzle_temperature": [ "0" ], diff --git a/resources/profiles/re3D/filament/re3D Greengate rPETG.json b/resources/profiles/re3D/filament/re3D rPETG.json similarity index 78% rename from resources/profiles/re3D/filament/re3D Greengate rPETG.json rename to resources/profiles/re3D/filament/re3D rPETG.json index de56af4f02..fe19f12539 100644 --- a/resources/profiles/re3D/filament/re3D Greengate rPETG.json +++ b/resources/profiles/re3D/filament/re3D rPETG.json @@ -1,13 +1,14 @@ { "type": "filament", - "name": "re3D Greengate rPETG", + "name": "re3D rPETG", "from": "system", + "renamed_from": "re3D Greengate rPETG", "instantiation": "true", "inherits": "fdm_filament_pet", "filament_id": "GFG01", - "setting_id": "SdugLw5oy9GB7NID", + "setting_id": "6aESuJ2S2Kogd4Lq", "filament_settings_id": [ - "re3D Greengate rPETG" + "re3D rPETG" ], "compatible_printers": [ "re3D GigabotX 2 0.8 nozzle", diff --git a/resources/profiles/re3D/filament/re3D rPP @0.8 nozzle.json b/resources/profiles/re3D/filament/re3D rPP @0.8 nozzle.json index a49f19e128..5f5467e86d 100644 --- a/resources/profiles/re3D/filament/re3D rPP @0.8 nozzle.json +++ b/resources/profiles/re3D/filament/re3D rPP @0.8 nozzle.json @@ -5,7 +5,7 @@ "name": "re3D rPP @0.8 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_filament_pet", + "inherits": "fdm_filament_pp", "filament_type": [ "PP" ], diff --git a/resources/profiles/re3D/filament/re3D rPP @1.75 nozzle.json b/resources/profiles/re3D/filament/re3D rPP @1.75 nozzle.json index 0bde56c596..2e5a3f4386 100644 --- a/resources/profiles/re3D/filament/re3D rPP @1.75 nozzle.json +++ b/resources/profiles/re3D/filament/re3D rPP @1.75 nozzle.json @@ -5,7 +5,7 @@ "name": "re3D rPP @1.75 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_filament_pet", + "inherits": "fdm_filament_pp", "filament_type": [ "PP" ], diff --git a/resources/profiles/re3D/filament/re3D rPP.json b/resources/profiles/re3D/filament/re3D rPP.json index bf96aa51e6..f7244f5985 100644 --- a/resources/profiles/re3D/filament/re3D rPP.json +++ b/resources/profiles/re3D/filament/re3D rPP.json @@ -3,10 +3,7 @@ "name": "re3D rPP", "from": "system", "instantiation": "true", - "inherits": "fdm_filament_pet", - "filament_type": [ - "PP" - ], + "inherits": "fdm_filament_pp", "filament_id": "GFG02", "setting_id": "8PB62qm5Cd3SHLf4", "filament_settings_id": [ diff --git a/resources/profiles/re3D/machine/re3D Gigabot 4 0.4 nozzle.json b/resources/profiles/re3D/machine/re3D Gigabot 4 0.4 nozzle.json index a0cbd3c0e2..d14d3c260e 100644 --- a/resources/profiles/re3D/machine/re3D Gigabot 4 0.4 nozzle.json +++ b/resources/profiles/re3D/machine/re3D Gigabot 4 0.4 nozzle.json @@ -6,7 +6,7 @@ "machine_tech": "FFF", "model_id": "GB4", "printer_model": "re3D Gigabot 4", - "bed_texture": "Gigabot 4_buildplate_texture.png", + "bed_texture": "re3D Gigabot 4_buildplate_texture.svg", "default_materials": "re3D PETG;re3D PLA;re3D PC", "printable_area": [ "0x0", diff --git a/resources/profiles/re3D/machine/re3D Gigabot 4 0.8 nozzle.json b/resources/profiles/re3D/machine/re3D Gigabot 4 0.8 nozzle.json index e5d847e62c..9bc78b36ad 100644 --- a/resources/profiles/re3D/machine/re3D Gigabot 4 0.8 nozzle.json +++ b/resources/profiles/re3D/machine/re3D Gigabot 4 0.8 nozzle.json @@ -6,7 +6,7 @@ "machine_tech": "FFF", "model_id": "GB4", "printer_model": "re3D Gigabot 4", - "bed_texture": "Gigabot 4_buildplate_texture.png", + "bed_texture": "re3D Gigabot 4_buildplate_texture.svg", "default_materials": "re3D PETG;re3D PLA;re3D PC", "printable_area": [ "0x0", diff --git a/resources/profiles/re3D/machine/re3D Gigabot 4 XLT 0.4 nozzle.json b/resources/profiles/re3D/machine/re3D Gigabot 4 XLT 0.4 nozzle.json index 8a5e118bff..56b4030476 100644 --- a/resources/profiles/re3D/machine/re3D Gigabot 4 XLT 0.4 nozzle.json +++ b/resources/profiles/re3D/machine/re3D Gigabot 4 XLT 0.4 nozzle.json @@ -6,7 +6,7 @@ "machine_tech": "FFF", "model_id": "GB4", "printer_model": "re3D Gigabot 4 XLT", - "bed_texture": "Gigabot 4 XLT_buildplate_texture.png", + "bed_texture": "re3D Gigabot 4 XLT_buildplate_texture.svg", "default_materials": "re3D PETG;re3D PLA;re3D PC", "printable_area": [ "0x0", diff --git a/resources/profiles/re3D/machine/re3D Gigabot 4 XLT 0.8 nozzle.json b/resources/profiles/re3D/machine/re3D Gigabot 4 XLT 0.8 nozzle.json index a3fabc985d..a14e730b30 100644 --- a/resources/profiles/re3D/machine/re3D Gigabot 4 XLT 0.8 nozzle.json +++ b/resources/profiles/re3D/machine/re3D Gigabot 4 XLT 0.8 nozzle.json @@ -6,7 +6,7 @@ "machine_tech": "FFF", "model_id": "GB4", "printer_model": "re3D Gigabot 4 XLT", - "bed_texture": "Gigabot 4 XLT_buildplate_texture.png", + "bed_texture": "re3D Gigabot 4 XLT_buildplate_texture.svg", "default_materials": "re3D PETG;re3D PLA;re3D PC", "printable_area": [ "0x0", diff --git a/resources/profiles/re3D/machine/re3D GigabotX 2 0.8 nozzle.json b/resources/profiles/re3D/machine/re3D GigabotX 2 0.8 nozzle.json index 8260ee5a1d..f6bac17a0d 100644 --- a/resources/profiles/re3D/machine/re3D GigabotX 2 0.8 nozzle.json +++ b/resources/profiles/re3D/machine/re3D GigabotX 2 0.8 nozzle.json @@ -6,7 +6,7 @@ "machine_tech": "FGF", "model_id": "re3D GBX2", "printer_model": "re3D GigabotX 2", - "bed_texture": "Gigabot 4_buildplate_texture.png", + "bed_texture": "re3D GigabotX 2_buildplate_texture.svg", "printable_area": [ "0x0", "552x0", @@ -25,7 +25,7 @@ "0.3" ], "default_filament_profile": [ - "re3D Greengate rPETG @0.8 nozzle" + "re3D rPETG @0.8 nozzle" ], "default_print_profile": "0.6 Standard", "printer_settings_id": "re3d_gbx_08", diff --git a/resources/profiles/re3D/machine/re3D GigabotX 2 1.75 nozzle.json b/resources/profiles/re3D/machine/re3D GigabotX 2 1.75 nozzle.json index 8a89e9d858..585c219bc7 100644 --- a/resources/profiles/re3D/machine/re3D GigabotX 2 1.75 nozzle.json +++ b/resources/profiles/re3D/machine/re3D GigabotX 2 1.75 nozzle.json @@ -7,7 +7,7 @@ "machine_tech": "FGF", "model_id": "re3D GBX2", "printer_model": "re3D GigabotX 2", - "bed_texture": "Gigabot 4_buildplate_texture.png", + "bed_texture": "re3D GigabotX 2_buildplate_texture.svg", "printable_area": [ "0x0", "552x0", @@ -26,7 +26,7 @@ "0.6" ], "default_filament_profile": [ - "re3D Greengate rPETG @1.75 nozzle" + "re3D rPETG @1.75 nozzle" ], "default_print_profile": "1.0 Standard", "printer_settings_id": "re3d_gbx_175", diff --git a/resources/profiles/re3D/machine/re3D GigabotX 2 XLT 0.8 nozzle.json b/resources/profiles/re3D/machine/re3D GigabotX 2 XLT 0.8 nozzle.json index 2d81331c5c..863d8e6403 100644 --- a/resources/profiles/re3D/machine/re3D GigabotX 2 XLT 0.8 nozzle.json +++ b/resources/profiles/re3D/machine/re3D GigabotX 2 XLT 0.8 nozzle.json @@ -6,7 +6,7 @@ "machine_tech": "FGF", "model_id": "re3D GBX2 XLT", "printer_model": "re3D GigabotX 2 XLT", - "bed_texture": "GigabotX 2 XLT_buildplate_texture.png", + "bed_texture": "re3D GigabotX 2 XLT_buildplate_texture.svg", "printable_area": [ "0x0", "552x0", @@ -25,7 +25,7 @@ "0.3" ], "default_filament_profile": [ - "re3D Greengate rPETG @0.8 nozzle" + "re3D rPETG @0.8 nozzle" ], "default_print_profile": "0.6 Standard", "printer_settings_id": "re3d_gbx_xlt_08", diff --git a/resources/profiles/re3D/machine/re3D GigabotX 2 XLT 1.75 nozzle.json b/resources/profiles/re3D/machine/re3D GigabotX 2 XLT 1.75 nozzle.json index 63503c01d8..5784b4e673 100644 --- a/resources/profiles/re3D/machine/re3D GigabotX 2 XLT 1.75 nozzle.json +++ b/resources/profiles/re3D/machine/re3D GigabotX 2 XLT 1.75 nozzle.json @@ -7,7 +7,7 @@ "machine_tech": "FGF", "model_id": "re3D GBX2 XLT", "printer_model": "re3D GigabotX 2 XLT", - "bed_texture": "GigabotX 2 XLT_buildplate_texture.png", + "bed_texture": "re3D GigabotX 2 XLT_buildplate_texture.svg", "printable_area": [ "0x0", "552x0", @@ -26,7 +26,7 @@ "0.6" ], "default_filament_profile": [ - "re3D Greengate rPETG @1.75 nozzle" + "re3D rPETG @1.75 nozzle" ], "default_print_profile": "1.0 Standard", "printer_settings_id": "re3d_gbx_xlt_175", diff --git a/resources/profiles/re3D/machine/re3D GigabotX 2 XLT.json b/resources/profiles/re3D/machine/re3D GigabotX 2 XLT.json index 09a2702f3a..99800331d9 100644 --- a/resources/profiles/re3D/machine/re3D GigabotX 2 XLT.json +++ b/resources/profiles/re3D/machine/re3D GigabotX 2 XLT.json @@ -9,5 +9,5 @@ "bed_model": "", "bed_texture": "re3D GigabotX 2 XLT_buildplate_texture.svg", "hotend_model": "GBX-HOTEND.stl", - "default_materials": "re3D Greengate rPETG;re3D rPP;" + "default_materials": "re3D rPETG;re3D rPP;" } diff --git a/resources/profiles/re3D/machine/re3D GigabotX 2.json b/resources/profiles/re3D/machine/re3D GigabotX 2.json index cc1470ee05..3a1db130b0 100644 --- a/resources/profiles/re3D/machine/re3D GigabotX 2.json +++ b/resources/profiles/re3D/machine/re3D GigabotX 2.json @@ -9,5 +9,5 @@ "bed_model": "", "bed_texture": "re3D GigabotX 2_buildplate_texture.svg", "hotend_model": "GBX-HOTEND.stl", - "default_materials": "re3D Greengate rPETG;re3D rPP;" + "default_materials": "re3D rPETG;re3D rPP;" } diff --git a/resources/profiles/re3D/machine/re3D Terabot 4 0.4 nozzle.json b/resources/profiles/re3D/machine/re3D Terabot 4 0.4 nozzle.json index 105b0f2621..d24ba564a2 100644 --- a/resources/profiles/re3D/machine/re3D Terabot 4 0.4 nozzle.json +++ b/resources/profiles/re3D/machine/re3D Terabot 4 0.4 nozzle.json @@ -6,7 +6,7 @@ "machine_tech": "FFF", "model_id": "TB4", "printer_model": "re3D Terabot 4", - "bed_texture": "Gigabot 4_buildplate_texture.png", + "bed_texture": "re3D Terabot 4_buildplate_texture.svg", "default_materials": "re3D PETG;re3D PLA;re3D PC", "printable_area": [ "0x0", diff --git a/resources/profiles/re3D/machine/re3D Terabot 4 0.8 nozzle.json b/resources/profiles/re3D/machine/re3D Terabot 4 0.8 nozzle.json index bd83a5ef45..6255e84896 100644 --- a/resources/profiles/re3D/machine/re3D Terabot 4 0.8 nozzle.json +++ b/resources/profiles/re3D/machine/re3D Terabot 4 0.8 nozzle.json @@ -6,7 +6,7 @@ "machine_tech": "FFF", "model_id": "TB4", "printer_model": "re3D Terabot 4", - "bed_texture": "Gigabot 4_buildplate_texture.png", + "bed_texture": "re3D Terabot 4_buildplate_texture.svg", "default_materials": "re3D PETG;re3D PLA;re3D PC", "printable_area": [ "0x0", diff --git a/resources/profiles/re3D/machine/re3D TerabotX 2 0.8 nozzle.json b/resources/profiles/re3D/machine/re3D TerabotX 2 0.8 nozzle.json index daa97c2e88..5622a813c1 100644 --- a/resources/profiles/re3D/machine/re3D TerabotX 2 0.8 nozzle.json +++ b/resources/profiles/re3D/machine/re3D TerabotX 2 0.8 nozzle.json @@ -6,7 +6,7 @@ "machine_tech": "FGF", "model_id": "re3D TBX2", "printer_model": "re3D TerabotX 2", - "bed_texture": "Gigabot 4_buildplate_texture.png", + "bed_texture": "re3D TerabotX 2_buildplate_texture.svg", "printable_area": [ "0x0", "892x0", @@ -25,7 +25,7 @@ "0.3" ], "default_filament_profile": [ - "re3D Greengate rPETG @0.8 nozzle" + "re3D rPETG @0.8 nozzle" ], "default_print_profile": "0.6 Standard", "printer_settings_id": "re3d_tbx2_08", diff --git a/resources/profiles/re3D/machine/re3D TerabotX 2 1.75 nozzle.json b/resources/profiles/re3D/machine/re3D TerabotX 2 1.75 nozzle.json index 401833977a..398ab006bd 100644 --- a/resources/profiles/re3D/machine/re3D TerabotX 2 1.75 nozzle.json +++ b/resources/profiles/re3D/machine/re3D TerabotX 2 1.75 nozzle.json @@ -7,7 +7,7 @@ "machine_tech": "FGF", "model_id": "re3D TBX2", "printer_model": "re3D TerabotX 2", - "bed_texture": "Gigabot 4_buildplate_texture.png", + "bed_texture": "re3D TerabotX 2_buildplate_texture.svg", "printable_area": [ "0x0", "892x0", @@ -26,7 +26,7 @@ "0.6" ], "default_filament_profile": [ - "re3D Greengate rPETG @1.75 nozzle" + "re3D rPETG @1.75 nozzle" ], "default_print_profile": "1.0 Standard", "printer_settings_id": "re3d_tbx2_175", diff --git a/resources/profiles/re3D/machine/re3D TerabotX 2.json b/resources/profiles/re3D/machine/re3D TerabotX 2.json index 9d8d0b2cb4..f541a62ad7 100644 --- a/resources/profiles/re3D/machine/re3D TerabotX 2.json +++ b/resources/profiles/re3D/machine/re3D TerabotX 2.json @@ -9,5 +9,5 @@ "bed_model": "", "bed_texture": "re3D TerabotX 2_buildplate_texture.svg", "hotend_model": "GBX-HOTEND.stl", - "default_materials": "re3D Greengate rPETG;re3D rPP;" + "default_materials": "re3D rPETG;re3D rPP;" } diff --git a/resources/profiles/re3D/process/0.26mm Standard @re3D fdm 0.4.json b/resources/profiles/re3D/process/0.26mm Standard @re3D fdm 0.4.json index 7d443c9730..2ab80cdf26 100644 --- a/resources/profiles/re3D/process/0.26mm Standard @re3D fdm 0.4.json +++ b/resources/profiles/re3D/process/0.26mm Standard @re3D fdm 0.4.json @@ -22,5 +22,35 @@ "top_surface_line_width": "0.48", "support_line_width": "0.48", "support_top_z_distance": "0.2", - "support_bottom_z_distance": "0.2" -} \ No newline at end of file + "support_bottom_z_distance": "0.2", + "bridge_speed": "50", + "internal_bridge_speed": "150%", + "default_acceleration": "5000", + "outer_wall_speed": "60", + "initial_layer_speed": "50", + "gap_infill_speed": "60", + "sparse_infill_speed": "80", + "inner_wall_speed": "80", + "internal_solid_infill_speed": "80", + "support_interface_speed": "30", + "support_speed": "90", + "top_surface_speed": "50", + "travel_speed": "300", + "top_surface_acceleration": "2500", + "initial_layer_acceleration": "1000", + "travel_acceleration": "5000", + "inner_wall_acceleration": "5000", + "ironing_speed": "25", + "overhang_1_4_speed": "0", + "overhang_2_4_speed": "50", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "10", + "initial_layer_infill_speed": "50", + "outer_wall_acceleration": "2500", + "bridge_acceleration": "3500", + "sparse_infill_acceleration": "5000", + "internal_solid_infill_acceleration": "5000", + "initial_layer_travel_speed": "100%", + "small_perimeter_speed": "50%", + "filename_format": "{input_filename_base}_{\"E\"}{initial_tool}_{filament_type[initial_tool]}_{print_time}.gcode" +} diff --git a/resources/profiles/re3D/process/0.2mm Fine @re3D fdm 0.4.json b/resources/profiles/re3D/process/0.2mm Fine @re3D fdm 0.4.json index 2734cf3334..10013e9c36 100644 --- a/resources/profiles/re3D/process/0.2mm Fine @re3D fdm 0.4.json +++ b/resources/profiles/re3D/process/0.2mm Fine @re3D fdm 0.4.json @@ -22,5 +22,32 @@ "top_surface_line_width": "0.44", "support_line_width": "0.48", "support_top_z_distance": "0.2", - "support_bottom_z_distance": "0.2" -} \ No newline at end of file + "support_bottom_z_distance": "0.2", + "outer_wall_speed": "60", + "initial_layer_speed": "50", + "gap_infill_speed": "60", + "sparse_infill_speed": "80", + "inner_wall_speed": "80", + "internal_solid_infill_speed": "80", + "support_interface_speed": "30", + "support_speed": "90", + "top_surface_speed": "50", + "travel_speed": "300", + "top_surface_acceleration": "2500", + "initial_layer_acceleration": "1000", + "travel_acceleration": "5000", + "inner_wall_acceleration": "5000", + "ironing_speed": "25", + "overhang_1_4_speed": "0", + "overhang_2_4_speed": "50", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "10", + "initial_layer_infill_speed": "50", + "outer_wall_acceleration": "2500", + "bridge_acceleration": "3500", + "sparse_infill_acceleration": "5000", + "internal_solid_infill_acceleration": "5000", + "initial_layer_travel_speed": "100%", + "small_perimeter_speed": "50%", + "filename_format": "{input_filename_base}_{\"E\"}{initial_tool}_{filament_type[initial_tool]}_{print_time}.gcode" +} diff --git a/resources/profiles/re3D/process/0.32mm Draft @re3D fdm 0.4.json b/resources/profiles/re3D/process/0.32mm Draft @re3D fdm 0.4.json index 3ce98e2e7e..1b14349f81 100644 --- a/resources/profiles/re3D/process/0.32mm Draft @re3D fdm 0.4.json +++ b/resources/profiles/re3D/process/0.32mm Draft @re3D fdm 0.4.json @@ -22,5 +22,32 @@ "top_surface_line_width": "0.48", "support_line_width": "0.48", "support_top_z_distance": "0.35", - "support_bottom_z_distance": "0.35" -} \ No newline at end of file + "support_bottom_z_distance": "0.35", + "outer_wall_speed": "60", + "initial_layer_speed": "50", + "gap_infill_speed": "60", + "sparse_infill_speed": "80", + "inner_wall_speed": "80", + "internal_solid_infill_speed": "80", + "support_interface_speed": "30", + "support_speed": "90", + "top_surface_speed": "50", + "travel_speed": "300", + "top_surface_acceleration": "2500", + "initial_layer_acceleration": "1000", + "travel_acceleration": "5000", + "inner_wall_acceleration": "5000", + "ironing_speed": "25", + "overhang_1_4_speed": "0", + "overhang_2_4_speed": "50", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "10", + "initial_layer_infill_speed": "50", + "outer_wall_acceleration": "2500", + "bridge_acceleration": "3500", + "sparse_infill_acceleration": "5000", + "internal_solid_infill_acceleration": "5000", + "initial_layer_travel_speed": "100%", + "small_perimeter_speed": "50%", + "filename_format": "{input_filename_base}_{\"E\"}{initial_tool}_{filament_type[initial_tool]}_{print_time}.gcode" +} diff --git a/resources/profiles/re3D/process/0.3mm Fine @re3D fdm 0.8.json b/resources/profiles/re3D/process/0.3mm Fine @re3D fdm 0.8.json index 27c2452d19..2b35f2c1f8 100644 --- a/resources/profiles/re3D/process/0.3mm Fine @re3D fdm 0.8.json +++ b/resources/profiles/re3D/process/0.3mm Fine @re3D fdm 0.8.json @@ -22,5 +22,32 @@ "top_surface_line_width": "1", "support_line_width": "1", "support_top_z_distance": "0.24", - "support_bottom_z_distance": "0.24" -} \ No newline at end of file + "support_bottom_z_distance": "0.24", + "outer_wall_speed": "60", + "initial_layer_speed": "50", + "gap_infill_speed": "60", + "sparse_infill_speed": "80", + "inner_wall_speed": "80", + "internal_solid_infill_speed": "80", + "support_interface_speed": "30", + "support_speed": "90", + "top_surface_speed": "50", + "travel_speed": "300", + "top_surface_acceleration": "2500", + "initial_layer_acceleration": "1000", + "travel_acceleration": "5000", + "inner_wall_acceleration": "5000", + "ironing_speed": "25", + "overhang_1_4_speed": "0", + "overhang_2_4_speed": "50", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "10", + "initial_layer_infill_speed": "50", + "outer_wall_acceleration": "2500", + "bridge_acceleration": "3500", + "sparse_infill_acceleration": "5000", + "internal_solid_infill_acceleration": "5000", + "initial_layer_travel_speed": "100%", + "small_perimeter_speed": "50%", + "filename_format": "{input_filename_base}_{\"E\"}{initial_tool}_{filament_type[initial_tool]}_{print_time}.gcode" +} diff --git a/resources/profiles/re3D/process/0.4mm Draft @re3D fdm 0.8.json b/resources/profiles/re3D/process/0.4mm Draft @re3D fdm 0.8.json index d46316ef4e..d00f8bce44 100644 --- a/resources/profiles/re3D/process/0.4mm Draft @re3D fdm 0.8.json +++ b/resources/profiles/re3D/process/0.4mm Draft @re3D fdm 0.8.json @@ -22,5 +22,32 @@ "top_surface_line_width": "1", "support_line_width": "1", "support_top_z_distance": "0.42", - "support_bottom_z_distance": "0.42" -} \ No newline at end of file + "support_bottom_z_distance": "0.42", + "outer_wall_speed": "60", + "initial_layer_speed": "50", + "gap_infill_speed": "60", + "sparse_infill_speed": "80", + "inner_wall_speed": "80", + "internal_solid_infill_speed": "80", + "support_interface_speed": "30", + "support_speed": "90", + "top_surface_speed": "50", + "travel_speed": "300", + "top_surface_acceleration": "2500", + "initial_layer_acceleration": "1000", + "travel_acceleration": "5000", + "inner_wall_acceleration": "5000", + "ironing_speed": "25", + "overhang_1_4_speed": "0", + "overhang_2_4_speed": "50", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "10", + "initial_layer_infill_speed": "50", + "outer_wall_acceleration": "2500", + "bridge_acceleration": "3500", + "sparse_infill_acceleration": "5000", + "internal_solid_infill_acceleration": "5000", + "initial_layer_travel_speed": "100%", + "small_perimeter_speed": "50%", + "filename_format": "{input_filename_base}_{\"E\"}{initial_tool}_{filament_type[initial_tool]}_{print_time}.gcode" +} diff --git a/resources/profiles/re3D/process/fdm_process_common.json b/resources/profiles/re3D/process/fdm_process_common.json index 164ff9d58a..dcd5c826ae 100644 --- a/resources/profiles/re3D/process/fdm_process_common.json +++ b/resources/profiles/re3D/process/fdm_process_common.json @@ -6,34 +6,27 @@ "adaptive_layer_height": "0", "reduce_crossing_wall": "0", "bridge_flow": "0.95", - "bridge_speed": "10", "brim_width": "5", "compatible_printers": [], "print_sequence": "by layer", - "default_acceleration": "0", "bridge_no_support": "0", "elefant_foot_compensation": "0.1", "outer_wall_line_width": "0.4", - "outer_wall_speed": "25", "line_width": "0.4", "infill_direction": "45", "sparse_infill_density": "15%", "sparse_infill_pattern": "crosshatch", "initial_layer_line_width": "0.4", "initial_layer_print_height": "0.2", - "initial_layer_speed": "15", - "gap_infill_speed": "25", "infill_combination": "0", "sparse_infill_line_width": "0.4", "infill_wall_overlap": "25%", - "sparse_infill_speed": "70", "interface_shells": "0", "detect_overhang_wall": "0", "reduce_infill_retraction": "0", "filename_format": "{input_filename_base}.gcode", "wall_loops": "3", "inner_wall_line_width": "0.4", - "inner_wall_speed": "40", "print_settings_id": "", "raft_layers": "0", "seam_position": "nearest", @@ -41,7 +34,6 @@ "skirt_height": "2", "minimum_sparse_infill_area": "0", "internal_solid_infill_line_width": "0.4", - "internal_solid_infill_speed": "60", "spiral_mode": "0", "standby_temperature_delta": "-20", "enable_support": "0", @@ -53,16 +45,12 @@ "support_interface_loop_pattern": "0", "support_interface_top_layers": "2", "support_interface_spacing": "0", - "support_interface_speed": "80", "support_base_pattern": "rectilinear", "support_base_pattern_spacing": "2", - "support_speed": "40", "support_threshold_angle": "30", "support_object_xy_distance": "0.5", "detect_thin_wall": "0", "top_surface_line_width": "0.4", - "top_surface_speed": "35", - "travel_speed": "150", "enable_prime_tower": "1", "prime_tower_width": "60", "xy_hole_compensation": "0", diff --git a/resources/profiles/re3D/process/fdm_process_re3D_common.json b/resources/profiles/re3D/process/fdm_process_re3D_common.json index a1547448e3..ea169330f4 100644 --- a/resources/profiles/re3D/process/fdm_process_re3D_common.json +++ b/resources/profiles/re3D/process/fdm_process_re3D_common.json @@ -1,116 +1,88 @@ { - "type": "process", - "name": "fdm_process_re3D_common", - "from": "system", - "instantiation": "false", - "inherits": "fdm_process_common", - "adaptive_layer_height": "0", - "reduce_crossing_wall": "1", - "bridge_flow": "0.985", - "bridge_speed": "25", - "brim_width": "8", - "print_sequence": "by layer", - "default_acceleration": "5000", - "bridge_no_support": "0", - "elefant_foot_compensation": "0", - "outer_wall_speed": "120", - "sparse_infill_density": "15%", - "sparse_infill_pattern": "rectilinear", - "initial_layer_speed": "50", - "gap_infill_speed": "30", - "infill_combination": "0", - "infill_wall_overlap": "25%", - "sparse_infill_speed": "50", - "detect_overhang_wall": "1", - "reduce_infill_retraction": "0", - "filename_format": "{input_filename_base}.gcode", - "wall_loops": "3", - "inner_wall_speed": "40", - "wall_generator": "arachne", - "raft_layers": "0", - "seam_position": "nearest", - "skirt_distance": "8", - "skirt_height": "1", - "minimum_sparse_infill_area": "0", - "internal_solid_infill_speed": "40", - "spiral_mode": "0", - "standby_temperature_delta": "-75", - "enable_support": "1", - "support_filament": "0", - "support_interface_filament": "0", - "support_on_build_plate_only": "0", - "support_interface_loop_pattern": "0", - "support_interface_top_layers": "2", - "support_interface_spacing": "0.05", - "support_interface_speed": "80", - "support_base_pattern": "rectilinear", - "support_base_pattern_spacing": "2", - "support_speed": "40", - "support_threshold_angle": "30", - "support_object_xy_distance": "0.5", - "detect_thin_wall": "0", - "top_surface_speed": "30", - "travel_speed": "300", - "enable_prime_tower": "0", - "prime_tower_width": "60", - "xy_hole_compensation": "0", - "xy_contour_compensation": "0", - "max_travel_detour_distance": "0", - "bottom_surface_pattern": "monotonic", - "bottom_shell_layers": "3", - "bottom_shell_thickness": "0", - "brim_object_gap": "0.1", - "compatible_printers_condition": "", - "top_surface_acceleration": "500", - "draft_shield": "disabled", - "enable_arc_fitting": "1", - "wall_infill_order": "inner wall/outer wall/infill", - "infill_direction": "45", - "initial_layer_acceleration": "500", - "travel_acceleration": "5000", - "inner_wall_acceleration": "5000", - "interface_shells": "0", - "ironing_flow": "10%", - "ironing_spacing": "0.1", - "ironing_speed": "20", - "ironing_type": "no ironing", - "overhang_1_4_speed": "45", - "overhang_2_4_speed": "35", - "overhang_3_4_speed": "25", - "overhang_4_4_speed": "15", - "print_settings_id": "fdm_process_re3D_common", - "skirt_loops": "2", - "resolution": "0.0", - "support_type": "normal(auto)", - "support_style": "snug", - "support_interface_bottom_layers": "2", - "tree_support_branch_angle": "45", - "tree_support_wall_count": "0", - "top_surface_pattern": "monotonicline", - "top_shell_layers": "4", - "top_shell_thickness": "0.6", - "initial_layer_infill_speed": "50", - "wipe_tower_no_sparse_layers": "0", - "precise_outer_wall": "0", - "outer_wall_acceleration": "2500", - "bridge_acceleration": "5000", - "sparse_infill_acceleration": "5000", - "internal_solid_infill_acceleration": "5000", - "accel_to_decel_enable": "0", - "prime_volume": "200", - "ooze_prevention": "1", - "preheat_time": "30", - "initial_layer_travel_speed": "100", - "slow_down_layers": "2", - "small_perimeter_speed": "20", - "small_perimeter_threshold": "10", - "exclude_object": "1", - "compatible_printers": [ - "re3D Gigabot 4 0.4 nozzle", - "re3D Gigabot 4 0.8 nozzle", - "re3D Gigabot 4 XLT 0.4 nozzle", - "re3D Gigabot 4 XLT 0.8 nozzle", - "re3D Terabot 4 0.4 nozzle", - "re3D Terabot 4 0.8 nozzle" - ] -} \ No newline at end of file + "type": "process", + "name": "fdm_process_re3D_common", + "from": "system", + "instantiation": "false", + "inherits": "fdm_process_common", + "adaptive_layer_height": "0", + "reduce_crossing_wall": "1", + "bridge_flow": "0.985", + "brim_width": "8", + "print_sequence": "by layer", + "bridge_no_support": "0", + "elefant_foot_compensation": "0", + "sparse_infill_density": "15%", + "sparse_infill_pattern": "rectilinear", + "infill_combination": "0", + "infill_wall_overlap": "25%", + "detect_overhang_wall": "1", + "reduce_infill_retraction": "0", + "filename_format": "{input_filename_base}.gcode", + "wall_loops": "3", + "wall_generator": "arachne", + "raft_layers": "0", + "seam_position": "nearest", + "skirt_distance": "8", + "skirt_height": "1", + "minimum_sparse_infill_area": "0", + "spiral_mode": "0", + "standby_temperature_delta": "-75", + "enable_support": "1", + "support_filament": "0", + "support_interface_filament": "0", + "support_on_build_plate_only": "0", + "support_interface_loop_pattern": "0", + "support_interface_top_layers": "2", + "support_interface_spacing": "0.05", + "support_base_pattern": "rectilinear", + "support_base_pattern_spacing": "2", + "support_threshold_angle": "30", + "support_object_xy_distance": "0.5", + "detect_thin_wall": "0", + "enable_prime_tower": "0", + "prime_tower_width": "60", + "xy_hole_compensation": "0", + "xy_contour_compensation": "0", + "max_travel_detour_distance": "0", + "bottom_surface_pattern": "monotonic", + "bottom_shell_layers": "3", + "bottom_shell_thickness": "0", + "brim_object_gap": "0.1", + "compatible_printers_condition": "", + "draft_shield": "disabled", + "enable_arc_fitting": "1", + "wall_infill_order": "inner wall/outer wall/infill", + "infill_direction": "45", + "interface_shells": "0", + "ironing_flow": "10%", + "ironing_spacing": "0.1", + "ironing_type": "no ironing", + "print_settings_id": "fdm_process_re3D_common", + "skirt_loops": "2", + "resolution": "0.0", + "support_type": "normal(auto)", + "support_style": "snug", + "support_interface_bottom_layers": "2", + "tree_support_branch_angle": "45", + "tree_support_wall_count": "0", + "top_surface_pattern": "monotonicline", + "top_shell_layers": "4", + "top_shell_thickness": "0.6", + "wipe_tower_no_sparse_layers": "0", + "precise_outer_wall": "0", + "accel_to_decel_enable": "0", + "prime_volume": "200", + "ooze_prevention": "1", + "preheat_time": "30", + "slow_down_layers": "2", + "small_perimeter_threshold": "10", + "exclude_object": "1", + "compatible_printers": [ + "re3D Gigabot 4 0.4 nozzle", + "re3D Gigabot 4 0.8 nozzle", + "re3D Gigabot 4 XLT 0.4 nozzle", + "re3D Gigabot 4 XLT 0.8 nozzle", + "re3D Terabot 4 0.4 nozzle", + "re3D Terabot 4 0.8 nozzle" + ] +} diff --git a/resources/shaders/140/gouraud.fs b/resources/shaders/140/gouraud.fs index 728b7f942c..e099984b46 100644 --- a/resources/shaders/140/gouraud.fs +++ b/resources/shaders/140/gouraud.fs @@ -1,4 +1,7 @@ #version 140 +// Multisample depth texture for the anti-aliased outline (see 3DScene.cpp render_with_outline). +// Optional on the GLSL 140 path: if unavailable, fallback to a non-multisample depth texture. +#extension GL_ARB_texture_multisample : enable const vec3 ZERO = vec3(0.0, 0.0, 0.0); //BBS: add grey and orange @@ -36,7 +39,14 @@ uniform SlopeDetection slope; //BBS: add outline_color uniform bool is_outline; +// The outline is a per-fragment discard mask, which the framebuffer MSAA cannot smooth, so the +// silhouette is resolved per sample from a multisample copy of the outlined model's depth buffer. +#ifdef GL_ARB_texture_multisample +uniform sampler2DMS depth_tex; +uniform int msaa_samples; // samples in depth_tex, 1 when MSAA is off +#else uniform sampler2D depth_tex; +#endif uniform vec2 screen_size; #ifdef ENABLE_ENVIRONMENT_MAP @@ -99,45 +109,87 @@ float GetTolerance(float d, float k) return -k*(d+A)*(d+A)/B; } -float DetectSilho(vec2 fragCoord, vec2 dir) +// Depth of sample s at integer pixel coord. +#ifdef GL_ARB_texture_multisample +float FetchDepth(ivec2 coord, int s) +{ + // texelFetch has no wrap mode, so clamp to the edge texel (sampler2D used CLAMP_TO_EDGE). + ivec2 sz = textureSize(depth_tex); + return abs(texelFetch(depth_tex, clamp(coord, ivec2(0), sz - 1), s).r); +} +#else +float FetchDepth(ivec2 coord, int s) +{ + return abs(texture(depth_tex, (vec2(coord) + 0.5) / screen_size).r); +} +#endif + +float DetectSilho(ivec2 coord, ivec2 dir, int s) { // ------------------------------------------- - // x0 ___ x1----o - // :\ : + // x0 ___ x1----o + // :\ : // r0 : \ : r1 - // : \ : + // : \ : // o---x2 ___ x3 // // r0 and r1 are the differences between actual // and expected (as if x0..3 where on the same // plane) depth values. // ------------------------------------------- - - float x0 = abs(texture(depth_tex, (fragCoord + dir*-2.0) / screen_size).r); - float x1 = abs(texture(depth_tex, (fragCoord + dir*-1.0) / screen_size).r); - float x2 = abs(texture(depth_tex, (fragCoord + dir* 0.0) / screen_size).r); - float x3 = abs(texture(depth_tex, (fragCoord + dir* 1.0) / screen_size).r); - + float x0 = FetchDepth(coord + dir*-2, s); + float x1 = FetchDepth(coord + dir*-1, s); + float x2 = FetchDepth(coord, s); + float x3 = FetchDepth(coord + dir* 1, s); + float d0 = (x1-x0); float d1 = (x2-x3); - + float r0 = x1 + d0 - x2; float r1 = x2 + d1 - x1; - - float tol = GetTolerance(x2, 0.04); - - return smoothstep(0.0, tol*tol, max( - r0*r1, 0.0)); + float tol = GetTolerance(x2, 0.04); + + return smoothstep(0.0, tol*tol, max( - r0*r1, 0.0)); } -float DetectSilho(vec2 fragCoord) +float DetectSilho(ivec2 coord, int s) { return max( - DetectSilho(fragCoord, vec2(1,0)), // Horizontal - DetectSilho(fragCoord, vec2(0,1)) // Vertical + DetectSilho(coord, ivec2(1,0), s), // Horizontal + DetectSilho(coord, ivec2(0,1), s) // Vertical ); } +// Full response of one sample. Reduce the max() per sample and average only afterwards: +// max(mean) <= mean(max), and averaging first hollows out diagonal and curved lines. +float DetectSilhoSample(ivec2 coord, int s) +{ + float v = DetectSilho(coord, s); + // Makes silhouettes thicker. + for (int i = 1; i <= INFLATE; ++i) + { + v = max(v, DetectSilho(coord + ivec2(i, 0), s)); + v = max(v, DetectSilho(coord + ivec2(0, i), s)); + } + return v; +} + +// Average the per-sample coverage into the sub-pixel anti-aliasing of the line. +float DetectSilho(vec2 fragCoord) +{ + ivec2 coord = ivec2(fragCoord); +#ifdef GL_ARB_texture_multisample + int n = max(msaa_samples, 1); +#else + const int n = 1; +#endif + float acc = 0.0; + for (int s = 0; s < n; ++s) + acc += DetectSilhoSample(coord, s); + return acc / float(n); +} + // Returns a lighting multiplier in [1 - shadow_intensity, 1]: < 1 where the fragment is // occluded from the light in the shadow map. 3x3 PCF softens the edges. float shadow_shade() @@ -224,14 +276,7 @@ void main() //BBS: add outline_color if (is_outline) { color = vec4((vec3(intensity.y) + color.rgb * intensity.x) * shade, color.a); - vec2 fragCoord = gl_FragCoord.xy; - float s = DetectSilho(fragCoord); - // Makes silhouettes thicker. - for(int i=1;i<=INFLATE; i++) - { - s = max(s, DetectSilho(fragCoord.xy + vec2(i, 0))); - s = max(s, DetectSilho(fragCoord.xy + vec2(0, i))); - } + float s = DetectSilho(gl_FragCoord.xy); if (s < 0.01) discard; out_color = vec4(mix(color.rgb, getBackfaceColor(color.rgb), s), color.a); diff --git a/resources/shaders/140/phong.fs b/resources/shaders/140/phong.fs index bbde72592c..f847763658 100644 --- a/resources/shaders/140/phong.fs +++ b/resources/shaders/140/phong.fs @@ -1,4 +1,7 @@ #version 140 +// Multisample depth texture for the anti-aliased outline (see 3DScene.cpp render_with_outline). +// Optional on the GLSL 140 path: if unavailable, fallback to a non-multisample depth texture. +#extension GL_ARB_texture_multisample : enable const vec3 ZERO = vec3(0.0, 0.0, 0.0); const vec3 LightRed = vec3(0.78, 0.0, 0.0); @@ -51,7 +54,14 @@ uniform SlopeDetection slope; //BBS: add outline_color uniform bool is_outline; +// The outline is a per-fragment discard mask, which the framebuffer MSAA cannot smooth, so the +// silhouette is resolved per sample from a multisample copy of the outlined model's depth buffer. +#ifdef GL_ARB_texture_multisample +uniform sampler2DMS depth_tex; +uniform int msaa_samples; // samples in depth_tex, 1 when MSAA is off +#else uniform sampler2D depth_tex; +#endif uniform vec2 screen_size; #ifdef ENABLE_ENVIRONMENT_MAP @@ -100,12 +110,27 @@ float GetTolerance(float d, float k) return -k*(d+A)*(d+A)/B; } -float DetectSilho(vec2 fragCoord, vec2 dir) +// Depth of sample s at integer pixel coord. +#ifdef GL_ARB_texture_multisample +float FetchDepth(ivec2 coord, int s) { - float x0 = abs(texture(depth_tex, (fragCoord + dir*-2.0) / screen_size).r); - float x1 = abs(texture(depth_tex, (fragCoord + dir*-1.0) / screen_size).r); - float x2 = abs(texture(depth_tex, (fragCoord + dir* 0.0) / screen_size).r); - float x3 = abs(texture(depth_tex, (fragCoord + dir* 1.0) / screen_size).r); + // texelFetch has no wrap mode, so clamp to the edge texel (sampler2D used CLAMP_TO_EDGE). + ivec2 sz = textureSize(depth_tex); + return abs(texelFetch(depth_tex, clamp(coord, ivec2(0), sz - 1), s).r); +} +#else +float FetchDepth(ivec2 coord, int s) +{ + return abs(texture(depth_tex, (vec2(coord) + 0.5) / screen_size).r); +} +#endif + +float DetectSilho(ivec2 coord, ivec2 dir, int s) +{ + float x0 = FetchDepth(coord + dir*-2, s); + float x1 = FetchDepth(coord + dir*-1, s); + float x2 = FetchDepth(coord, s); + float x3 = FetchDepth(coord + dir* 1, s); float d0 = (x1-x0); float d1 = (x2-x3); @@ -116,17 +141,45 @@ float DetectSilho(vec2 fragCoord, vec2 dir) float tol = GetTolerance(x2, 0.04); return smoothstep(0.0, tol*tol, max( - r0*r1, 0.0)); - } -float DetectSilho(vec2 fragCoord) +float DetectSilho(ivec2 coord, int s) { return max( - DetectSilho(fragCoord, vec2(1,0)), - DetectSilho(fragCoord, vec2(0,1)) + DetectSilho(coord, ivec2(1,0), s), + DetectSilho(coord, ivec2(0,1), s) ); } +// Full response of one sample. Reduce the max() per sample and average only afterwards: +// max(mean) <= mean(max), and averaging first hollows out diagonal and curved lines. +float DetectSilhoSample(ivec2 coord, int s) +{ + float v = DetectSilho(coord, s); + // Makes silhouettes thicker. + for (int i = 1; i <= INFLATE; ++i) + { + v = max(v, DetectSilho(coord + ivec2(i, 0), s)); + v = max(v, DetectSilho(coord + ivec2(0, i), s)); + } + return v; +} + +// Average the per-sample coverage into the sub-pixel anti-aliasing of the line. +float DetectSilho(vec2 fragCoord) +{ + ivec2 coord = ivec2(fragCoord); +#ifdef GL_ARB_texture_multisample + int n = max(msaa_samples, 1); +#else + const int n = 1; +#endif + float acc = 0.0; + for (int s = 0; s < n; ++s) + acc += DetectSilhoSample(coord, s); + return acc / float(n); +} + float compute_ssao_factor(vec3 normal, vec3 view_dir, vec3 eye_pos) { vec3 normal_dx = dFdx(normal); @@ -270,13 +323,7 @@ void main() if (is_outline) { vec3 shaded_rgb = (vec3(specular) + window_reflection + color.rgb * diffuse) * PHONG_BRIGHTNESS * shade; vec4 shaded_color = vec4(clamp(shaded_rgb, vec3(0.0), vec3(1.0)), color.a); - vec2 fragCoord = gl_FragCoord.xy; - float s = DetectSilho(fragCoord); - for(int i=1;i<=INFLATE; i++) - { - s = max(s, DetectSilho(fragCoord.xy + vec2(i, 0))); - s = max(s, DetectSilho(fragCoord.xy + vec2(0, i))); - } + float s = DetectSilho(gl_FragCoord.xy); if (s < 0.01) discard; out_color = vec4(mix(shaded_color.rgb, getBackfaceColor(shaded_color.rgb), s), shaded_color.a); diff --git a/resources/web/dialog/PluginsDialog/index.js b/resources/web/dialog/PluginsDialog/index.js index ea081a23aa..ad1242e4f9 100644 --- a/resources/web/dialog/PluginsDialog/index.js +++ b/resources/web/dialog/PluginsDialog/index.js @@ -602,15 +602,17 @@ function SourceLabel(source) { return "Mine"; case "subscribed": return "Subscribed"; + case "orphaned": + return "Orphaned"; default: return "Local"; } } -// Shared Local/Subscribed/Mine pill, used both after the row name and in the info panel. +// Shared source pill, used both after the row name and in the info panel. function SourceBadge(source) { const normalized = String(source || "").toLowerCase(); - const variant = (normalized === "mine" || normalized === "subscribed") ? normalized : "local"; + const variant = (normalized === "mine" || normalized === "subscribed" || normalized === "orphaned") ? normalized : "local"; const badge = document.createElement("span"); badge.className = `plugin-source-badge source-${variant}`; badge.textContent = SourceLabel(source); @@ -654,7 +656,7 @@ function LabelCell(plugin, isExpanded = false, capabilityCount = 0, nameRanges = const labelCell = document.createElement("span"); labelCell.className = "label-cell"; - const hasCloudLink = plugin.source === "mine" || plugin.source === "subscribed"; + const hasCloudLink = plugin.source === "mine" || plugin.source === "subscribed" || plugin.source === "orphaned"; const pluginLabelText = plugin.label || plugin.name || plugin.plugin_id || ""; const canExpand = capabilityCount > 0; @@ -705,7 +707,7 @@ function LabelCell(plugin, isExpanded = false, capabilityCount = 0, nameRanges = function SourceCell(plugin) { const cell = document.createElement("span"); const normalized = String(plugin.source || "").toLowerCase(); - const variant = (normalized === "mine" || normalized === "subscribed") ? normalized : "local"; + const variant = (normalized === "mine" || normalized === "subscribed" || normalized === "orphaned") ? normalized : "local"; cell.className = `source-cell source-${variant}`; const sourceLabel = document.createElement("span"); @@ -1233,7 +1235,7 @@ function RenderDescription(plugin) { return; } - const isCloud = plugin && (plugin.source === "mine" || plugin.source === "subscribed"); + const isCloud = plugin && (plugin.source === "mine" || plugin.source === "subscribed" || plugin.source === "orphaned"); if (isCloud && String(plugin?.sharing_token || "")) { node.appendChild(document.createTextNode("View on OrcaCloud ")); const link = document.createElement("a"); @@ -1370,6 +1372,13 @@ function RenderDetailSummary(container, plugin) { message.textContent = errorText || StatusDescription(plugin); container.appendChild(message); + if (plugin.orphaned === true) { + const warning = document.createElement("div"); + warning.className = "detail-description detail-warning-text"; + warning.textContent = "Orphaned: This plugin is no longer subscribed or available in OrcaCloud. The local copy remains installed and can still be used."; + container.appendChild(warning); + } + const updateStatus = GetUpdateStatus(plugin); if (updateStatus === "update_available") { const note = document.createElement("div"); diff --git a/resources/web/dialog/PluginsDialog/styles.css b/resources/web/dialog/PluginsDialog/styles.css index b1c3caa055..3d8c18be9e 100644 --- a/resources/web/dialog/PluginsDialog/styles.css +++ b/resources/web/dialog/PluginsDialog/styles.css @@ -251,6 +251,11 @@ body.pane-resizing { font-weight: 600; } +.source-cell.source-orphaned { + color: var(--plugin-status-warn); + font-weight: 600; +} + .source-cell.source-local { color: var(--plugin-source-neutral-text); } @@ -648,6 +653,10 @@ body.pane-resizing { color: var(--plugin-status-danger); } +.detail-warning-text { + color: var(--plugin-status-warn); +} + .detail-status-chip { display: inline-flex; align-items: center; @@ -915,6 +924,11 @@ body.pane-resizing { color: var(--plugin-source-subscribed-text); } +.plugin-source-badge.source-orphaned { + background: var(--plugin-status-warn-bg); + color: var(--plugin-status-warn); +} + .plugin-cloud-link { color: var(--plugin-link-text); cursor: pointer; diff --git a/scripts/msix/AppxManifest.xml b/scripts/msix/AppxManifest.xml index 62b2216c5a..fd4c89edb0 100644 --- a/scripts/msix/AppxManifest.xml +++ b/scripts/msix/AppxManifest.xml @@ -2,11 +2,13 @@ + IgnorableNamespaces="uap uap3 rescap rescap3 desktop desktop6 virtualization"> + + + + + + + + + + + + + + diff --git a/scripts/orca_extra_profile_check.py b/scripts/orca_extra_profile_check.py index cdfc8544a4..07ce3d69d3 100644 --- a/scripts/orca_extra_profile_check.py +++ b/scripts/orca_extra_profile_check.py @@ -46,12 +46,16 @@ def no_duplicates_object_pairs_hook(pairs): return seen # NOTE: currently Orca expects compatible_printers to be a defined in every instantiation profile, inheritation is not supported in Profile page -def check_filament_compatible_printers(vendor_folder): +def check_filament_compatible_printers(vendor, vendor_folder): """ Checks JSON files in the vendor folder for missing or empty 'compatible_printers' when 'instantiation' is flagged as true. + In the OrcaFilamentLibrary 'compatible_printers' is optional: a profile without it is generic and + offered on every printer, while a profile that lists printers supersedes the generic one there. + Parameters: + vendor (str): The vendor name the folder belongs to. vendor_folder (str or Path): The directory to search for JSON profile files. Returns: @@ -115,7 +119,7 @@ def check_filament_compatible_printers(vendor_folder): for profile in profiles.values(): instantiation = str(profile['content'].get("instantiation", "")).lower() == "true" - if instantiation: + if instantiation and vendor != 'OrcaFilamentLibrary': try: compatible_printers = get_property(profile, "compatible_printers") if not compatible_printers or (isinstance(compatible_printers, list) and not compatible_printers): @@ -571,7 +575,7 @@ def main(): vendor_path = profiles_dir / vendor_name if args.check_filaments or not (args.check_materials and not args.check_filaments): - errors_found += check_filament_compatible_printers(vendor_path / "filament") + errors_found += check_filament_compatible_printers(vendor_name, vendor_path / "filament") if args.check_materials: new_errors, new_warnings = check_machine_default_materials(profiles_dir, vendor_name) diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index e0a15209a3..71d6ffde80 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -7054,7 +7054,7 @@ int CLI::run(int argc, char **argv) gcode_viewer.render_calibration_thumbnail(*calibration_data, cali_thumbnail_width, cali_thumbnail_height, calibration_params, partplate_list, opengl_mgr); //generate_calibration_thumbnail(*calibration_data, thumbnail_width, thumbnail_height, calibration_params); - //*plate_bboxes[index] = p->generate_first_layer_bbox(); + // *plate_bboxes[index] = p->generate_first_layer_bbox(); calibration_thumbnails.push_back(calibration_data);*/ PlateBBoxData* plate_bbox = new PlateBBoxData(); diff --git a/src/libslic3r/AABBMesh.cpp b/src/libslic3r/AABBMesh.cpp index a23fd69f68..be026f69d7 100644 --- a/src/libslic3r/AABBMesh.cpp +++ b/src/libslic3r/AABBMesh.cpp @@ -54,12 +54,12 @@ public: int & i, Eigen::Matrix &closest) { - size_t idx_unsigned = 0; - Vec3d closest_vec3d(closest); - double dist = + size_t idx_unsigned { 0 }; + Vec3d closest_vec3d { Vec3d::Zero() }; + const double dist { AABBTreeIndirect::squared_distance_to_indexed_triangle_set( its.vertices, its.indices, m_tree, point, idx_unsigned, - closest_vec3d); + closest_vec3d) }; i = int(idx_unsigned); closest = closest_vec3d; return dist; @@ -311,10 +311,9 @@ AABBMesh::hit_result IndexedMesh::filter_hits( double AABBMesh::squared_distance(const Vec3d &p, int& i, Vec3d& c) const { - double sqdst = 0; - Eigen::Matrix pp = p; - Eigen::Matrix cc; - sqdst = m_aabb->squared_distance(*m_tm, pp, i, cc); + const Eigen::Matrix pp { p }; + Eigen::Matrix cc { Vec3d::Zero() }; + const double sqdst { m_aabb->squared_distance(*m_tm, pp, i, cc) }; c = cc; return sqdst; } diff --git a/src/libslic3r/AABBTreeLines.hpp b/src/libslic3r/AABBTreeLines.hpp index 97ad1bdf44..52c4cdf545 100644 --- a/src/libslic3r/AABBTreeLines.hpp +++ b/src/libslic3r/AABBTreeLines.hpp @@ -31,8 +31,9 @@ namespace AABBTreeLines { inline VectorType closest_point_to_origin(size_t primitive_index, ScalarType& squared_distance) const { Vec nearest_point; + Vec cast_origin = origin.template cast(); const LineType& line = lines[primitive_index]; - squared_distance = line_alg::distance_to_squared(line, origin.template cast(), &nearest_point); + squared_distance = line_alg::distance_to_squared(line, cast_origin, &nearest_point); return nearest_point.template cast(); } }; diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index dcbead0ddd..a5d0e24eac 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -202,10 +202,25 @@ void AppConfig::set_defaults() if (get("seq_top_layer_only").empty()) set("seq_top_layer_only", "1"); - // ORCA: darken layers below the current one while scrubbing the preview (ported from preFlight) + // ORCA: darken the layers the preview layer slider is not scrubbed to if (get("preview_dim_previous_layers").empty()) set_bool("preview_dim_previous_layers", false); + // ORCA: brightness of those dimmed layers, in percent. 0 = black, capped at 99 because + // 100 would render them unchanged, which is what disabling the option already does + if (get("preview_dim_previous_layers_brightness").empty()) + set("preview_dim_previous_layers_brightness", "40"); + else { + int brightness = 40; + try { + brightness = std::stoi(get("preview_dim_previous_layers_brightness")); + } + catch (...) { + brightness = 40; + } + set("preview_dim_previous_layers_brightness", std::to_string(std::max(0, std::min(brightness, 99)))); + } + if (get("filaments_area_preferred_count").empty()) set("filaments_area_preferred_count", "10"); @@ -611,6 +626,12 @@ void AppConfig::set_defaults() set_bool("window_buttons_on_left", false); #endif + if (get("use_printer_agents").empty()) + { + // false = legacy behavior using print hosts + set_bool("use_printer_agents", false); + } + // Remove legacy window positions/sizes erase("app", "main_frame_maximized"); erase("app", "main_frame_pos"); @@ -862,7 +883,7 @@ std::string AppConfig::load() } } } - } catch(std::exception err) { + } catch(const std::exception &err) { BOOST_LOG_TRIVIAL(info) << format("parse app config \"%1%\", error: %2%", AppConfig::loading_path(), err.what()); return err.what(); diff --git a/src/libslic3r/Arachne/WallToolPaths.hpp b/src/libslic3r/Arachne/WallToolPaths.hpp index dde3dc785f..d7120a088c 100644 --- a/src/libslic3r/Arachne/WallToolPaths.hpp +++ b/src/libslic3r/Arachne/WallToolPaths.hpp @@ -23,14 +23,14 @@ inline coord_t meshfix_maximum_extrusion_area_deviation() { return scaled> - BoundingBoxBase(It from, It to) + BoundingBoxBase(It from, It to) : BoundingBoxBase() { construct(*this, from, to); } BoundingBoxBase(const PointsType &points) diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp index 6473dc5c21..9cee5a0e4b 100644 --- a/src/libslic3r/Brim.cpp +++ b/src/libslic3r/Brim.cpp @@ -32,15 +32,13 @@ static void append_and_translate(ExPolygons &dst, const ExPolygons &src, const P for (; dst_idx < dst.size(); ++dst_idx) dst[dst_idx].translate(instance_shift); } -// BBS: generate brim area by objs -static void append_and_translate(ExPolygons& dst, const ExPolygons& src, - const PrintInstance& instance, size_t instance_idx, std::map& brimAreaMap) { +// Orca: Translate the brim area into print coordinates and store it per instance. +static void append_and_translate(const ExPolygons& src, const PrintInstance& instance, + size_t instance_idx, std::map& brimAreaMap) { ExPolygons srcShifted = src; Point instance_shift = instance.shift_without_plate_offset(); - for (size_t src_idx = 0; src_idx < srcShifted.size(); ++src_idx) - srcShifted[src_idx].translate(instance_shift); - srcShifted = diff_ex(srcShifted, dst); - //expolygons_append(dst, temp2); + for (ExPolygon& expoly : srcShifted) + expoly.translate(instance_shift); expolygons_append(brimAreaMap[{ instance.print_object->id(), instance_idx }], std::move(srcShifted)); } @@ -351,7 +349,7 @@ static ExPolygons make_brim_ears_auto(const ExPolygons& obj_expoly, coord_t size return mouse_ears_ex; } -static ExPolygons make_brim_ears(const PrintObject* object, const double& flowWidth, float brim_offset, Flow &flow, bool is_outer_brim) +static ExPolygons make_brim_ears(const PrintObject* object) { ExPolygons mouse_ears_ex; BrimPoints brim_ear_points = object->model_object()->brim_points; @@ -375,12 +373,7 @@ static ExPolygons make_brim_ears(const PrintObject* object, const double& flowWi Vec3f world_pos = pt.transform(trsf.get_matrix()); if ( world_pos.z() > 0) continue; Polygon point_round; - float brim_width = floor(scale_(pt.head_front_radius) / flowWidth / 2) * flowWidth * 2; - if (is_outer_brim) { - double flowWidthScale = flowWidth / SCALING_FACTOR; - brim_width = floor(brim_width / flowWidthScale / 2) * flowWidthScale * 2; - } - coord_t size_ear = (brim_width - brim_offset - flow.scaled_spacing()); + const coord_t size_ear = scale_(pt.head_front_radius); for (size_t i = 0; i < POLY_SIDE_COUNT; i++) { double angle = (2.0 * PI * i) / POLY_SIDE_COUNT; point_round.points.emplace_back(size_ear * cos(angle), size_ear * sin(angle)); @@ -454,7 +447,8 @@ static ExPolygons outer_inner_brim_area(const Print& print, bool has_brim_auto = object->config().brim_type == btAutoBrim; const bool use_auto_brim_ears = object->config().brim_type == btEar; const bool use_brim_ears = object->config().brim_type == btPainted; - const bool has_inner_brim = brim_type == btInnerOnly || brim_type == btOuterAndInner || use_auto_brim_ears || use_brim_ears; + const bool use_inner_brim_ears = (use_auto_brim_ears || use_brim_ears) && !object->config().brim_ears_outer_only.value; + const bool has_inner_brim = brim_type == btInnerOnly || brim_type == btOuterAndInner || use_inner_brim_ears; const bool has_outer_brim = brim_type == btOuterOnly || brim_type == btOuterAndInner || brim_type == btAutoBrim || use_auto_brim_ears || use_brim_ears; coord_t ear_detection_length = scale_(object->config().brim_ears_detection_length.value); coordf_t brim_ears_max_angle = object->config().brim_ears_max_angle.value; @@ -533,7 +527,7 @@ static ExPolygons outer_inner_brim_area(const Print& print, auto innerExpoly = offset_ex(ex_poly.contour, brim_offset, jtRound, SCALED_RESOLUTION); ExPolygons outerExpoly; if (use_brim_ears) { - outerExpoly = make_brim_ears(object, flowWidth, brim_offset, flow, true); + outerExpoly = make_brim_ears(object); //outerExpoly = offset_ex(outerExpoly, brim_width_mod, jtRound, SCALED_RESOLUTION); } else if (use_auto_brim_ears) { coord_t size_ear = (brim_width_mod - brim_offset - flow.scaled_spacing()); @@ -547,7 +541,7 @@ static ExPolygons outer_inner_brim_area(const Print& print, ExPolygons outerExpoly; auto innerExpoly = offset_ex(ex_poly_holes_reversed, -brim_width - brim_offset); if (use_brim_ears) { - outerExpoly = make_brim_ears(object, flowWidth, brim_offset, flow, false); + outerExpoly = make_brim_ears(object); } else if (use_auto_brim_ears) { coord_t size_ear = (brim_width - brim_offset - flow.scaled_spacing()); outerExpoly = make_brim_ears_auto(offset_ex(ex_poly_holes_reversed, -brim_offset), size_ear, ear_detection_length, brim_ears_max_angle, false); @@ -572,7 +566,7 @@ static ExPolygons outer_inner_brim_area(const Print& print, for (size_t instance_idx = 0; instance_idx < object->instances().size(); ++instance_idx) { const PrintInstance& instance = object->instances()[instance_idx]; if (!brim_area_object.empty()) - append_and_translate(brim_area, brim_area_object, instance, instance_idx, brimAreaMap); + append_and_translate(brim_area_object, instance, instance_idx, brimAreaMap); append_and_translate(no_brim_area, no_brim_area_object, instance); append_and_translate(holes, holes_object, instance); append_and_translate(objectIslands, objectIsland, instance); @@ -875,6 +869,14 @@ void make_brim(const Print& print, PrintTryCancel try_cancel, Polygons& islands_ ExPolygons islands_area_ex = outer_inner_brim_area(print, float(flow.scaled_spacing()), brimAreaMap, objPrintVec, printExtruders); + if (!print.config().combine_brims) { + ExPolygons claimed_area; + for (auto& [_, areas] : brimAreaMap) { + areas = diff_ex(areas, claimed_area); + expolygons_append(claimed_area, areas); + } + } + // BBS: Find boundingbox of the first layer for (const ObjectID printObjID : print.print_object_ids()) { BoundingBox bbx; diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index da36321b6f..ef93f0d509 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -2,6 +2,7 @@ #define slic3r_Config_hpp_ #include +#include #include #include #include @@ -780,10 +781,14 @@ public: this->values[i] = rhs_vec->values[i]; modified = true; } else { - if ((i < default_index.size()) && (default_index[i] < default_value.size())) + // Orca: a negative slot (failed variant lookup) must not silently collapse the + // whole array to the first slot's value — the int-vs-size_t comparison used to + // promote -1 past the bounds check. Keep the slot's own value (get_at-style + // clamp) when no valid index is available. + if ((i < default_index.size()) && (default_index[i] >= 0) && (size_t(default_index[i]) < default_value.size())) this->values[i] = default_value[default_index[i]]; else - this->values[i] = default_value[0]; + this->values[i] = default_value[std::min(i, default_value.size() - 1)]; } } return modified; @@ -2106,6 +2111,11 @@ public: throw ConfigurationError("ConfigOptionEnumGeneric: Assigning an incompatible type"); // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum this->value = rhs->getInt(); + // Orca: options embedded in a StaticPrintConfig are constructed without a keys_map; + // adopt the source's so a later serialize() can emit names. + if (this->keys_map == nullptr) + if (auto rhs_generic = dynamic_cast(rhs)) + this->keys_map = rhs_generic->keys_map; } std::string serialize() const override @@ -2162,7 +2172,12 @@ public: if (rhs->type() != this->type()) throw ConfigurationError("ConfigOptionEnumGeneric: Assigning an incompatible type"); // rhs could be of the following type: ConfigOptionEnumsGeneric - this->values = dynamic_cast(rhs)->values; + auto rhs_enums = dynamic_cast(rhs); + this->values = rhs_enums->values; + // Orca: options embedded in a StaticPrintConfig are constructed without a keys_map; + // adopt the source's so a later serialize() emits names instead of empty tokens. + if (this->keys_map == nullptr) + this->keys_map = rhs_enums->keys_map; } std::string serialize() const override @@ -2258,6 +2273,8 @@ public: plugin_picker, // Raw JSON string value, edited through a dialog behind a button rather than in the row. plugin_config, + // PrinterAgentChoice + printer_agent_select, }; // Identifier of this option. It is stored here so that it is accessible through the by_serialization_key_ordinal map. @@ -2965,6 +2982,8 @@ public: const double & opt_float(const t_config_option_key &opt_key, unsigned int idx) const; double & opt_float_nullable(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } const double & opt_float_nullable(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } + FloatOrPercent & opt_float_or_percent_nullable(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } + const FloatOrPercent & opt_float_or_percent_nullable(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } int& opt_int(const t_config_option_key &opt_key) { return this->option(opt_key)->value; } int opt_int(const t_config_option_key &opt_key) const { return dynamic_cast(this->option(opt_key))->value; } diff --git a/src/libslic3r/Extruder.cpp b/src/libslic3r/Extruder.cpp index 1e250b707e..b1b6ca347a 100644 --- a/src/libslic3r/Extruder.cpp +++ b/src/libslic3r/Extruder.cpp @@ -220,12 +220,12 @@ double Extruder::retract_restart_extra() const double Extruder::retract_length_toolchange() const { - return m_config->retract_length_toolchange.get_at(extruder_id()); + return m_config->retract_length_toolchange.get_at(m_config_index); } double Extruder::retract_restart_extra_toolchange() const { - return m_config->retract_restart_extra_toolchange.get_at(extruder_id()); + return m_config->retract_restart_extra_toolchange.get_at(m_config_index); } double Extruder::travel_slope() const diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index f29d4ef3fd..88d87ddb26 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -278,6 +278,9 @@ struct SurfaceFillParams // For Gyroid: when true, use the parameterized "optimized" wave. bool gyroid_optimized = false; + // Orca: corner smoothing factor in the range [0, 1]. + double smooth_factor { 0. }; + CenterOfSurfacePattern center_of_surface_pattern{CenterOfSurfacePattern::Each_Surface}; bool separated_infills{false}; @@ -316,6 +319,7 @@ struct SurfaceFillParams RETURN_COMPARE_NON_EQUAL(skin_infill_depth); RETURN_COMPARE_NON_EQUAL(infill_overhang_angle); RETURN_COMPARE_NON_EQUAL(gyroid_optimized); + RETURN_COMPARE_NON_EQUAL(smooth_factor); RETURN_COMPARE_NON_EQUAL(center_of_surface_pattern); RETURN_COMPARE_NON_EQUAL(separated_infills); RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, fill_order); @@ -348,6 +352,7 @@ struct SurfaceFillParams this->center_of_surface_pattern == rhs.center_of_surface_pattern && this->separated_infills == rhs.separated_infills && this->gyroid_optimized == rhs.gyroid_optimized && + this->smooth_factor == rhs.smooth_factor && this->fill_order == rhs.fill_order; } }; @@ -964,6 +969,11 @@ std::vector group_fills(const Layer &layer, LockRegionParam &lock_p params.angle = calculate_infill_rotation_angle(layer.object(), layer.id(), region_config.infill_direction.value, region_config.sparse_infill_rotate_template.value); params.fixed_angle = !region_config.sparse_infill_rotate_template.value.empty(); + + // Orca: special case; apply smoothing factor only for Hilbert Curve sparse infill. + // FillHilbertCurve::generate clamps and validates the value itself. + if (params.pattern == ipHilbertCurve) + params.smooth_factor = 0.01 * region_config.sparse_infill_smooth_factor.value; } else { const bool top_layer_direction_set = surface.is_top() && region_config.top_layer_direction.value >= 0.; const bool bottom_layer_direction_set = surface.is_bottom() && region_config.bottom_layer_direction.value >= 0.; @@ -1328,6 +1338,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: params.lateral_lattice_angle_2 = surface_fill.params.lateral_lattice_angle_2; params.infill_overhang_angle = surface_fill.params.infill_overhang_angle; params.gyroid_optimized = surface_fill.params.gyroid_optimized; + params.smooth_factor = surface_fill.params.smooth_factor; // BBS params.flow = surface_fill.params.flow; @@ -1569,6 +1580,7 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc params.infill_overhang_angle = surface_fill.params.infill_overhang_angle; params.multiline = surface_fill.params.multiline; params.gyroid_optimized = surface_fill.params.gyroid_optimized; + params.smooth_factor = surface_fill.params.smooth_factor; for (ExPolygon &expoly : surface_fill.expolygons) { // Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon. diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 2606529099..45157ec42d 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -1857,12 +1857,12 @@ static inline void base_support_extend_infill_lines(Polylines &infill, BoundaryI const bool first = graph.first(cp); int extend_next_idx = -1; int extend_prev_idx = -1; - coord_t dist_y_prev; - coord_t dist_y_next; - double arc_len_prev; - double arc_len_next; + coord_t dist_y_prev = 0; + coord_t dist_y_next = 0; + double arc_len_prev = 0; + double arc_len_next = 0; - if (! graph.next_vertical(cp)){ + if (! graph.next_vertical(cp)) { size_t i = cp.point_idx; size_t j = next_idx_modulo(i, contour); while (j != cp.next_on_contour->point_idx) { diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index 8128b9c9d1..d50c29b332 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -82,6 +82,9 @@ struct FillParams // For Gyroid: when true, use the parameterized "optimized" variant. bool gyroid_optimized { false }; + // Orca: corner smoothing factor in the range [0, 1]. + double smooth_factor { 0. }; + // For Lateral lattice coordf_t lateral_lattice_angle_1 { 0.f }; coordf_t lateral_lattice_angle_2 { 0.f }; diff --git a/src/libslic3r/Fill/FillPlanePath.cpp b/src/libslic3r/Fill/FillPlanePath.cpp index 7ce8e4abb3..7c4f285ac6 100644 --- a/src/libslic3r/Fill/FillPlanePath.cpp +++ b/src/libslic3r/Fill/FillPlanePath.cpp @@ -114,12 +114,12 @@ void FillPlanePath::_fill_surface_single( // Filling in a bounding box over the whole object, clip generated polyline against the snug bounding box. snug_bounding_box.translate(-shift.x(), -shift.y()); InfillPolylineClipper output(snug_bounding_box, distance_between_lines); - this->generate(min_x, min_y, max_x, max_y, resolution, output); + this->generate(min_x, min_y, max_x, max_y, resolution, params, output); polyline.points = std::move(output.result()); } else { // Filling in a snug bounding box, no need to clip. InfillPolylineOutput output(distance_between_lines); - this->generate(min_x, min_y, max_x, max_y, resolution, output); + this->generate(min_x, min_y, max_x, max_y, resolution, params, output); polyline.points = std::move(output.result()); } } @@ -288,6 +288,147 @@ static void generate_hilbert_curve(coord_t min_x, coord_t min_y, coord_t max_x, } } +using QuinticBezier = std::array; + +static bool is_bezier_flat(const QuinticBezier &curve, const double deviation) +{ + // A Bezier curve stays inside the convex hull of its control points. Therefore, keeping every + // control point within a deviation-wide strip around the endpoint chord conservatively bounds the + // flattening error. The cross product is the perpendicular distance scaled by the chord length; + // comparing squared values avoids a square root. + const Vec2d chord = curve.back() - curve.front(); + const double chord_length_sq = chord.squaredNorm(); + const double max_cross_sq = deviation * deviation * chord_length_sq; + + for (size_t i = 1; i + 1 < curve.size(); ++i) { + const Vec2d offset = curve[i] - curve.front(); + const double cross = chord.x() * offset.y() - chord.y() * offset.x(); + if (cross * cross > max_cross_sq) + return false; + } + return true; +} + +static void subdivide_bezier(const QuinticBezier &curve, QuinticBezier &left, QuinticBezier &right) +{ + // Split the curve at t = 0.5 using de Casteljau's algorithm. Each averaging level contributes one + // control point to the left half and one to the right half; the latter is filled backwards to keep + // both resulting control polygons in their original parameter direction. + QuinticBezier subdivision = curve; + left.front() = subdivision.front(); + right.back() = subdivision.back(); + for (size_t level = 1; level < curve.size(); ++level) { + for (size_t i = 0; i + level < curve.size(); ++i) + subdivision[i] = 0.5 * (subdivision[i] + subdivision[i + 1]); + left[level] = subdivision.front(); + right[curve.size() - level - 1] = subdivision[curve.size() - level - 1]; + } +} + +static void flatten_bezier(const QuinticBezier &curve, const double deviation, std::vector &output) +{ + // Subdivide to at least depth 1 so a rounded corner cannot collapse to a single diagonal chord. + // A uniform subdivision depth keeps samples at equal parameter intervals t = k / 2^depth, + // avoiding abrupt segment-length jumps at adaptive-depth boundaries. + static constexpr size_t max_depth = 16; + + std::vector subcurves(2); + subdivide_bezier(curve, subcurves[0], subcurves[1]); + + for (size_t depth = 1; depth < max_depth; ++depth) { + bool all_flat = true; + for (const QuinticBezier &c : subcurves) + if (!is_bezier_flat(c, deviation)) { + all_flat = false; + break; + } + if (all_flat) + break; + std::vector finer(subcurves.size() * 2); + for (size_t i = 0; i < subcurves.size(); ++i) + subdivide_bezier(subcurves[i], finer[i * 2], finer[i * 2 + 1]); + subcurves = std::move(finer); + } + + // The curve start is deliberately omitted so consecutive curve pieces can share it without duplication. + output.reserve(output.size() + subcurves.size()); + for (const QuinticBezier &c : subcurves) + output.emplace_back(c.back()); +} + +template +static void generate_smooth_hilbert_curve( + coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, + const double corner_distance, Output &output) +{ + // A Hilbert curve is defined on a square grid whose side is a power of two. As in the unsmoothed + // generator, expand the larger requested dimension to the next valid Hilbert grid size. The output + // clipper or the later region intersection removes the padded part of the traversal. + size_t sz = 2; + const size_t sz0 = std::max(max_x + 1 - min_x, max_y + 1 - min_y); + while (sz < sz0) + sz <<= 1; + + const size_t point_count = sz * sz; + output.reserve(point_count); + + // The caller normalizes resolution to the unit Hilbert grid; retain a finite positive tolerance + // if this helper is invoked with an invalid resolution. + const double deviation = resolution > 0. && std::isfinite(resolution) ? resolution : EPSILON; + // Construct one canonical 90-degree corner from (-corner_distance, 0) to (0, corner_distance). + // At each end, the first three control points are collinear and equally spaced: the tangent follows + // the adjoining straight leg and the second derivative is zero. The endpoint curvature is therefore + // zero, giving G2 joins to both legs. Every Hilbert turn is an oriented copy of this curve, so flatten + // it only once to the requested chordal-deviation tolerance. + const QuinticBezier corner_curve {{ + {-corner_distance, 0.}, {-0.7 * corner_distance, 0.}, {-0.4 * corner_distance, 0.}, + {0., 0.4 * corner_distance}, {0., 0.7 * corner_distance}, {0., corner_distance} + }}; + std::vector curve_coefficients; + flatten_bezier(corner_curve, deviation, curve_coefficients); + + auto translated_point = [min_x, min_y](size_t idx) { + Point p = hilbert_n_to_xy(idx); + return Point(p.x() + min_x, p.y() + min_y); + }; + auto to_vec2d = [](const Point &p) { return Vec2d(double(p.x()), double(p.y())); }; + bool has_last_output = false; + Vec2d last_output; + // Fully smoothed adjacent corners may meet at the same segment midpoint. Suppress such duplicates + // to avoid emitting zero-length extrusion segments. + auto add_point = [&output, &has_last_output, &last_output](const Vec2d &point) { + if (!has_last_output || point.x() != last_output.x() || point.y() != last_output.y()) { + output.add_point(point); + last_output = point; + has_last_output = true; + } + }; + + Vec2d previous = to_vec2d(translated_point(0)); + Vec2d corner = to_vec2d(translated_point(1)); + add_point(previous); + // Replace each non-collinear Hilbert vertex by the canonical curve expressed in the local basis of + // its incoming and outgoing unit vectors. Collinear vertices remain part of the straight polyline. + for (size_t i = 1; i + 1 < point_count; ++i) { + const Vec2d next = to_vec2d(translated_point(i + 1)); + const Vec2d incoming = (corner - previous).normalized(); + const Vec2d outgoing = (next - corner).normalized(); + const double cross = incoming.x() * outgoing.y() - incoming.y() * outgoing.x(); + + if (std::abs(cross) < EPSILON) { + add_point(corner); + } else { + add_point(corner - corner_distance * incoming); + for (const Vec2d &coefficient : curve_coefficients) + add_point(corner + coefficient.x() * incoming + coefficient.y() * outgoing); + } + + previous = corner; + corner = next; + } + add_point(corner); +} + void FillHilbertCurve::generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double /* resolution */, InfillPolylineOutput &output) { if (output.clips()) @@ -296,6 +437,24 @@ void FillHilbertCurve::generate(coord_t min_x, coord_t min_y, coord_t max_x, coo generate_hilbert_curve(min_x, min_y, max_x, max_y, output); } +void FillHilbertCurve::generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, + const FillParams ¶ms, InfillPolylineOutput &output) +{ + const double smooth_factor = std::isfinite(params.smooth_factor) ? + std::clamp(params.smooth_factor, 0., 1.) : 0.; + if (smooth_factor == 0.) { + this->generate(min_x, min_y, max_x, max_y, resolution, output); + return; + } + + const double corner_distance = 0.5 * smooth_factor; + if (output.clips()) + generate_smooth_hilbert_curve( + min_x, min_y, max_x, max_y, resolution, corner_distance, static_cast(output)); + else + generate_smooth_hilbert_curve(min_x, min_y, max_x, max_y, resolution, corner_distance, output); +} + template static void generate_octagram_spiral(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, Output &output) { diff --git a/src/libslic3r/Fill/FillPlanePath.hpp b/src/libslic3r/Fill/FillPlanePath.hpp index 1371e8506a..b4b25b73ae 100644 --- a/src/libslic3r/Fill/FillPlanePath.hpp +++ b/src/libslic3r/Fill/FillPlanePath.hpp @@ -53,6 +53,11 @@ protected: friend class InfillPolylineClipper; virtual void generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, InfillPolylineOutput &output) = 0; + virtual void generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, + const FillParams & /* params */, InfillPolylineOutput &output) + { + this->generate(min_x, min_y, max_x, max_y, resolution, output); + } }; class FillArchimedeanChords : public FillPlanePath @@ -75,6 +80,8 @@ public: protected: bool centered() const override { return false; } void generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, InfillPolylineOutput &output) override; + void generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, + const FillParams ¶ms, InfillPolylineOutput &output) override; }; class FillOctagramSpiral : public FillPlanePath diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp index 138b50bc88..8b40b8753c 100644 --- a/src/libslic3r/Fill/FillRectilinear.cpp +++ b/src/libslic3r/Fill/FillRectilinear.cpp @@ -3576,7 +3576,7 @@ Polylines FillLateralHoneycomb::fill_surface(const Surface *surface, const FillP // | // | // 0 --+-- - // / \ + // ⟋ ⟍ // why inverted? // it makes determining some of the properties easier // and the two angled legs provide additional horizontal stiffness diff --git a/src/libslic3r/Format/STEP.cpp b/src/libslic3r/Format/STEP.cpp index 8b07286c5b..f82ced7d86 100644 --- a/src/libslic3r/Format/STEP.cpp +++ b/src/libslic3r/Format/STEP.cpp @@ -712,7 +712,7 @@ unsigned int Step::get_triangle_num(double linear_deflection, double angle_defle return 0; } } - } catch(Exception e) { + } catch(const Exception &e) { return 0; } diff --git a/src/libslic3r/Format/STEP.hpp b/src/libslic3r/Format/STEP.hpp index 1a65d5956b..336fd79766 100644 --- a/src/libslic3r/Format/STEP.hpp +++ b/src/libslic3r/Format/STEP.hpp @@ -78,7 +78,7 @@ public: Standard_Boolean UserBreak() override { return should_stop.load(); } void Show(const Message_ProgressScope&, const Standard_Boolean) override { - std::cout << "Progress: " << GetPosition() << "%" << std::endl; + std::cout << "Progress: " << std::fixed << std::setprecision(2) << 100.0 * GetPosition() << "%" << std::endl; } private: std::atomic& should_stop; diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 5b0ce2f716..18d805936e 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -13,6 +13,7 @@ #include "GCode/PrintExtents.hpp" #include "GCode/Thumbnails.hpp" #include "GCode/WipeTower.hpp" +#include "GCode/WipeTower2.hpp" #include "ShortestPath.hpp" #include "GCode/OrderingStrategies.hpp" #include "Print.hpp" @@ -767,30 +768,31 @@ static std::vector get_path_of_change_filament(const Print& print) return changes; } + // Clearance the tower-approach router keeps around the tower: the avoid box is + // inflated by this much before routing, and the inflated corners must stay on the + // bed for a route to be generated at all. + static constexpr float wipe_tower_routing_clearance = 2.f; + // BBS // start_pos refers to the last position before the wipe_tower. // end_pos refers to the wipe tower's start_pos. // using the print coordinate system - Polyline WipeTowerIntegration::generate_path_to_wipe_tower(const Point& start_pos,const Point &end_pos , const BoundingBox& avoid_polygon , const BoundingBox& printer_bbx) const + Polyline WipeTowerIntegration::generate_path_to_wipe_tower(const Point& start_pos,const Point &end_pos , const BoundingBox& avoid_polygon , const Polygons& bed_polygons) const { Polyline res; - coord_t alpha = scaled(2.f); // offset distance + coord_t alpha = scaled(wipe_tower_routing_clearance); // offset distance BoundingBox avoid_polygon_inner = avoid_polygon; avoid_polygon_inner.offset(alpha); coord_t width = avoid_polygon_inner.max[0] - avoid_polygon_inner.min[0]; - Polygon bed_polygon = printer_bbx.polygon(); Vec2f v(1, 0); // the first print direction of end_pos. if (abs(end_pos[0] - avoid_polygon_inner.min[0]) < width / 2) v = -v; // judge whether the wipe tower's infill goes to the left or right. - // Judge whether the avoid_polygon_inner is outside the printer_bbx. + // Judge whether the avoid_polygon_inner is outside the bed. The real printable + // outline is tested (not its bounding box), so on circular/custom beds corners + // hanging off the bed are rejected. // If so, do nothing and just go directly to the end_pos. - bool is_bbx_in_bed = true; Points avoid_points = avoid_polygon_inner.polygon().points; - for (auto &wipe_tower_bbx_p : avoid_points) { - if (ClipperLib::PointInPolygon(wipe_tower_bbx_p, bed_polygon.points) != 1) { - is_bbx_in_bed = false; - break; - } - } + const bool is_bbx_in_bed = std::all_of(avoid_points.begin(), avoid_points.end(), + [&bed_polygons](const Point &pt) { return contains(bed_polygons, pt, /*border_result=*/false); }); if (!is_bbx_in_bed) { res.points.push_back(end_pos); return res; @@ -889,6 +891,77 @@ static std::vector get_path_of_change_filament(const Print& print) return res; } + // Type2 tower-local point -> bed frame. The rib-wall offset is tower-local, so it + // rotates with the tower (unlike the BBL tower in append_tcr, which never rotates). + Vec2f WipeTowerIntegration::transform_wt2_pt(const Vec2f &pt) const + { + const float alpha = m_wipe_tower_rotation / 180.f * float(M_PI); + return Eigen::Rotation2Df(alpha) * (pt + m_rib_offset) + m_wipe_tower_pos; + } + + // Bed outline the tower-approach router plans against, in object coordinates. The real + // outline is returned, not its bounding box, so the router's containment tests fail off + // the bed on circular/custom shapes; the multi-nozzle narrowing lives in the accessor. + Polygons WipeTowerIntegration::shared_printable_area(GCode &gcodegen) const + { + // The frame change is a pure translation, so transform the origin once. + const Point offset = wipe_tower_point_to_object_point(gcodegen, Vec2f(m_plate_origin(0), m_plate_origin(1))); + Polygons bed_polygons = gcodegen.m_print->get_extruder_shared_printable_polygon(); + for (Polygon &poly : bed_polygons) + poly.translate(offset); + return bed_polygons; + } + + // With skip points enabled the Type2 tower wall has an opening at each toolchange's + // entry (tcr.start_pos): route the approach around the tower's bounding box so the + // nozzle enters through that opening instead of dragging across the printed wall + // (append_tcr parity). Emits only the waypoints leading up to the opening — the + // caller still travels to start_wipe_pos itself. Returns an empty string when the + // gap wall is off (option off or cone wall) or the approach already starts inside + // the tower: such hops never cross the wall and must stay direct. + std::string WipeTowerIntegration::travel_to_tower_gap(GCode &gcodegen, const Point &route_start, const Point &start_wipe_pos) const + { + if (!WipeTower2::use_gap_wall(gcodegen.m_config)) + return {}; + const Vec2f plate_origin_2d(m_plate_origin(0), m_plate_origin(1)); + // Transform tower-local corners exactly like the tcr points; a rotated tower gets a + // conservative axis-aligned envelope from the result. + auto tower_polygon = [&](const BoundingBoxf &bbx) { + Polygon poly = scaled(bbx).polygon(); + for (Point &p : poly.points) + p = wipe_tower_point_to_object_point(gcodegen, transform_wt2_pt(unscale(p).cast()) + plate_origin_2d); + return poly; + }; + // The avoid envelope covers the first-layer brim (and rib flare), which a travel may + // cross freely: early-out only when the approach already starts over the tower body + // itself, so a start between the wall and the brim edge still gets routed in through + // the wall opening. Test the rotated polygon, not its bounding box — at angles off the + // axes the box's corner triangles cover most of the brim ring. + const float body_width = gcodegen.m_config.wipe_tower_wall_type.value == WipeTowerWallType::wtwRib ? m_wipe_tower_depth : m_right; + if (tower_polygon(BoundingBoxf(Vec2d(0., 0.), Vec2d(body_width, m_wipe_tower_depth))).contains(route_start)) + return {}; + + const Polygons bed = shared_printable_area(gcodegen); + BoundingBox avoid_bbx = get_extents(tower_polygon(m_wipe_tower_bbx)); + // The inflated corners must stay on the bed for the router to generate a route at all: + // clamp the box against the bed shrunk by the clearance the router adds, so a tower + // parked near the bed edge is still routed along the clamped side instead of always + // travelling straight across the tower. + BoundingBox clamp_bbx = get_extents(bed); + clamp_bbx.offset(-(scaled(wipe_tower_routing_clearance) + SCALED_EPSILON)); + avoid_bbx.min = avoid_bbx.min.cwiseMax(clamp_bbx.min); + avoid_bbx.max = avoid_bbx.max.cwiseMin(clamp_bbx.max); + if (avoid_bbx.min.x() >= avoid_bbx.max.x() || avoid_bbx.min.y() >= avoid_bbx.max.y()) + return {}; + + Polyline travel_polyline = generate_path_to_wipe_tower(route_start, start_wipe_pos, avoid_bbx, bed); + std::string gcode; + // The polyline's last point is start_wipe_pos itself — emitted by the caller. + for (size_t i = 0; i + 1 < travel_polyline.points.size(); ++i) + gcode += gcodegen.travel_to(travel_polyline.points[i], erMixed, "Travel to a Wipe Tower"); + return gcode; + } + std::string WipeTowerIntegration::append_tcr(GCode& gcodegen, const WipeTower::ToolChangeResult& tcr, int new_filament_id, double z) const { if (new_filament_id != -1 && new_filament_id != tcr.new_tool) @@ -999,6 +1072,7 @@ static std::vector get_path_of_change_filament(const Print& print) std::string change_filament_gcode = gcodegen.config().change_filament_gcode.value; bool is_used_travel_avoid_perimeter = gcodegen.m_config.prime_tower_skip_points.value; + if (is_nozzle_change && !tcr.nozzle_change_result.is_extruder_change) is_used_travel_avoid_perimeter = false; // add nozzle change gcode into change filament gcode std::string nozzle_change_gcode_trans; @@ -1076,8 +1150,8 @@ static std::vector get_path_of_change_filament(const Print& print) float old_retract_length = (old_filament_id != -1) ? full_config.retraction_length.get_at(old_fi) : 0; float new_retract_length = full_config.retraction_length.get_at(new_fi); - float old_retract_length_toolchange = (old_filament_id != -1) ? full_config.retract_length_toolchange.get_at(old_filament_id) : 0; - float new_retract_length_toolchange = full_config.retract_length_toolchange.get_at(new_filament_id); + float old_retract_length_toolchange = (old_filament_id != -1) ? full_config.retract_length_toolchange.get_at(old_fi) : 0; + float new_retract_length_toolchange = full_config.retract_length_toolchange.get_at(new_fi); int old_filament_temp = (old_filament_id != -1) ? (gcodegen.on_first_layer()? full_config.nozzle_temperature_initial_layer.get_at(old_fi) : full_config.nozzle_temperature.get_at(old_fi)) : 210; int new_filament_temp = gcodegen.on_first_layer() ? full_config.nozzle_temperature_initial_layer.get_at(new_fi) : full_config.nozzle_temperature.get_at(new_fi); Vec3d nozzle_pos = gcode_writer.get_position(); @@ -1261,24 +1335,7 @@ static std::vector get_path_of_change_filament(const Print& print) Vec2f gcode_last_pos2d{gcode_last_pos[0], gcode_last_pos[1]}; Point gcode_last_pos2d_object = gcodegen.gcode_to_point(gcode_last_pos2d.cast() + plate_origin_2d.cast()); Point start_wipe_pos = wipe_tower_point_to_object_point(gcodegen, tool_change_start_pos + plate_origin_2d); - BoundingBox avoid_bbx, printer_bbx; - { - // set printer_bbx - // Multi-nozzle: clamp the avoid-perimeter travel bounds to the region every - // extruder can reach (get_extruder_shared_printable_polygon) instead of the full - // bed. Gated on the multi-nozzle predicate so H2D and every existing single/dual - // printer keep the historic full-printable_area routing byte-identical. - if (is_multi_nozzle_printer(gcodegen.m_config)) { - printer_bbx = get_extents(gcodegen.m_print->get_extruder_shared_printable_polygon()); - printer_bbx.min = wipe_tower_point_to_object_point(gcodegen, unscaled(printer_bbx.min) + plate_origin_2d); - printer_bbx.max = wipe_tower_point_to_object_point(gcodegen, unscaled(printer_bbx.max) + plate_origin_2d); - } else { - Pointfs bed_pointsf = gcodegen.m_config.printable_area.values; - Points bed_points; - for (auto p : bed_pointsf) { bed_points.push_back(wipe_tower_point_to_object_point(gcodegen, p.cast() + plate_origin_2d)); } - printer_bbx = BoundingBox(bed_points); - } - } + BoundingBox avoid_bbx; { // set avoid_bbx avoid_bbx = scaled(m_wipe_tower_bbx); @@ -1290,7 +1347,7 @@ static std::vector get_path_of_change_filament(const Print& print) avoid_bbx = BoundingBox(avoid_points.points); } std::string travel_to_wipe_tower_gcode; - Polyline travel_polyline = generate_path_to_wipe_tower(gcode_last_pos2d_object, start_wipe_pos, avoid_bbx, printer_bbx); + Polyline travel_polyline = generate_path_to_wipe_tower(gcode_last_pos2d_object, start_wipe_pos, avoid_bbx, shared_printable_area(gcodegen)); for (size_t i = 0; i < travel_polyline.points.size(); ++i) { const auto &p = travel_polyline.points[i]; @@ -1308,20 +1365,23 @@ static std::vector get_path_of_change_filament(const Print& print) } // do unretract after setting current extruder_id - // PETG filaments on a device with a filament switcher get a small (2 mm) pre-extrusion - // before the tool change. has_filament_switcher is a develop-only key read defensively from the - // full config (Orca does not carry it as a static PrintConfig member — same convention as - // enable_filament_dynamic_map); no shipping profile sets it (grep resources/profiles = 0), so - // is_petg_pre_extrusion is always false -> extra_unretract stays 0 -> byte-identical to the plain - // unretract() fleet-wide. The tower-interface contact pre-extrusion length (the - // is_contact_pre_extrusion branch) is NOT applied here; it is only computed as the guard used to - // give the contact path priority over PETG. + // BBS pattern: the wipe tower shifts the toolchange start position outward for the + // tower-interface (contact) pre-extrusion and for the PETG-with-filament-switcher case; + // the pre-extrusion material itself is laid down here as extra unretract on the approach. + // has_filament_switcher is a develop-only key read defensively from the full config (Orca + // does not carry it as a static PrintConfig member — same convention as + // enable_filament_dynamic_map); no shipping profile sets it, so is_petg_pre_extrusion is + // always false fleet-wide. const ConfigOptionBool* has_filament_switcher_opt = gcodegen.m_print->full_print_config().option("has_filament_switcher"); bool is_contact_pre_extrusion = tcr.is_contact && gcodegen.m_config.enable_tower_interface_features; bool is_petg_pre_extrusion = !is_contact_pre_extrusion && gcodegen.config().filament_type.get_at(tcr.new_tool) == "PETG" && has_filament_switcher_opt && has_filament_switcher_opt->value; - float extra_unretract = is_petg_pre_extrusion ? 2.f : 0.f; + float extra_unretract = 0.f; + if (is_contact_pre_extrusion) + extra_unretract = gcodegen.m_config.filament_tower_interface_pre_extrusion_length.get_at(tcr.new_tool); + else if (is_petg_pre_extrusion) + extra_unretract = 2.f; std::string toolchange_unretract_str = (extra_unretract > 0.f) ? gcodegen.unretract(extra_unretract) : gcodegen.unretract(); check_add_eol(toolchange_unretract_str); @@ -1419,20 +1479,16 @@ static std::vector get_path_of_change_filament(const Print& print) // We want to rotate and shift all extrusions (gcode postprocessing) and starting and ending position float alpha = m_wipe_tower_rotation / 180.f * float(M_PI); - auto transform_wt_pt = [&alpha, this](const Vec2f &pt) -> Vec2f { - Vec2f out = Eigen::Rotation2Df(alpha) * pt; - out += m_wipe_tower_pos; - return out; - }; - + // Priming lines are absolute bed moves; everything else is tower-local + // (transform_wt2_pt). Vec2f start_pos = tcr.start_pos; Vec2f end_pos = tcr.end_pos; if (!tcr.priming) { - start_pos = transform_wt_pt(start_pos); - end_pos = transform_wt_pt(end_pos); + start_pos = transform_wt2_pt(start_pos); + end_pos = transform_wt2_pt(end_pos); } - Vec2f wipe_tower_offset = tcr.priming ? Vec2f::Zero() : m_wipe_tower_pos; + Vec2f wipe_tower_offset = tcr.priming ? Vec2f::Zero() : Vec2f(m_wipe_tower_pos + Eigen::Rotation2Df(alpha) * m_rib_offset); float wipe_tower_rotation = tcr.priming ? 0.f : alpha; Vec2f plate_origin_2d(m_plate_origin(0), m_plate_origin(1)); @@ -1462,16 +1518,34 @@ static std::vector get_path_of_change_filament(const Print& print) || is_ramming || tool_change_on_wipe_tower); - if (should_travel_to_tower || gcodegen.m_need_change_layer_lift_z) { + const Point start_wipe_pos = wipe_tower_point_to_object_point(gcodegen, start_pos + plate_origin_2d); + const bool travel_to_tower_now = should_travel_to_tower || gcodegen.m_need_change_layer_lift_z; + if (travel_to_tower_now) { // FIXME: It would be better if the wipe tower set the force_travel flag for all toolchanges, // then we could simplify the condition and make it more readable. - gcode += gcodegen.retract(); + + // Orca: pass the configured lift type, as append_tcr does above. lazy_lift() keeps + // the first type it is given, so the NormalLift default would pin this hop to a + // standing move. Slope and spiral both need a known head position. + LiftType lift_type = LiftType::NormalLift; + if (gcodegen.writer().filament() != nullptr && gcodegen.writer().is_current_position_clear()) { + ZHopType z_hop_type = ZHopType(gcodegen.config().z_hop_types.get_at( + gcodegen.get_filament_config_index((int) gcodegen.writer().filament()->id()))); + if (z_hop_type == ZHopType::zhtAuto) + z_hop_type = ZHopType::zhtSpiral; + lift_type = gcodegen.to_lift_type(z_hop_type); + } + gcode += gcodegen.retract(false, false, lift_type); gcodegen.m_avoid_crossing_perimeters.use_external_mp_once(); - gcode += gcodegen.travel_to(wipe_tower_point_to_object_point(gcodegen, start_pos + plate_origin_2d), erMixed, "Travel to a Wipe Tower"); + if (!tcr.priming && gcodegen.last_pos_defined()) + gcode += travel_to_tower_gap(gcodegen, gcodegen.last_pos(), start_wipe_pos); + gcode += gcodegen.travel_to(start_wipe_pos, erMixed, "Travel to a Wipe Tower"); gcode += gcodegen.unretract(); } else { // When this is multiextruder printer without any ramming, we can just change - // the tool without travelling to the tower. + // the tool without travelling to the tower. The tower entry travel then lives + // inside the tcr gcode; with skip points on it is rerouted below, once the + // toolchange gcode (and the head position it ends at) is known. } if (will_go_down) { @@ -1493,7 +1567,38 @@ static std::vector get_path_of_change_filament(const Print& print) interface_temp = gcodegen.config().nozzle_temperature_range_high.get_at(new_extruder_id); toolchange_temp_override = interface_temp; } - toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z, false, toolchange_temp_override); // TODO: toolchange_z vs print_z + toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z, false, toolchange_temp_override, + WipeTower2::wait_for_temp_enabled(gcodegen.m_config)); // TODO: toolchange_z vs print_z + if (!travel_to_tower_now && !tcr.priming && WipeTower2::use_gap_wall(gcodegen.m_config)) { + // The tool changed in place (multi-tool printer without ramming), so the + // tower entry is the tcr's own positioning move — a straight line across + // the printed wall. Route it around the tower and in through the wall + // opening instead, riding at the end of the change_filament_gcode + // substitution so the generator's positioning move degrades to a + // zero-length one (append_tcr parity: travel after the filament change, + // retracted, with the new filament). + Vec3f last_gcode_pos = gcodegen.writer().get_position().cast(); + Point route_start; + bool have_start = false; + if (GCodeProcessor::get_last_position_from_gcode(toolchange_gcode_str, last_gcode_pos)) { + // A custom change_filament_gcode may have moved the head (tool docks + // etc.); recover the real position from the emitted gcode. + route_start = gcodegen.gcode_to_point(Vec2d(last_gcode_pos.x(), last_gcode_pos.y()) + plate_origin_2d.cast()); + have_start = true; + } else if (gcodegen.last_pos_defined()) { + route_start = gcodegen.last_pos(); + have_start = true; + } + if (have_start) { + gcodegen.set_last_pos(route_start); + gcodegen.m_avoid_crossing_perimeters.use_external_mp_once(); + std::string travel = travel_to_tower_gap(gcodegen, route_start, start_wipe_pos); + travel += gcodegen.travel_to(start_wipe_pos, erMixed, "Travel to a Wipe Tower"); + check_add_eol(travel); + toolchange_gcode_str += travel; + gcodegen.set_last_pos(start_wipe_pos); + } + } if (gcodegen.config().enable_prime_tower) { deretraction_str += gcodegen.writer().travel_to_z(z, "Force restore layer Z", true); Vec3d position{gcodegen.writer().get_position()}; @@ -1614,7 +1719,7 @@ static std::vector get_path_of_change_filament(const Print& print) std::string trimmed = line; trimmed.erase(0, trimmed.find_first_not_of(" \t")); bool skip_line = false; - if (boost::starts_with(trimmed, "M109")) { + if (boost::starts_with(trimmed, "M109") && trimmed.find(WipeTower2::wait_for_temp_tag()) == std::string::npos) { bool matches_extruder = true; if (trimmed.find('T') != std::string::npos) matches_extruder = trimmed.find(t_token) != std::string::npos; @@ -1679,7 +1784,7 @@ static std::vector get_path_of_change_filament(const Print& print) // Prepare a future wipe. gcodegen.m_wipe.reset_path(); for (const Vec2f& wipe_pt : tcr.wipe_path) - gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, transform_wt_pt(wipe_pt) + plate_origin_2d)); + gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, transform_wt2_pt(wipe_pt) + plate_origin_2d)); } // Let the planner know we are traveling between objects. @@ -2793,6 +2898,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato DoExport::init_gcode_processor(print.config(), m_processor, m_silent_time_estimator_enabled, print.get_layered_nozzle_group_result()); const bool is_bbl_printers = print.is_BBL_printer(); + const bool skip_config_block = print.config().gcode_skip_config_block; const WipeTowerType wipe_tower_type = print.wipe_tower_type(); m_calib_config.clear(); // resets analyzer's tracking data @@ -2968,7 +3074,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // as configuration key / value pairs to be parsable by older versions of // PrusaSlicer G-code viewer. { - if (is_bbl_printers) { + if (is_bbl_printers && !skip_config_block) { file.write("; CONFIG_BLOCK_START\n"); std::string full_config; append_full_config(print, full_config); @@ -3995,23 +4101,25 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder) .c_str()); file.write("\n"); - file.write("; CONFIG_BLOCK_START\n"); - std::string full_config; - append_full_config(print, full_config); - if (!full_config.empty()) - file.write(full_config); + if (!skip_config_block) { + file.write("; CONFIG_BLOCK_START\n"); + std::string full_config; + append_full_config(print, full_config); + if (!full_config.empty()) + file.write(full_config); - // SoftFever: write compatiple info - int first_layer_bed_temperature = get_bed_temperature(0, true, print.config().curr_bed_type); - file.write_format("; first_layer_bed_temperature = %d\n", first_layer_bed_temperature); - file.write_format("; bed_shape = %s\n", print.full_print_config().opt_serialize("printable_area").c_str()); - file.write_format("; first_layer_temperature = %d\n", print.config().nozzle_temperature_initial_layer.get_at(0)); - file.write_format("; first_layer_height = %.3f\n", print.config().initial_layer_print_height.value); - - //SF TODO -// file.write_format("; variable_layer_height = %d\n", print.ad.adaptive_layer_height ? 1 : 0); - - file.write("; CONFIG_BLOCK_END\n\n"); + // SoftFever: write compatiple info + int first_layer_bed_temperature = get_bed_temperature(0, true, print.config().curr_bed_type); + file.write_format("; first_layer_bed_temperature = %d\n", first_layer_bed_temperature); + file.write_format("; bed_shape = %s\n", print.full_print_config().opt_serialize("printable_area").c_str()); + file.write_format("; first_layer_temperature = %d\n", print.config().nozzle_temperature_initial_layer.get_at(0)); + file.write_format("; first_layer_height = %.3f\n", print.config().initial_layer_print_height.value); + + //SF TODO +// file.write_format("; variable_layer_height = %d\n", print.ad.adaptive_layer_height ? 1 : 0); + + file.write("; CONFIG_BLOCK_END\n\n"); + } // !skip_config_block } file.write("\n"); @@ -5417,7 +5525,7 @@ LayerResult GCode::process_layer( // add tag for processor gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change) + "\n"; // export layer z - char buf[64]; + char buf[80]; sprintf(buf, print.is_BBL_printer() ? "; Z_HEIGHT: %g\n" : ";Z:%g\n", print_z); gcode += buf; // export layer height @@ -6618,6 +6726,7 @@ void GCode::append_full_config(const Print &print, std::string &str) "farthest_point_timelapse"sv, "compatible_printers"sv, "compatible_prints"sv, + "filament_colour_type"sv, "print_host"sv, "print_host_webui"sv, "printhost_apikey"sv, @@ -7542,8 +7651,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, if (sloped) { speed = std::min(speed, m_config.scarf_joint_speed.get_abs_value(speed)); } - } - else if(path.role() == erInternalBridgeInfill) { + } else if(path.role() == erInternalBridgeInfill) { speed = m_config.get_abs_value_at("internal_bridge_speed", get_nozzle_config_index(m_writer.filament()->id())); } else if (path.role() == erOverhangPerimeter || path.role() == erSupportTransition || path.role() == erBridgeInfill) { speed = NOZZLE_CONFIG(bridge_speed); @@ -7554,7 +7662,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, } else if (path.role() == erTopSolidInfill) { speed = NOZZLE_CONFIG(top_surface_speed); } else if (path.role() == erIroning) { - speed = m_config.get_abs_value("ironing_speed"); + const size_t filament_idx = get_filament_config_index(m_writer.filament()->id()); + speed = m_config.filament_ironing_speed.is_nil(filament_idx) + ? m_config.get_abs_value("ironing_speed") + : m_config.filament_ironing_speed.get_at(filament_idx); } else if (path.role() == erBottomSurface) { speed = NOZZLE_CONFIG(initial_layer_infill_speed); } else if (path.role() == erGapFill) { @@ -8845,7 +8956,7 @@ void GCode::update_placeholder_parser_with_variant_params() } } -std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bool by_object, int toolchange_temp_override) +std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bool by_object, int toolchange_temp_override, bool defer_temp_wait) { int new_extruder_id = get_extruder_id(new_filament_id); if (!m_writer.need_toolchange(new_filament_id)) @@ -8944,7 +9055,7 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo // per-layer nozzle grouping; resolve the column instead of indexing by the filament id. size_t new_fi = get_filament_config_index((int)new_filament_id); float new_retract_length = m_config.retraction_length.get_at(new_fi); - float new_retract_length_toolchange = m_config.retract_length_toolchange.get_at(new_filament_id); + float new_retract_length_toolchange = m_config.retract_length_toolchange.get_at(new_fi); int new_filament_temp = this->on_first_layer() ? m_config.nozzle_temperature_initial_layer.get_at(new_fi) : m_config.nozzle_temperature.get_at(new_fi); // BBS: if print_z == 0 use first layer temperature if (abs(print_z) < EPSILON) @@ -8952,6 +9063,24 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo if (toolchange_temp_override > 0) new_filament_temp = toolchange_temp_override; + // With wait_for_temp_on_wipe_tower the blocking M109 is deferred to the wipe tower, so raise + // the incoming filament's target here — ahead of the tool change rather than after it — and + // let the heat-up overlap the change itself as well as the travel to the tower. The command + // always carries an explicit tool index (the option is off for single extruder MM, so the + // writer emits one), leaving the outgoing filament that pre_toolchange just dropped to its + // standby temperature alone. nozzle_temperature == 0 means "use the first layer temperature". + if (defer_temp_wait) { + // Target what the tower will wait on. It waits on the first layer temperature not only on + // the first layer but also while priming, which runs before any layer is set: there + // on_first_layer() is false and print_z is the initial layer height, so neither test above + // catches it. nozzle_temperature == 0 means "use the first layer temperature" as well. + int preheat_temp = new_filament_temp; + if (toolchange_temp_override <= 0 && (m_layer == nullptr || preheat_temp <= 0)) + preheat_temp = m_config.nozzle_temperature_initial_layer.get_at(new_fi); + if (preheat_temp > 0) + gcode += m_writer.set_temperature(preheat_temp, false, new_filament_id); + } + Vec3d nozzle_pos = m_writer.get_position(); float old_retract_length, old_retract_length_toolchange, wipe_volume; int old_filament_temp, old_filament_e_feedrate; @@ -8975,7 +9104,7 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo // gap-filled carry-forward, so its current-layer column matches the nozzle it occupies. size_t old_fi = get_filament_config_index(old_filament_id); old_retract_length = m_config.retraction_length.get_at(old_fi); - old_retract_length_toolchange = m_config.retract_length_toolchange.get_at(old_filament_id); + old_retract_length_toolchange = m_config.retract_length_toolchange.get_at(old_fi); old_filament_temp = this->on_first_layer()? m_config.nozzle_temperature_initial_layer.get_at(old_fi) : m_config.nozzle_temperature.get_at(old_fi); //During the filament change, the extruder will extrude an extra length of grab_length for the corresponding detection, so the purge can reduce this length. @@ -9255,8 +9384,10 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo } check_add_eol(gcode); } - // Set the new extruder to the operating temperature. - if (m_ooze_prevention.enable) + // Set the new extruder to the operating temperature. With defer_temp_wait the target was + // already raised before the tool change and the blocking wait belongs to the wipe tower + // generator, so there is nothing left to restore here. + if (m_ooze_prevention.enable && !defer_temp_wait) gcode += m_ooze_prevention.post_toolchange(*this); if (m_config.enable_pressure_advance.get_at(new_filament_id)) { diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index fdb6f54861..6bdb04a8a9 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -130,8 +130,11 @@ public: private: WipeTowerIntegration& operator=(const WipeTowerIntegration&); std::string append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z = -1.) const; - Polyline generate_path_to_wipe_tower(const Point &start_pos, const Point &end_pos, const BoundingBox &avoid_polygon, const BoundingBox &printer_bbx) const; + Polyline generate_path_to_wipe_tower(const Point &start_pos, const Point &end_pos, const BoundingBox &avoid_polygon, const Polygons &bed_polygons) const; std::string append_tcr2(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z = -1.) const; + std::string travel_to_tower_gap(GCode &gcodegen, const Point &route_start, const Point &start_wipe_pos) const; + Vec2f transform_wt2_pt(const Vec2f &pt) const; + Polygons shared_printable_area(GCode &gcodegen) const; // Postprocesses gcode: rotates and moves G1 extrusions and returns result std::string post_process_wipe_tower_moves(const WipeTower::ToolChangeResult& tcr, const Vec2f& translation, float angle) const; @@ -181,7 +184,7 @@ struct LayerResult { // It is used for the pressure equalizer because it needs to buffer one layer back. bool nop_layer_result { false }; - static LayerResult make_nop_layer_result() { return {"", std::numeric_limits::max(), false, false, true}; } + static LayerResult make_nop_layer_result() { return {"", std::numeric_limits::max(), false, false, true}; } }; class GCode { @@ -259,7 +262,7 @@ public: std::string retract(bool toolchange = false, bool is_last_retraction = false, LiftType lift_type = LiftType::NormalLift, bool apply_instantly = false, ExtrusionRole role = erNone); // extra_retract forwards a PETG pre-extrusion over-extrusion; default 0 -> identical to the plain deretract. std::string unretract(float extra_retract = 0.f) { return m_writer.unlift() + m_writer.unretract(extra_retract); } - std::string set_extruder(unsigned int extruder_id, double print_z, bool by_object=false, int toolchange_temp_override = -1); + std::string set_extruder(unsigned int extruder_id, double print_z, bool by_object=false, int toolchange_temp_override = -1, bool defer_temp_wait = false); bool is_BBL_Printer(); WipeTowerType wipe_tower_type(); diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index cc53cd0e51..cebfe486cb 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -1450,8 +1450,8 @@ void GCodeProcessor::run_post_process() // flag) runs none of this. It is pure data construction — it only fills m_filament_blocks / // m_extruder_blocks / m_machine_*_gcode_*_line_id and never touches the exported g-code, so even // the enable_pre_heating fleet stays byte-identical (nothing reads the blocks until the injection - // pass). In practice it also stays empty/degenerate today because no template/code yet emits the - // MACHINE_*_GCODE_* / NOZZLE_CHANGE_* / CP_TOOLCHANGE_WIPE markers it keys off. + // pass). The wipe tower emits the NOZZLE_CHANGE_* (ramming) and CP_TOOLCHANGE_WIPE markers this + // builder keys off; the MACHINE_*_GCODE_* markers come from the machine g-code templates. m_filament_blocks.clear(); m_extruder_blocks.clear(); m_machine_start_gcode_end_line_id = (unsigned int) (-1); @@ -5926,8 +5926,11 @@ void GCodeProcessor::process_G10(const GCodeReader::GCodeLine& line) GCodeReader::GCodeLine g10; g10.set(Axis::E, -this->m_parser.config().retraction_length.get_at(m_extruder_id)); g10.set(Axis::F, this->m_parser.config().retraction_speed.get_at(m_extruder_id) * 60); + //Orca: Firmware retract emulation must not change the modal G1 feedrate. + const float feedrate = m_feedrate; --m_g1_line_id; process_G1(g10); + m_feedrate = feedrate; } void GCodeProcessor::process_G11(const GCodeReader::GCodeLine& line) @@ -5936,8 +5939,11 @@ void GCodeProcessor::process_G11(const GCodeReader::GCodeLine& line) GCodeReader::GCodeLine g11; g11.set(Axis::E, this->m_parser.config().retraction_length.get_at(m_extruder_id) + this->m_parser.config().retract_restart_extra.get_at(m_extruder_id)); g11.set(Axis::F, this->m_parser.config().deretraction_speed.get_at(m_extruder_id) * 60); + // Orca: Firmware unretract emulation must not change the modal G1 feedrate. + const float feedrate = m_feedrate; --m_g1_line_id; process_G1(g11); + m_feedrate = feedrate; } void GCodeProcessor::process_G20(const GCodeReader::GCodeLine& line) diff --git a/src/libslic3r/GCode/PrintExtents.cpp b/src/libslic3r/GCode/PrintExtents.cpp index 4a65ae5ae4..9008adaa9a 100644 --- a/src/libslic3r/GCode/PrintExtents.cpp +++ b/src/libslic3r/GCode/PrintExtents.cpp @@ -143,7 +143,8 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_ double wipe_tower_y = print.config().wipe_tower_y.get_at(plate_idx) + plate_origin(1); Transform2d trafo = Eigen::Translation2d(wipe_tower_x, wipe_tower_y) * - Eigen::Rotation2Dd(Geometry::deg2rad(print.config().wipe_tower_rotation_angle.value)); + Eigen::Rotation2Dd(Geometry::deg2rad(print.config().wipe_tower_rotation_angle.value)) * + Eigen::Translation2d(print.wipe_tower_data().rib_offset.cast()); // tower-local rib-wall shift, zero unless rib BoundingBoxf bbox; for (const std::vector &tool_changes : print.wipe_tower_data().tool_changes) { diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 06bca292d4..5834937169 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -3,11 +3,9 @@ #include #include #include -#include #include #include #include - #include "GCodeProcessor.hpp" #include "BoundingBox.hpp" #include "ClipperUtils.hpp" @@ -17,12 +15,16 @@ namespace Slic3r { -constexpr float flat_iron_speed = 10.f * 60.f; +float flat_iron_speed = 10.f * 60.f; static const double wipe_tower_wall_infill_overlap = 0.0; static constexpr double WIPE_TOWER_RESOLUTION = 0.1; +// Orca: SCALING_FACTOR is a runtime variable (large-printer switch), so this cannot be constexpr #define WT_SIMPLIFY_TOLERANCE_SCALED (0.001 / SCALING_FACTOR) static constexpr int arc_fit_size = 20; #define SCALED_WIPE_TOWER_RESOLUTION (WIPE_TOWER_RESOLUTION / SCALING_FACTOR) +enum class LimitFlow { None, LimitPrintFlow, LimitRammingFlow, LimitRammingFlowNC};//nc:nozzle change +static const std::map nozzle_diameter_to_nozzle_change_width{{0.2f, 0.5f}, {0.4f, 1.0f}, {0.6f, 1.2f}, {0.8f, 1.4f}}; + inline float align_round(float value, float base) { return std::round(value / base) * base; @@ -67,7 +69,7 @@ static bool is_valid_gcode(const std::string &gcode) return is_valid; } -static Polygon chamfer_polygon(Polygon &polygon, double chamfer_dis = 2., double angle_tol = 30. / 180. * PI) +Polygon chamfer_polygon(Polygon &polygon, double chamfer_dis = 2., double angle_tol = 30. / 180. * PI) { if (polygon.points.size() < 3) return polygon; Polygon res; @@ -169,7 +171,7 @@ Polygon WipeTower::rounding_polygon(Polygon &polygon, double rounding /*= 2.*/, return res; } -static Polygon rounding_rectangle(Polygon &polygon, double rounding = 2., double angle_tol = 30. / 180. * PI) { +Polygon rounding_rectangle(Polygon &polygon, double rounding = 2., double angle_tol = 30. / 180. * PI) { if (polygon.points.size() < 3) return polygon; Polygon res; res.points.reserve(polygon.points.size() * 2); @@ -226,7 +228,7 @@ static Polygon rounding_rectangle(Polygon &polygon, double rounding = 2., double return res; } -static std::pair ray_intersetion_line(const Vec2f &a, const Vec2f &v1, const Vec2f &b, const Vec2f &c) +std::pair ray_intersetion_line(const Vec2f &a, const Vec2f &v1, const Vec2f &b, const Vec2f &c) { const Vec2f v2 = c - b; double denom = cross2(v1, v2); @@ -243,19 +245,19 @@ static std::pair ray_intersetion_line(const Vec2f &a, const Vec2f & } return std::pair(false, Vec2f{0, 0}); } -static Polygon scale_polygon(const std::vector &points) { +Polygon scale_polygon(const std::vector &points) { Polygon res; for (const auto &p : points) res.points.push_back(scaled(p)); return res; } -static std::vector unscale_polygon(const Polygon& polygon) +std::vector unscale_polygon(const Polygon& polygon) { std::vector res; for (const auto &p : polygon.points) res.push_back(unscaled(p)); return res; } -static Polygon generate_rectange(const Line &line, coord_t offset) +Polygon generate_rectange(const Line &line, coord_t offset) { Point p1 = line.a; Point p2 = line.b; @@ -294,7 +296,7 @@ struct Segment bool is_valid() const { return start.y() < end.y(); } }; -static std::vector remove_points_from_segment(const Segment &segment, const std::vector &skip_points, double range) +std::vector remove_points_from_segment(const Segment &segment, const std::vector &skip_points, double range) { std::vector result; result.push_back(segment); @@ -333,7 +335,7 @@ struct PointWithFlag int pair_idx; // gap_pair idx bool is_forward; }; -static IntersectionInfo move_point_along_polygon(const std::vector &points, const Vec2f &startPoint, int startIdx, float offset, bool forward, int pair_idx) +IntersectionInfo move_point_along_polygon(const std::vector &points, const Vec2f &startPoint, int startIdx, float offset, bool forward, int pair_idx) { float remainingDistance = offset; IntersectionInfo res; @@ -395,7 +397,7 @@ static IntersectionInfo move_point_along_polygon(const std::vector &point return res; }; -static void insert_points(std::vector &pl, int idx, Vec2f pos, int pair_idx, bool is_forward) +void insert_points(std::vector &pl, int idx, Vec2f pos, int pair_idx, bool is_forward) { int next = (idx + 1) % pl.size(); Vec2f pos1 = pl[idx].pos; @@ -411,15 +413,111 @@ static void insert_points(std::vector &pl, int idx, Vec2f pos, in } } -static Polylines remove_points_from_polygon(const Polygon &polygon, const std::vector &skip_points, double range, bool is_left ,Polygon& insert_skip_pg) +// For skip_point +// TODO: Optimize the skip_point algorithm itself instead of adding guards here +Polygon add_extra_point(const Polygon &polygon, int scale_range) { - assert(polygon.size() > 2); + Polygon res; + if (polygon.size() < 2) return polygon; + + // Compute bounding box of the polygon + auto polygon_box = get_extents(polygon); + + // Anchor point: X at bbox center, Y at bbox bottom + Vec2f anchor_point(float(polygon_box.center()[0]), float(polygon_box.min[1])); + + // Find the edge whose midpoint is closest to the anchor point + size_t closest_edge_idx = 0; + float min_dist_sq = std::numeric_limits::max(); + + for (size_t i = 0; i < polygon.size(); ++i) { + const Point &a_i = polygon[i]; + const Point &b_i = polygon[(i + 1) % polygon.size()]; + + Vec2f a(float(a_i.x()), float(a_i.y())); + Vec2f b(float(b_i.x()), float(b_i.y())); + Vec2f mid = (a + b) * 0.5f; + + float dist_sq = (anchor_point - mid).squaredNorm(); + if (dist_sq < min_dist_sq) { + min_dist_sq = dist_sq; + closest_edge_idx = i; + } + } + + // Edge endpoints (integer space) + const Point &a_i = polygon[closest_edge_idx]; + const Point &b_i = polygon[(closest_edge_idx + 1) % polygon.size()]; + + // Convert to float for geometric computation + Vec2f a(float(a_i.x()), float(a_i.y())); + Vec2f b(float(b_i.x()), float(b_i.y())); + + Vec2f mid = (a + b) * 0.5f; + + // Direction vectors from midpoint towards A and B + Vec2f dir_to_a = a - mid; + Vec2f dir_to_b = b - mid; + + float len_a = dir_to_a.norm(); + float len_b = dir_to_b.norm(); + + // Guard against degenerated edges + if (len_a < EPSILON || len_b < EPSILON) return polygon; + + dir_to_a /= len_a; + dir_to_b /= len_b; + + // Clamp range to avoid overshooting the edge + float max_range = std::min(len_a, len_b) * 0.9f; + float range = std::min(float(scale_range), max_range); + + // Offset points (float space) + Vec2f offset_to_a_f = mid + dir_to_a * range; + Vec2f offset_to_b_f = mid + dir_to_b * range; + + // Safe cast back to scaled integer Point + auto to_int_point = [](const Vec2f &p) { + auto clamp = [](float v) -> coord_t { + constexpr float kMin = float(std::numeric_limits::min()); + constexpr float kMax = float(std::numeric_limits::max()); + v = std::clamp(v, kMin, kMax); + return static_cast(std::lround(v)); + }; + return Point(clamp(p.x()), clamp(p.y())); + }; + + Point mid_i = to_int_point(mid); + Point offset_to_a_i = to_int_point(offset_to_a_f); + Point offset_to_b_i = to_int_point(offset_to_b_f); + + // Rebuild polygon with inserted points + for (size_t i = 0; i < polygon.size(); ++i) { + res.points.push_back(polygon[i]); + + // Insert points right after the selected edge start vertex + if (i == closest_edge_idx) { + res.points.push_back(offset_to_a_i); + res.points.push_back(mid_i); + res.points.push_back(offset_to_b_i); + } + } + + return res; +} + + + +Polylines remove_points_from_polygon(const Polygon &polygon_ori, const std::vector &skip_points, double range, float wt_width, Polygon &insert_skip_pg) +{ + Polygon polygon = add_extra_point(polygon_ori, scale_(range)); + if (polygon.size() < 2) return Polylines{to_polyline(polygon)}; Polylines result; std::vector new_pl; // add intersection points for gaps, where bool indicates whether it's a gap point. std::vector inter_info; - Vec2f ray = is_left ? Vec2f(-1, 0) : Vec2f(1, 0); auto polygon_box = get_extents(polygon); - Point anchor_point = is_left ? Point{polygon_box.max[0], polygon_box.min[1]} : polygon_box.min; // rd:ld + //Point anchor_point = /*is_left ? Point{polygon_box.max[0], polygon_box.min[1]} :*/ polygon_box.min; // rd:ld + Point anchor_point = Point{polygon_box.center()[0], polygon_box.min[1]}; // for next reconnect std::vector points; { points.reserve(polygon.points.size()); @@ -430,6 +528,8 @@ static Polylines remove_points_from_polygon(const Polygon &polygon, const std::v } for (int i = 0; i < skip_points.size(); i++) { + bool is_left = abs(skip_points[i].x()) < wt_width / 2.f; + Vec2f ray = is_left ? Vec2f(-1, 0) : Vec2f(1, 0); for (int j = 0; j < points.size(); j++) { Vec2f& p1 = points[j]; Vec2f& p2 = points[(j + 1) % points.size()]; @@ -493,22 +593,22 @@ static Polylines remove_points_from_polygon(const Polygon &polygon, const std::v return result; } -static Polylines contrust_gap_for_skip_points(const Polygon &polygon, const std::vector & skip_points ,float wt_width,float gap_length,Polygon& insert_skip_polygon) +Polylines construct_gap_for_skip_points(const Polygon &polygon, const std::vector & skip_points ,float wt_width,float gap_length,Polygon& insert_skip_polygon) { if (skip_points.empty()) { insert_skip_polygon = polygon; return Polylines{to_polyline(polygon)}; } - bool is_left = false; - const auto &pt = skip_points.front(); - if (abs(pt.x()) < wt_width/2.f) { - is_left = true; - } - return remove_points_from_polygon(polygon, skip_points, gap_length, is_left, insert_skip_polygon); + //bool is_left = false; + //const auto &pt = skip_points.front(); + //if (abs(pt.x()) < wt_width/2.f) { + // is_left = true; + //} + return remove_points_from_polygon(polygon, skip_points, gap_length, wt_width, insert_skip_polygon); }; -static Polygon generate_rectange_polygon(const Vec2f &wt_box_min ,const Vec2f & wt_box_max) { +Polygon generate_rectange_polygon(const Vec2f &wt_box_min ,const Vec2f & wt_box_max) { Polygon res; res.points.push_back(scaled(wt_box_min)); res.points.push_back(scaled(Vec2f{wt_box_max[0], wt_box_min[1]})); @@ -517,10 +617,22 @@ static Polygon generate_rectange_polygon(const Vec2f &wt_box_min ,const Vec2f & return res; } +const char* flush_planner_queue_command(GCodeFlavor flavor) +{ + return flavor == gcfKlipper ? "M400\n" : "G4 S0\n"; +} + +std::string wait_command(GCodeFlavor flavor, float seconds) +{ + if (flavor == gcfKlipper) + return "G4 P" + std::to_string(std::lround(seconds * 1000.f)) + "\n"; + return "G4 S" + Slic3r::float_to_string_decimal_point(seconds, 3) + "\n"; +} + class WipeTowerWriter { public: - WipeTowerWriter(float layer_height, float line_width, GCodeFlavor flavor, const std::vector& filament_parameters) : + WipeTowerWriter(float layer_height, float line_width, GCodeFlavor flavor, const std::vector& filament_parameters, bool enable_arc_fitting) : m_current_pos(std::numeric_limits::max(), std::numeric_limits::max()), m_current_z(0.f), m_current_feedrate(0.f), @@ -528,9 +640,13 @@ public: m_extrusion_flow(0.f), m_preview_suppressed(false), m_elapsed_time(0.f), - m_gcode_flavor(flavor), - m_filpar(filament_parameters) - { +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + m_default_analyzer_line_width(line_width), +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + m_gcode_flavor(flavor), + m_enable_arc_fitting(enable_arc_fitting), + m_filpar(filament_parameters) + { // ORCA: This class is only used by BBL printers, so set the parameter appropriately. // This fixes an issue where the wipe tower was using BBL tags resulting in statistics for purging in the purge tower not being displayed. GCodeProcessor::s_IsBBLPrinter = true; @@ -550,6 +666,18 @@ public: return *this; } +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + WipeTowerWriter& change_analyzer_mm3_per_mm(float len, float e) { + static const float area = float(M_PI) * 1.75f * 1.75f / 4.f; + float mm3_per_mm = (len == 0.f ? 0.f : area * e / len); + // adds tag for processor: + std::stringstream str; + str << ";" << GCodeProcessor::Mm3_Per_Mm_Tag << mm3_per_mm << "\n"; + m_gcode += str.str(); + return *this; + } +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + WipeTowerWriter& set_initial_position(const Vec2f &pos, float width = 0.f, float depth = 0.f, float internal_angle = 0.f) { m_wipe_tower_width = width; m_wipe_tower_depth = depth; @@ -587,8 +715,13 @@ public: // Suppress / resume G-code preview in Slic3r. Slic3r will have difficulty to differentiate the various // filament loading and cooling moves from normal extrusion moves. Therefore the writer // is asked to suppres output of some lines, which look like extrusions. +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + WipeTowerWriter& suppress_preview() { change_analyzer_line_width(0.f); m_preview_suppressed = true; return *this; } + WipeTowerWriter& resume_preview() { change_analyzer_line_width(m_default_analyzer_line_width); m_preview_suppressed = false; return *this; } +#else WipeTowerWriter& suppress_preview() { m_preview_suppressed = true; return *this; } - WipeTowerWriter& resume_preview() { m_preview_suppressed = false; return *this; } + WipeTowerWriter& resume_preview() { m_preview_suppressed = false; return *this; } +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING WipeTowerWriter& feedrate(float f) { @@ -610,9 +743,9 @@ public: float get_and_reset_used_filament_length() { float temp = m_used_filament_length; m_used_filament_length = 0.f; return temp; } // Extrude with an explicitely provided amount of extrusion. - WipeTowerWriter& extrude_explicit(float x, float y, float e, float f = 0.f, bool record_length = false, bool limit_volumetric_flow = true) + WipeTowerWriter &extrude_explicit(float x, float y, float e, float f = 0.f, bool record_length = false ,LimitFlow limit_flow = LimitFlow::LimitPrintFlow) { - if (x == m_current_pos.x() && y == m_current_pos.y() && e == 0.f && (f == 0.f || f == m_current_feedrate)) + if ((std::abs(x - m_current_pos.x()) <= (float)EPSILON) && (std::abs(y - m_current_pos.y()) < (float)EPSILON) && e == 0.f && (f == 0.f || f == m_current_feedrate)) // Neither extrusion nor a travel move. return *this; @@ -627,9 +760,12 @@ public: Vec2f rot(this->rotate(Vec2f(x,y))); // this is where we want to go if (! m_preview_suppressed && e > 0.f && len > 0.f) { - // Width of a squished extrusion, corrected for the roundings of the squished extrusions. +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + change_analyzer_mm3_per_mm(len, e); +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + // Width of a squished extrusion, corrected for the roundings of the squished extrusions. // This is left zero if it is a travel move. - float width = e * m_filpar[0].filament_area / (len * m_layer_height); + float width = e * m_filpar[0].filament_area / (len * m_layer_height); // Correct for the roundings of a squished extrusion. width += m_layer_height * float(1. - M_PI / 4.); if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos) @@ -637,6 +773,12 @@ public: m_extrusions.emplace_back(WipeTower::Extrusion(rot, width, m_current_tool)); } + if (e == 0.f) { + m_gcode += set_travel_acceleration(); + } else { + m_gcode += set_normal_acceleration(); + } + m_gcode += "G1"; if (std::abs(rot.x() - rotated_current_pos.x()) > (float)EPSILON) m_gcode += set_format_X(rot.x()); @@ -649,9 +791,12 @@ public: m_gcode += set_format_E(e); if (f != 0.f && f != m_current_feedrate) { - if (limit_volumetric_flow) { + if (limit_flow!= LimitFlow::None) { float e_speed = e / (((len == 0.f) ? std::abs(e) : len) / f * 60.f); - f /= std::max(1.f, e_speed / m_filpar[m_current_tool].max_e_speed); + float tmp = m_filpar[m_current_tool].max_e_speed; + if (limit_flow == LimitFlow::LimitRammingFlow) tmp = m_filpar[m_current_tool].max_e_ramming_speed.first; + else if (limit_flow == LimitFlow::LimitRammingFlowNC) tmp = m_filpar[m_current_tool].max_e_ramming_speed.second; + f /= std::max(1.f, e_speed / tmp); } m_gcode += set_format_F(f); } @@ -666,7 +811,7 @@ public: } // Extrude with an explicitely provided amount of extrusion. - WipeTowerWriter &extrude_arc_explicit(ArcSegment &arc, float f = 0.f, bool record_length = false, bool limit_volumetric_flow = true) + WipeTowerWriter &extrude_arc_explicit(ArcSegment &arc, float f = 0.f, bool record_length = false, LimitFlow limit_flow = LimitFlow::LimitPrintFlow) { float x = (float)unscale(arc.end_point).x(); float y = (float)unscale(arc.end_point).y(); @@ -706,6 +851,13 @@ public: } } + + if (e == 0.f) { + m_gcode += set_travel_acceleration(); + } else { + m_gcode += set_normal_acceleration(); + } + m_gcode += arc.direction == ArcDirection::Arc_Dir_CCW ? "G3" : "G2"; const Vec2f center_offset = this->rotate(unscaled(arc.center)) - rotated_current_pos; m_gcode += set_format_X(rot.x()); @@ -716,9 +868,13 @@ public: if (e != 0.f) m_gcode += set_format_E(e); if (f != 0.f && f != m_current_feedrate) { - if (limit_volumetric_flow) { + if (limit_flow != LimitFlow::None) { float e_speed = e / (((len == 0.f) ? std::abs(e) : len) / f * 60.f); - f /= std::max(1.f, e_speed / m_filpar[m_current_tool].max_e_speed); + float tmp = m_filpar[m_current_tool].max_e_speed; + if (limit_flow == LimitFlow::LimitRammingFlow) tmp = m_filpar[m_current_tool].max_e_ramming_speed.first; + else if (limit_flow == LimitFlow::LimitRammingFlowNC) + tmp = m_filpar[m_current_tool].max_e_ramming_speed.second; + f /= std::max(1.f, e_speed / tmp); } m_gcode += set_format_F(f); } @@ -732,8 +888,10 @@ public: return *this; } - WipeTowerWriter& extrude_explicit(const Vec2f &dest, float e, float f = 0.f, bool record_length = false, bool limit_volumetric_flow = true) - { return extrude_explicit(dest.x(), dest.y(), e, f, record_length); } + WipeTowerWriter &extrude_explicit(const Vec2f &dest, float e, float f = 0.f, bool record_length = false, LimitFlow limit_flow = LimitFlow::LimitPrintFlow) + { + return extrude_explicit(dest.x(), dest.y(), e, f, record_length, limit_flow); + } // Travel to a new XY position. f=0 means use the current value. WipeTowerWriter& travel(float x, float y, float f = 0.f) @@ -743,15 +901,15 @@ public: { return extrude_explicit(dest.x(), dest.y(), 0.f, f); } // Extrude a line from current position to x, y with the extrusion amount given by m_extrusion_flow. - WipeTowerWriter& extrude(float x, float y, float f = 0.f) + WipeTowerWriter &extrude(float x, float y, float f = 0.f, LimitFlow limit_flow = LimitFlow::LimitPrintFlow) { float dx = x - m_current_pos.x(); float dy = y - m_current_pos.y(); - return extrude_explicit(x, y, std::sqrt(dx*dx+dy*dy) * m_extrusion_flow, f, true); + return extrude_explicit(x, y, std::sqrt(dx * dx + dy * dy) * m_extrusion_flow, f, false, limit_flow); } - WipeTowerWriter &extrude_arc(ArcSegment &arc, float f = 0.f) + WipeTowerWriter &extrude_arc(ArcSegment &arc, float f = 0.f, LimitFlow limit_flow = LimitFlow::LimitPrintFlow) { - return extrude_arc_explicit(arc, f, true); + return extrude_arc_explicit(arc, f, false , limit_flow); } WipeTowerWriter& extrude(const Vec2f &dest, const float f = 0.f) @@ -866,7 +1024,12 @@ public: { Polyline pl = to_polyline(wall_polygon); pl.simplify(WT_SIMPLIFY_TOLERANCE_SCALED); - pl.simplify_by_fitting_arc(SCALED_WIPE_TOWER_RESOLUTION); + if (m_enable_arc_fitting) { + pl.simplify_by_fitting_arc(SCALED_WIPE_TOWER_RESOLUTION); + } else { + pl.simplify(SCALED_WIPE_TOWER_RESOLUTION); + pl.reset_to_linear_move(); + } auto get_closet_idx = [this](std::vector &corners) -> int { Vec2f anchor{this->m_current_pos.x(), this->m_current_pos.y()}; @@ -895,6 +1058,9 @@ public: } } + if (segments.empty()) + return (*this); + int index_of_closest = get_closet_idx(segments); int i = index_of_closest; travel(segments[i].start); // travel to the closest points @@ -937,7 +1103,7 @@ public: } float end_point = x() + (farthest_x > x() ? 1.f : -1.f) * x_distance; - return extrude_explicit(end_point, y(), loading_dist, x_speed * 60.f, false, false); + return extrude_explicit(end_point, y(), loading_dist, x_speed * 60.f, false, LimitFlow::None); } // Elevate the extruder head above the current print_z position. @@ -958,8 +1124,8 @@ public: // extrude quickly amount e to x2 with feed f. WipeTowerWriter& ram(float x1, float x2, float dy, float e0, float e, float f) { - extrude_explicit(x1, m_current_pos.y() + dy, e0, f, true, false); - extrude_explicit(x2, m_current_pos.y(), e, 0.f, true, false); + extrude_explicit(x1, m_current_pos.y() + dy, e0, f, true, LimitFlow::None); + extrude_explicit(x2, m_current_pos.y(), e, 0.f, true, LimitFlow::None); return *this; } @@ -968,8 +1134,8 @@ public: // at the current Y position to spread the leaking material. WipeTowerWriter& cool(float x1, float x2, float e1, float e2, float f) { - extrude_explicit(x1, m_current_pos.y(), e1, f, false, false); - extrude_explicit(x2, m_current_pos.y(), e2, false, false); + extrude_explicit(x1, m_current_pos.y(), e1, f, false, LimitFlow::None); + extrude_explicit(x2, m_current_pos.y(), e2, 0.f, false, LimitFlow::None); return *this; } @@ -991,7 +1157,7 @@ public: { if (time==0.f) return *this; - m_gcode += "G4 S" + Slic3r::float_to_string_decimal_point(time, 3) + "\n"; + m_gcode += wait_command(m_gcode_flavor, time); return *this; } @@ -1002,26 +1168,22 @@ public: return *this; } - // Let the firmware back up the active speed override value. - WipeTowerWriter& speed_override_backup() + // Let the firmware back up the active speed override value. + WipeTowerWriter& speed_override_backup() { // BBS: BBL machine don't support speed backup -#if 0 if (m_gcode_flavor == gcfMarlinLegacy || m_gcode_flavor == gcfMarlinFirmware) m_gcode += "M220 B\n"; -#endif - return *this; + return *this; } - // Let the firmware restore the active speed override value. - WipeTowerWriter& speed_override_restore() - { - // BBS: BBL machine don't support speed restore -#if 0 + // Let the firmware restore the active speed override value. + WipeTowerWriter& speed_override_restore() + { + // BBS: BBL machine don't support speed restore if (m_gcode_flavor == gcfMarlinLegacy || m_gcode_flavor == gcfMarlinFirmware) m_gcode += "M220 R\n"; -#endif - return *this; + return *this; } // Set digital trimpot motor @@ -1040,7 +1202,7 @@ public: WipeTowerWriter& flush_planner_queue() { - m_gcode += "G4 S0\n"; + m_gcode += flush_planner_queue_command(m_gcode_flavor); return *this; } @@ -1115,7 +1277,14 @@ public: } return closestIndex; }; - for (auto &pl : pls) pl.simplify_by_fitting_arc(SCALED_WIPE_TOWER_RESOLUTION); + if (m_enable_arc_fitting) { + for (auto &pl : pls) pl.simplify_by_fitting_arc(SCALED_WIPE_TOWER_RESOLUTION); + } else { + for (auto &pl : pls) { + pl.simplify(SCALED_WIPE_TOWER_RESOLUTION); + pl.reset_to_linear_move(); + } + } std::vector segments; for (const auto &pl : pls) { @@ -1131,9 +1300,11 @@ public: segments.back().is_arc = true; segments.back().arcsegment = pl.fitting_result[i].arc_data; } - } } + if (segments.empty()) + return; + int index_of_closest = get_closet_idx(segments); int i = index_of_closest; travel(segments[i].start); // travel to the closest points @@ -1158,7 +1329,7 @@ public: Vec2f box_max = center + Vec2f{step_length, step_length}; Vec2f box_min = center - Vec2f{step_length, step_length}; int n = std::ceil(edge_length / step_length / 2.f); - assert(n > 0); + if (n <= 0) return; while (n--) { travel(box_max.x(), m_current_pos.y(), feedrate); travel(m_current_pos.x(), box_max.y(), feedrate); @@ -1170,6 +1341,122 @@ public: } } + WipeTowerWriter &format_line_M104(int target_temp, int target_extruder, bool wait_for_moves = true, const std::string &comment = std::string()) + { + std::string buffer; + if (wait_for_moves) + // Not flush_planner_queue_command(): this BBL precool path wants M400, which every + // flavor it reaches understands, not the zero dwell the other flavors flush with. + buffer += "M400\n"; + buffer += "M104"; + if (target_extruder != -1) + buffer += (" T" + std::to_string(m_physical_extruder_map[target_extruder])); + buffer += " S" + std::to_string(target_temp) + " N0"; // N0 means the gcode is generated by slicer + if (!comment.empty()) buffer += " ;" + comment; + buffer += '\n'; + append(buffer); + return *this; + } + + WipeTowerWriter &format_line_M109(int target_temp, int target_extruder, const std::string &comment = std::string()) + { + std::string buffer = "M109"; + if (target_extruder != -1) + buffer += (" T" + std::to_string(m_physical_extruder_map[target_extruder])); + buffer += " S" + std::to_string(target_temp) + " N0"; // N0 means the gcode is generated by slicer + if (!comment.empty()) buffer += " ;" + comment; + buffer += '\n'; + append(buffer); + return *this; + }; + + void set_first_layer(bool is_first_layer) { m_is_first_layer = is_first_layer; } + void set_normal_acceleration(const std::vector &accelerations) { m_normal_accelerations = accelerations; }; + void set_first_layer_normal_acceleration(const std::vector &accelerations) { m_first_layer_normal_accelerations = accelerations; }; + void set_travel_acceleration(const std::vector &accelerations) { m_travel_accelerations = accelerations; }; + void set_first_layer_travel_acceleration(const std::vector &accelerations) { m_first_layer_travel_accelerations = accelerations; }; + void set_max_acceleration(unsigned int acceleration) { m_max_acceleration = acceleration; }; + void set_accel_to_decel_enable(bool enable) { m_accel_to_decel_enable = enable; } + void set_accel_to_decel_factor(float factor) { m_accel_to_decel_factor = factor; } + void set_layer_id(int layer_id) { m_layer_id = layer_id; } + void set_multi_nozzle_group_result(const MultiNozzleUtils::LayeredNozzleGroupResult *multi_nozzle_group_result) { m_multi_nozzle_group_result = multi_nozzle_group_result; } + void set_physical_extruder_map(const std::vector &physical_extruder_map) { m_physical_extruder_map = physical_extruder_map; } + +private: + std::string set_normal_acceleration() { + std::vector accelerations = m_is_first_layer ? m_first_layer_normal_accelerations : m_normal_accelerations; + if (accelerations.empty() || !m_multi_nozzle_group_result) + return std::string(); + int extruder_id = m_multi_nozzle_group_result->get_extruder_id(m_current_tool, m_layer_id); + // Orca: get_extruder_id returns -1 when the filament is not covered by the map + // (reachable with a stale manual filament map); skip instead of indexing out of bounds. + if (extruder_id < 0 || extruder_id >= (int) accelerations.size()) + return std::string(); + unsigned int acc = accelerations[extruder_id]; + return set_acceleration_impl(acc); + } + std::string set_travel_acceleration() + { + std::vector accelerations = m_is_first_layer ? m_first_layer_travel_accelerations : m_travel_accelerations; + if (accelerations.empty() || !m_multi_nozzle_group_result) + return std::string(); + int extruder_id = m_multi_nozzle_group_result->get_extruder_id(m_current_tool, m_layer_id); + // Orca: get_extruder_id returns -1 when the filament is not covered by the map + // (reachable with a stale manual filament map); skip instead of indexing out of bounds. + if (extruder_id < 0 || extruder_id >= (int) accelerations.size()) + return std::string(); + unsigned int acc = accelerations[extruder_id]; + return set_acceleration_impl(acc); + } + std::string set_acceleration_impl(unsigned int acceleration) { + // Clamp the acceleration to the allowed maximum. + if (m_max_acceleration > 0 && acceleration > m_max_acceleration) + acceleration = m_max_acceleration; + + if (acceleration == 0 || acceleration == m_last_acceleration) + return std::string(); + + m_last_acceleration = acceleration; + + std::ostringstream gcode; + if (m_gcode_flavor == gcfRepetier) { + // M201: Set max printing acceleration + gcode << "M201 X" << acceleration << " Y" << acceleration; + gcode << "\n"; + // M202: Set max travel acceleration + gcode << "M202 X" << acceleration << " Y" << acceleration; + } else if (m_gcode_flavor == gcfRepRapFirmware) { + // M204: Set default acceleration + gcode << "M204 P" << acceleration; + } else if (m_gcode_flavor == gcfMarlinFirmware) { + // This is new MarlinFirmware with separated print/retraction/travel acceleration. + // Use M204 P, we don't want to override travel acc by M204 S (which is deprecated anyway). + gcode << "M204 P" << acceleration; + } + else if (m_gcode_flavor == gcfKlipper && m_accel_to_decel_enable) { + gcode << "SET_VELOCITY_LIMIT ACCEL_TO_DECEL=" << acceleration * m_accel_to_decel_factor / 100; + gcode << "\nM204 S" << acceleration; + } + else { + // M204: Set default acceleration + gcode << "M204 S" << acceleration; + } + gcode << "\n"; + return gcode.str(); + } + std::vector m_normal_accelerations; + std::vector m_first_layer_normal_accelerations; + std::vector m_travel_accelerations; + std::vector m_first_layer_travel_accelerations; + bool m_is_first_layer{false}; + unsigned int m_max_acceleration{0}; + unsigned int m_last_acceleration{0}; + bool m_accel_to_decel_enable; + float m_accel_to_decel_factor; + const MultiNozzleUtils::LayeredNozzleGroupResult *m_multi_nozzle_group_result{nullptr}; + int m_layer_id = -1; + std::vector m_physical_extruder_map; + private: Vec2f m_start_pos; Vec2f m_current_pos; @@ -1189,8 +1476,12 @@ private: float m_wipe_tower_depth = 0.f; unsigned m_last_fan_speed = 0; int current_temp = -1; +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + const float m_default_analyzer_line_width; +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING float m_used_filament_length = 0.f; GCodeFlavor m_gcode_flavor; + bool m_enable_arc_fitting = true; const std::vector& m_filpar; std::string set_format_X(float x) @@ -1244,7 +1535,7 @@ WipeTower::ToolChangeResult WipeTower::construct_tcr(WipeTowerWriter& writer, bool is_finish, bool is_tool_change, float purge_volume, - bool is_contact) const + bool is_contact ) const { ToolChangeResult result; result.priming = priming; @@ -1261,9 +1552,8 @@ WipeTower::ToolChangeResult WipeTower::construct_tcr(WipeTowerWriter& writer, result.is_finish_first = is_finish; result.nozzle_change_result = m_nozzle_change_result; result.is_tool_change = is_tool_change; - result.is_contact = is_contact; result.tool_change_start_pos = is_tool_change ? result.start_pos : Vec2f(0, 0); - + result.is_contact = is_contact; // BBS result.purge_volume = purge_volume; return result; @@ -1285,7 +1575,6 @@ WipeTower::ToolChangeResult WipeTower::construct_block_tcr(WipeTowerWriter &writ result.wipe_path = std::move(writer.wipe_path()); result.is_finish_first = is_finish; result.is_tool_change = false; - result.is_contact = false; result.tool_change_start_pos = Vec2f(0, 0); // BBS result.purge_volume = purge_volume; @@ -1341,25 +1630,56 @@ float WipeTower::get_auto_brim_by_height(float max_height) { return 8.f; } -Vec2f WipeTower::move_box_inside_box(const BoundingBox &box1, const BoundingBox &box2,int scaled_offset) +Vec2f WipeTower::move_box_inside_polygon(const BoundingBox &box, const Polygons &polygons, coord_t offset) { - Vec2f res{0, 0}; - if (box1.size()[0] >= box2.size()[0]- 2*scaled_offset || box1.size()[1] >= box2.size()[1]-2*scaled_offset) return res; + if (polygons.empty()) return Vec2f{0.f, 0.f}; - if (box1.max[0] > box2.max[0] - scaled_offset) { - res[0] = unscaled((box2.max[0] - scaled_offset) - box1.max[0]); - } - else if (box1.min[0] < box2.min[0] + scaled_offset) { - res[0] = unscaled((box2.min[0] + scaled_offset) - box1.min[0]); + const BoundingBox bed = get_extents(polygons); + // No position fits the footprint. + if (box.size().x() >= bed.size().x() - 2 * offset || box.size().y() >= bed.size().y() - 2 * offset) + return Vec2f{0.f, 0.f}; + + // Clamp against the bounding box first, moving only along the axis that is violated so a dragged + // prime tower slides along the bed edge instead of jumping inwards. + Point shift(0, 0); + for (int axis = 0; axis < 2; ++axis) { + if (box.max[axis] > bed.max[axis] - offset) + shift[axis] = (bed.max[axis] - offset) - box.max[axis]; + else if (box.min[axis] < bed.min[axis] + offset) + shift[axis] = (bed.min[axis] + offset) - box.min[axis]; } - if (box1.max[1] > box2.max[1] - scaled_offset) { - res[1] = unscaled((box2.max[1] - scaled_offset) - box1.max[1]); + // A bed that fills its own bounding box is fully clamped by that, so every rectangular bed — all + // but the delta-style profiles — stops here and keeps its historic placement, including when a + // negative margin lets the footprint hang over the edge. The tolerance is relative because an + // exact rectangle loses a few ulps once the areas are squared world coordinates. + double area = 0.; + for (const Polygon &poly : polygons) area += std::abs(poly.area()); + const double bed_area = double(bed.size().x()) * double(bed.size().y()); + if (area >= bed_area * (1. - EPSILON)) return unscaled(shift); + + // Clamp a negative margin (an auto brim width that has not been resolved yet) to zero: padding by + // it would shrink the footprint and hand back a position the validation still rejects. The + // epsilon lets the move's round trip through millimeters land on the outline without counting as + // a violation. + BoundingBox padded = box.inflated(std::max(offset, 0) - SCALED_EPSILON); + padded.translate(shift); + auto fits = [&padded, &polygons](const Point &move) { + BoundingBox moved = padded; + moved.translate(move); + return diff(Polygons{moved.polygon()}, polygons).empty(); + }; + if (fits(Point(0, 0))) return unscaled(shift); + + // Walk towards the middle of the bed. On every non-rectangular bed we ship, the fitting positions + // form a convex region around it, so bisecting stops just inside the outline. + Point lo(0, 0), hi = bed.center() - padded.center(); + if (!fits(hi)) return unscaled(shift); + for (int i = 0; i < 12; ++i) { + const Point mid = (lo + hi) / 2; + if (fits(mid)) hi = mid; else lo = mid; } - else if (box1.min[1] < box2.min[1] + scaled_offset) { - res[1] = unscaled((box2.min[1] + scaled_offset) - box1.min[1]); - } - return res; + return unscaled(Point(shift + hi)); } Polygon WipeTower::rib_section(float width, float depth, float rib_length, float rib_width,bool fillet_wall) @@ -1480,40 +1800,43 @@ WipeTower::WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origi m_enable_wrapping_detection(config.enable_wrapping_detection), m_wrapping_detection_layers(config.wrapping_detection_layers.value && (config.wrapping_exclude_area.values.size() > 2)), m_slice_used_filaments(slice_used_filaments.size()), - m_filaments_change_length(config.filament_change_length.values), m_is_multi_extruder(config.nozzle_diameter.size() > 1), m_use_gap_wall(config.prime_tower_skip_points.value), + // Orca: rib-wall options live under wipe_tower_* names and the wall type is an enum m_use_rib_wall(config.wipe_tower_wall_type.value == WipeTowerWallType::wtwRib), m_extra_rib_length((float)config.wipe_tower_extra_rib_length.value), m_rib_width((float)config.wipe_tower_rib_width.value), m_used_fillet(config.wipe_tower_fillet_wall.value), m_extra_spacing((float)config.prime_tower_infill_gap.value/100.f), m_tower_framework(config.prime_tower_enable_framework.value), + // Orca: prime_tower_max_speed is named wipe_tower_max_purge_speed (same default/min) + m_max_speed((float)config.wipe_tower_max_purge_speed.value*60.f), + m_accel_to_decel_enable(config.accel_to_decel_enable.value), + m_accel_to_decel_factor(config.accel_to_decel_factor.value), + m_printable_height(config.extruder_printable_height.values), m_flat_ironing(config.prime_tower_flat_ironing.value), m_enable_tower_interface_features(config.enable_tower_interface_features.value), - m_enable_tower_interface_cooldown_during_tower(config.enable_tower_interface_cooldown_during_tower.value) + m_physical_extruder_map(config.physical_extruder_map.values), + m_enable_arc_fitting(config.enable_arc_fitting.value) + // Orca: has_filament_switcher is a device-set dynamic key, not a PrintConfig member; + // it is pushed in from Print via set_has_filament_switcher() instead of read here. { + m_contact_speed = 20 * 60.f; + m_filaments_change_length.first = config.filament_change_length.values; + m_filaments_change_length.second = config.filament_change_length_nc.values; + m_hotend_heating_rate = config.hotend_heating_rate.values; + m_hotend_cooling_rate = config.hotend_cooling_rate.values; m_flat_ironing = (m_flat_ironing && m_use_gap_wall); - - // Prime-tower heating during wipe. m_is_multiple_nozzle mirrors the gate used in ToolOrdering/GCode - // (std::any_of extruder_max_nozzle_count > 1); it is false for every current printer, so the - // heating-during-wipe logic in toolchange_wipe_new is inert. - m_hotend_heating_rate = config.hotend_heating_rate.values; - m_physical_extruder_map = config.physical_extruder_map.values; - m_is_multiple_nozzle = std::any_of(config.extruder_max_nozzle_count.values.begin(), - config.extruder_max_nozzle_count.values.end(), - [](int v) { return v > 1; }); - - // Per-extruder printable-height clamp. Empty for single-extruder printers - // (extruder_printable_height = []), so is_valid_last_layer is inert there. - m_printable_height = config.extruder_printable_height.values; - m_last_layer_id.assign(config.nozzle_diameter.size(), -1); + // Orca: default/initial-layer/travel acceleration are object-scope options here (PrintConfig + // members in BBS), so Print pushes the resolved columns in via set_accelerations() instead of + // the ctor reading them from config. + m_max_accels = config.machine_max_acceleration_extruding.values.front(); // Read absolute value of first layer speed, if given as percentage, // it is taken over following default. Speeds from config are not // easily accessible here. const float default_speed = 60.f; - m_first_layer_speed = config.initial_layer_speed.get_at(get_extruder_index(config, (unsigned int)initial_tool)); + m_first_layer_speed = config.initial_layer_speed.get_at(get_extruder_index(config, (unsigned int) initial_tool)); if (m_first_layer_speed == 0.f) // just to make sure autospeed doesn't break it. m_first_layer_speed = default_speed / 2.f; @@ -1550,6 +1873,9 @@ WipeTower::WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origi m_bed_bottom_left = m_bed_shape == RectangularBed ? Vec2f(bed_points.front().x(), bed_points.front().y()) : Vec2f::Zero(); + m_last_layer_id.resize(config.nozzle_diameter.size(), -1); + m_origin = {plate_origin[0], plate_origin[1]}; + m_is_multiple_nozzle = std::any_of(config.extruder_max_nozzle_count.values.begin(), config.extruder_max_nozzle_count.values.end(), [](auto &elem) { return elem > 1; }); } @@ -1559,31 +1885,16 @@ void WipeTower::set_extruder(size_t idx, const PrintConfig& config) //while (m_filpar.size() < idx+1) // makes sure the required element is in the vector m_filpar.push_back(FilamentParameters()); - // Orca: one row per filament, indexed by the raw filament id. Under a per-layer nozzle - // grouping the per-variant arrays may hold several columns per filament; the tower has no - // layer dimension here, so it keeps the filament's first column (tower x per-layer - // grouping is a documented follow-up). m_filpar[idx].material = config.filament_type.get_at(idx); + // Orca: wipe_tower_filament (issue #10971) forces a specific filament to print the tower wall by + // marking every other filament as "soluble"; 0 keeps the plain per-filament soluble flag. m_filpar[idx].is_soluble = config.wipe_tower_filament == 0 ? config.filament_soluble.get_at(idx) : (idx != size_t(config.wipe_tower_filament - 1)); // BBS m_filpar[idx].is_support = config.filament_is_support.get_at(idx); m_filpar[idx].nozzle_temperature = config.nozzle_temperature.get_at(idx); m_filpar[idx].nozzle_temperature_initial_layer = config.nozzle_temperature_initial_layer.get_at(idx); m_filpar[idx].category = config.filament_adhesiveness_category.get_at(idx); - { - int interface_temp = config.filament_tower_interface_print_temp.get_at(idx); - if (interface_temp == -1) - interface_temp = config.nozzle_temperature_range_high.get_at(idx); - m_filpar[idx].interface_print_temperature = interface_temp; - } - m_filpar[idx].tower_interface_pre_extrusion_dist = config.filament_tower_interface_pre_extrusion_dist.get_at(idx); - m_filpar[idx].tower_interface_pre_extrusion_length = config.filament_tower_interface_pre_extrusion_length.get_at(idx); - // PETG pre-extrusion offset reuses the tower-interface pre-extrusion distance. Only read by the - // has_filament_switcher-gated PETG branch in get_next_pos (inert fleet-wide). - m_filpar[idx].petg_pre_extrusion_offset_dist = config.filament_tower_interface_pre_extrusion_dist.get_at(idx); - m_filpar[idx].tower_ironing_area = config.filament_tower_ironing_area.get_at(idx); - m_filpar[idx].tower_interface_purge_length = config.filament_tower_interface_purge_volume.get_at(idx); - m_filpar[idx].filament_cooling_before_tower = config.filament_cooling_before_tower.get_at(idx); + m_filpar[idx].flat_iron_area = config.filament_tower_ironing_area.get_at(idx); // If this is a single extruder MM printer, we will use all the SE-specific config values. // Otherwise, the defaults will be used to turn off the SE stuff. @@ -1609,14 +1920,10 @@ void WipeTower::set_extruder(size_t idx, const PrintConfig& config) if (max_vol_speed!= 0.f) m_filpar[idx].max_e_speed = (max_vol_speed / filament_area()); - // Vortek H2C: carousel-specific ramming, precool, and reverse travel parameters + //set extruder change and nozzle change ramming speed { - // Ramming speed: .first = extruder change, .second = nozzle change (carousel) - // Use the dedicated ramming volumetric speed, falling back to max_vol_speed only when - // the setting is nil/-1. float ramming_vol_speed = float(config.filament_ramming_volumetric_speed.get_at(idx)); - if (config.filament_ramming_volumetric_speed.is_nil(idx) || is_approx(config.filament_ramming_volumetric_speed.get_at(idx), -1.)) - ramming_vol_speed = max_vol_speed; + if (config.filament_ramming_volumetric_speed.is_nil(idx) || is_approx(config.filament_ramming_volumetric_speed.get_at(idx), -1.)) ramming_vol_speed = max_vol_speed; m_filpar[idx].max_e_ramming_speed.first = (ramming_vol_speed / filament_area()); float ramming_vol_speed_nc = float(config.filament_ramming_volumetric_speed_nc.get_at(idx)); @@ -1624,51 +1931,57 @@ void WipeTower::set_extruder(size_t idx, const PrintConfig& config) ramming_vol_speed_nc = max_vol_speed; m_filpar[idx].max_e_ramming_speed.second = (ramming_vol_speed_nc / filament_area()); } - { - // Precool target temp: .first = extruder change, .second = nozzle change (carousel) - // Precool is only active when enable_pre_heating is on; otherwise no precool temp/timing is - // applied and the downstream precool_t stays 0, matching printers with pre-heating disabled. - m_filpar[idx].precool_target_temp = {0, 0}; - if (config.enable_pre_heating.value) { - if (!config.filament_pre_cooling_temperature.is_nil(idx) && config.filament_pre_cooling_temperature.get_at(idx) != 0) - m_filpar[idx].precool_target_temp.first = config.filament_pre_cooling_temperature.get_at(idx); - if (!config.filament_pre_cooling_temperature_nc.is_nil(idx) && config.filament_pre_cooling_temperature_nc.get_at(idx) != 0) - m_filpar[idx].precool_target_temp.second = config.filament_pre_cooling_temperature_nc.get_at(idx); - } - } - { - // Precool timing: (nozzle_temp - precool_temp) / hotend_cooling_rate - int extruder_count = m_is_multi_extruder ? 2 : 1; // H2C = 2 extruders - float nozzle_temp = float(config.nozzle_temperature.is_nil(idx) ? 0 : config.nozzle_temperature.get_at(idx)); - float nozzle_temp_fl = float(config.nozzle_temperature_initial_layer.is_nil(idx) ? nozzle_temp : config.nozzle_temperature_initial_layer.get_at(idx)); - m_filpar[idx].precool_t.first.resize(extruder_count, 0.f); - m_filpar[idx].precool_t.second.resize(extruder_count, 0.f); - m_filpar[idx].precool_t_first_layer.first.resize(extruder_count, 0.f); - m_filpar[idx].precool_t_first_layer.second.resize(extruder_count, 0.f); - std::vector cooling_rates = config.hotend_cooling_rate.values; - for (int i = 0; i < extruder_count && i < (int)cooling_rates.size(); i++) { - if (cooling_rates[i] < EPSILON) continue; - if (m_filpar[idx].precool_target_temp.first != 0) { - m_filpar[idx].precool_t.first[i] = std::max(0.f, nozzle_temp - float(m_filpar[idx].precool_target_temp.first)) / float(cooling_rates[i]); - m_filpar[idx].precool_t_first_layer.first[i] = std::max(0.f, nozzle_temp_fl - float(m_filpar[idx].precool_target_temp.first)) / float(cooling_rates[i]); - } - if (m_filpar[idx].precool_target_temp.second != 0) { - m_filpar[idx].precool_t.second[i] = std::max(0.f, nozzle_temp - float(m_filpar[idx].precool_target_temp.second)) / float(cooling_rates[i]); - m_filpar[idx].precool_t_first_layer.second[i] = std::max(0.f, nozzle_temp_fl - float(m_filpar[idx].precool_target_temp.second)) / float(cooling_rates[i]); - } - } - } - { - // Ramming travel time: .first = extruder change, .second = nozzle change (carousel) - m_filpar[idx].ramming_travel_time = {0.f, 0.f}; - if (!config.filament_ramming_travel_time.is_nil(idx)) - m_filpar[idx].ramming_travel_time.first = float(config.filament_ramming_travel_time.get_at(idx)); - if (!config.filament_ramming_travel_time_nc.is_nil(idx)) - m_filpar[idx].ramming_travel_time.second = float(config.filament_ramming_travel_time_nc.get_at(idx)); - } + //set precooling time/precooling target temp during extruder change and nozzle change + { + int extruder_count = m_multi_nozzle_group_result->get_extruder_count(); + m_filpar[idx].precool_t.first.resize(extruder_count, 0.f); + m_filpar[idx].precool_t_first_layer.first.resize(extruder_count, 0.f); + m_filpar[idx].precool_t.second.resize(extruder_count, 0.f); + m_filpar[idx].precool_t_first_layer.second.resize(extruder_count, 0.f); + m_filpar[idx].precool_target_temp.first = 0; + m_filpar[idx].precool_target_temp.second = 0; + float nozzle_temp_first_layer = config.nozzle_temperature_initial_layer.is_nil(idx) ? -1.f : float(config.nozzle_temperature_initial_layer.get_at(idx)); + float nozzle_temp_other_layer = config.nozzle_temperature.is_nil(idx) ? -1.f : float(config.nozzle_temperature.get_at(idx)); + std::vector hotend_cooling_rates = config.hotend_cooling_rate.values; + auto is_need_precooling = [&](bool extruder_change) -> bool + { + bool res = config.enable_pre_heating.value; + if (extruder_change) return res &&!config.filament_pre_cooling_temperature.is_nil(idx) && config.filament_pre_cooling_temperature.get_at(idx) != 0; + return res &&!config.filament_pre_cooling_temperature_nc.is_nil(idx) && config.filament_pre_cooling_temperature_nc.get_at(idx) != 0; + }; + if (is_need_precooling(true)) { + for (int i = 0; i < m_filpar[idx].precool_t.first.size(); i++) { + if (config.hotend_cooling_rate.is_nil(i)) continue; + m_filpar[idx].precool_t.first[i] = std::max(0.f, nozzle_temp_other_layer - float(config.filament_pre_cooling_temperature.get_at(idx))) / float(hotend_cooling_rates[i]); + m_filpar[idx].precool_t_first_layer.first[i] = std::max(0.f, nozzle_temp_first_layer -float(config.filament_pre_cooling_temperature.get_at(idx))) /float(hotend_cooling_rates[i]); + } + m_filpar[idx].precool_target_temp.first = config.filament_pre_cooling_temperature.get_at(idx); + } + + if (is_need_precooling(false)) { + for (int i = 0; i < m_filpar[idx].precool_t.second.size(); i++) { + if (config.hotend_cooling_rate.is_nil(i)) continue; + m_filpar[idx].precool_t.second[i] = std::max(0.f, nozzle_temp_other_layer - float(config.filament_pre_cooling_temperature_nc.get_at(idx))) / float(hotend_cooling_rates[i]); + m_filpar[idx].precool_t_first_layer.second[i] = std::max(0.f, nozzle_temp_first_layer -float(config.filament_pre_cooling_temperature_nc.get_at(idx))) /float(hotend_cooling_rates[i]); + } + m_filpar[idx].precool_target_temp.second = config.filament_pre_cooling_temperature_nc.get_at(idx); + } + + } + //set ramming reverse travel time during extruder change and nozzle change + { + m_filpar[idx].ramming_travel_time = {0, 0}; + if (!config.filament_ramming_travel_time.is_nil(idx)) m_filpar[idx].ramming_travel_time.first = float(config.filament_ramming_travel_time.get_at(idx)); + if (!config.filament_ramming_travel_time_nc.is_nil(idx)) m_filpar[idx].ramming_travel_time.second = float(config.filament_ramming_travel_time_nc.get_at(idx)); + } m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter - m_nozzle_change_perimeter_width = 2*m_perimeter_width; + // Orca: custom presets may use nozzle diameters outside the BBS table; fall back to the + // previous 2*perimeter_width rule (identical to the table for 0.4) instead of throwing. + { + auto nc_width_it = nozzle_diameter_to_nozzle_change_width.find(nozzle_diameter); + m_nozzle_change_perimeter_width = nc_width_it != nozzle_diameter_to_nozzle_change_width.end() ? nc_width_it->second : 2.f * m_perimeter_width; + } // BBS: remove useless config #if 0 if (m_semm) { @@ -1687,6 +2000,18 @@ void WipeTower::set_extruder(size_t idx, const PrintConfig& config) m_filpar[idx].retract_length = config.retraction_length.get_at(idx); m_filpar[idx].retract_speed = config.retraction_speed.get_at(idx); m_filpar[idx].wipe_dist = config.wipe_distance.get_at(idx); + m_filpar[idx].filament_cooling_before_tower = config.filament_cooling_before_tower.get_at(idx); + m_filpar[idx].filament_petg_pre_extrusion_offset_dist = config.filament_tower_interface_pre_extrusion_dist.get_at(idx); + if (config.enable_tower_interface_features.value) { + m_filpar[idx].filament_tower_interface_print_temp = config.filament_tower_interface_print_temp.get_at(idx) == -1 ? config.nozzle_temperature_range_high.get_at(idx) : + config.filament_tower_interface_print_temp.get_at(idx); + m_filpar[idx].filament_tower_interface_pre_extrusion_dist = config.filament_tower_interface_pre_extrusion_dist.get_at(idx); + m_filpar[idx].filament_tower_interface_pre_extrusion_length = config.filament_tower_interface_pre_extrusion_length.get_at(idx); + } else { + m_filpar[idx].filament_tower_interface_print_temp = config.nozzle_temperature.get_at(idx); + m_filpar[idx].filament_tower_interface_pre_extrusion_dist = 0.f; + m_filpar[idx].filament_tower_interface_pre_extrusion_length = 0.f; + } } @@ -1704,13 +2029,13 @@ std::vector WipeTower::prime( return std::vector(); } -Vec2f WipeTower::get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length, bool interface_layer, size_t interface_tool) +Vec2f WipeTower::get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length, bool solid_toolchange) { const float &xl = cleaning_box.ld.x(); const float &xr = cleaning_box.rd.x(); int line_count = wipe_length / (xr - xl); - float dy = m_layer_info->extra_spacing * m_perimeter_width; + float dy = m_layer_info->extra_spacing * get_block_gap_width(m_current_tool,false); float y_offset = float(line_count) * dy; const Vec2f pos_offset = Vec2f(0.f, m_depth_traversed); @@ -1733,23 +2058,20 @@ Vec2f WipeTower::get_next_pos(const WipeTower::box_coordinates &cleaning_box, fl break; default: break; } - // Shift the wipe start outward for a PETG pre-extrusion on filament-switcher devices, clamped to the - // shared printable bed. Gated on m_has_filament_switcher, which is false for the whole shipping fleet - // (no profile sets the key), so is_petg_pre_extrusion is always false and res is returned unchanged. - // The tower-interface contact branch is deliberately NOT applied here (enable_tower_interface_features - // DOES ship on H2C/X2D; applying it would change their g-code); is_contact_pre_extrusion is computed - // only as the guard that gives the contact path priority over PETG. - bool is_contact_pre_extrusion = interface_layer && m_enable_tower_interface_features; - bool is_petg_pre_extrusion = !is_contact_pre_extrusion && is_petg_filament(m_current_tool) && m_has_filament_switcher; - if (is_petg_pre_extrusion) { - Vec2f stop_pos = res; - float offset_dist = m_filpar[m_current_tool].petg_pre_extrusion_offset_dist; - auto printer_bbx = unscaled(get_extents(m_shared_print_bed)); // BoundingBoxBase - printer_bbx.translate((-m_wipe_tower_pos - m_rib_offset).cast()); + bool is_contact_pre_extrusion = solid_toolchange && m_enable_tower_interface_features; + bool is_petg_pre_extrusion = !is_contact_pre_extrusion && is_petg_filament(m_current_tool) && m_has_filament_switcher; + if (is_contact_pre_extrusion || is_petg_pre_extrusion) { + Vec2f stop_pos = res; + float filament_tower_interface_pre_extrusion_dist = is_petg_pre_extrusion + ? m_filpar[m_current_tool].filament_petg_pre_extrusion_offset_dist + : m_filpar[m_current_tool].filament_tower_interface_pre_extrusion_dist; + // Orca: unscaled(BoundingBox) here is a template returning BoundingBoxBase, not BoundingBoxf + auto printer_bbx = unscaled(get_extents(m_shared_print_bed)); + printer_bbx.translate((-m_wipe_tower_pos - m_rib_offset).cast()); // first layer never be contact if (stop_pos.x() < m_wipe_tower_width / 2.f) - stop_pos = Vec2f(stop_pos.x() - offset_dist, stop_pos.y()); + stop_pos = Vec2f(stop_pos.x() - filament_tower_interface_pre_extrusion_dist, stop_pos.y()); else - stop_pos = Vec2f(stop_pos.x() + offset_dist, stop_pos.y()); + stop_pos = Vec2f(stop_pos.x() + filament_tower_interface_pre_extrusion_dist, stop_pos.y()); if (stop_pos.x() < printer_bbx.min[0]) stop_pos.x() = printer_bbx.min[0]; if (stop_pos.x() > printer_bbx.max[0]) stop_pos.x() = printer_bbx.max[0]; res = stop_pos; @@ -1759,10 +2081,11 @@ Vec2f WipeTower::get_next_pos(const WipeTower::box_coordinates &cleaning_box, fl WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_perimeter, bool first_toolchange_to_nonsoluble) { - m_nozzle_change_result.gcode.clear(); - if (!m_filament_map.empty() && tool < m_filament_map.size() && m_filament_map[m_current_tool] != m_filament_map[tool]) { - m_nozzle_change_result = nozzle_change(m_current_tool, tool); - } + //only for tool = unsigned (-1) ,never get here + //m_nozzle_change_result.gcode.clear(); + //if (!m_filament_map.empty() && tool < m_filament_map.size() && m_filament_map[m_current_tool] != m_filament_map[tool]) { + // m_nozzle_change_result = nozzle_change(m_current_tool, tool); + //} size_t old_tool = m_current_tool; @@ -1792,7 +2115,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per (tool != (unsigned int)(-1) ? wipe_depth + m_depth_traversed - m_perimeter_width : m_wipe_tower_depth - m_perimeter_width)); - WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); + WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar, m_enable_arc_fitting); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) .set_initial_tool(m_current_tool) @@ -1801,13 +2124,14 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per "; CP TOOLCHANGE START\n") .comment_with_value(" toolchange #", m_num_tool_changes + 1); // the number is zero-based + set_for_wipe_tower_writer(writer); if (tool != (unsigned)(-1)) writer.append(std::string("; material : " + (m_current_tool < m_filpar.size() ? m_filpar[m_current_tool].material : "(NONE)") + " -> " + m_filpar[tool].material + "\n").c_str()) .append(";--------------------\n"); writer.speed_override_backup(); - writer.speed_override(100); + writer.speed_override(100); float feedrate = is_first_layer() ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, 5400.f); @@ -1857,7 +2181,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per } } - Vec2f initial_position = get_next_pos(cleaning_box, wipe_length, false, tool); + Vec2f initial_position = get_next_pos(cleaning_box, wipe_length,false); writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); if (extrude_perimeter) { @@ -1901,7 +2225,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per //BBS //if (m_set_extruder_trimpot) // writer.set_extruder_trimpot(550); // Reset the extruder current to a normal value. - writer.speed_override_restore(); + writer.speed_override_restore(); writer.feedrate(m_travel_speed * 60.f) .flush_planner_queue() .reset_extruder() @@ -1913,9 +2237,9 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per if (m_current_tool < m_used_filament_length.size()) m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length(); - return construct_tcr(writer, false, old_tool, false, true, purge_volume, false); + return construct_tcr(writer, false, old_tool, false, true, purge_volume,false); } - +#if 0 WipeTower::NozzleChangeResult WipeTower::nozzle_change(int old_filament_id, int new_filament_id) { float wipe_depth = 0.f; @@ -1940,18 +2264,27 @@ WipeTower::NozzleChangeResult WipeTower::nozzle_change(int old_filament_id, int // Otherwise we are going to Unload only. And m_layer_info would be invalid. } + auto format_nozzle_change_line = [](bool start, int old_filament_id, int new_filament_id)->std::string { + char buff[64]; + std::string tag = start ? GCodeProcessor::reserved_tag(GCodeProcessor::ETags::NozzleChangeStart) : GCodeProcessor::reserved_tag(GCodeProcessor::ETags::NozzleChangeEnd); + snprintf(buff, sizeof(buff), ";%s OF%d NF%d\n", tag.c_str(), old_filament_id, new_filament_id); + return std::string(buff); + }; + float nozzle_change_speed = 60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow; if (is_tpu_filament(m_current_tool)) { nozzle_change_speed *= 0.25; } - WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); + WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar, m_enable_arc_fitting); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) .set_initial_tool(m_current_tool) .set_extrusion_flow(m_extrusion_flow) .set_y_shift(m_y_shift + (new_filament_id != (unsigned int) (-1) && (m_current_shape == SHAPE_REVERSED) ? m_layer_info->depth - m_layer_info->toolchanges_depth() : 0.f)) - .append(format_nozzle_change_tag(true, old_filament_id, new_filament_id)); + .append(format_nozzle_change_line(true,old_filament_id,new_filament_id)); + + set_for_wipe_tower_writer(writer); box_coordinates cleaning_box(Vec2f(m_perimeter_width, m_perimeter_width), m_wipe_tower_width - 2 * m_perimeter_width, (new_filament_id != (unsigned int) (-1) ? wipe_depth + m_depth_traversed - m_perimeter_width : m_wipe_tower_depth - m_perimeter_width)); @@ -2027,14 +2360,14 @@ WipeTower::NozzleChangeResult WipeTower::nozzle_change(int old_filament_id, int } } - writer.append(format_nozzle_change_tag(false, old_filament_id, new_filament_id)); + writer.append(format_nozzle_change_line(false, old_filament_id, new_filament_id)); result.start_pos = writer.start_pos_rotated(); result.end_pos = writer.pos(); - result.gcode = std::move(writer.gcode()); + result.gcode = writer.gcode(); return result; } - +#endif // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. void WipeTower::toolchange_Unload( WipeTowerWriter &writer, @@ -2248,12 +2581,12 @@ void WipeTower::toolchange_Wipe( float wipe_length) { // Increase flow on first layer, slow down print. - writer.set_extrusion_flow(m_extrusion_flow * (is_first_layer() ? 1.15f : 1.f)) + writer.set_extrusion_flow(m_extrusion_flow * (is_first_layer() ? m_first_layer_flow_ratio : 1.f)) .append("; CP TOOLCHANGE WIPE\n"); // BBS: add the note for gcode-check, when the flow changed, the width should follow the change if (is_first_layer()) { - writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Width) + std::to_string(1.15 * m_perimeter_width) + "\n"); + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Width) + std::to_string(m_first_layer_flow_ratio * m_perimeter_width) + "\n"); } const float& xl = cleaning_box.ld.x(); @@ -2287,7 +2620,7 @@ void WipeTower::toolchange_Wipe( if (m_depth_traversed != 0) writer.travel(xl, writer.y() + dy); #endif - + bool need_change_flow = false; // now the wiping itself: for (int i = 0; true; ++i) { @@ -2382,6 +2715,21 @@ WipeTower::box_coordinates WipeTower::align_perimeter(const WipeTower::box_coord return aligned_box; } +void WipeTower::set_for_wipe_tower_writer(WipeTowerWriter &writer) +{ + writer.set_normal_acceleration(m_normal_accels); + writer.set_travel_acceleration(m_travel_accels); + writer.set_first_layer_normal_acceleration(m_first_layer_normal_accels); + writer.set_first_layer_travel_acceleration(m_first_layer_travel_accels); + writer.set_max_acceleration(m_max_accels); + writer.set_multi_nozzle_group_result(m_multi_nozzle_group_result); + writer.set_accel_to_decel_enable(m_accel_to_decel_enable); + writer.set_accel_to_decel_factor(m_accel_to_decel_factor); + writer.set_first_layer(m_cur_layer_id == 0); + writer.set_layer_id(m_cur_layer_id); + writer.set_physical_extruder_map(m_physical_extruder_map); +} +#if 0 WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool extruder_fill) { assert(! this->layer_finished()); @@ -2389,20 +2737,20 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool size_t old_tool = m_current_tool; - WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); + WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar, m_enable_arc_fitting); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) .set_initial_tool(m_current_tool) .set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)); + set_for_wipe_tower_writer(writer); + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n"); // Slow down on the 1st layer. bool first_layer = is_first_layer(); // BBS: speed up perimeter speed to 90mm/s for non-first layer float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, 5400.f); - if (m_enable_tower_interface_features && m_prev_layer_had_interface) - feedrate = std::min(feedrate, 20.f * 60.f); float fill_box_y = m_layer_info->toolchanges_depth() + m_perimeter_width; box_coordinates fill_box(Vec2f(m_perimeter_width, fill_box_y), m_wipe_tower_width - 2 * m_perimeter_width, m_layer_info->depth - fill_box_y); @@ -2545,12 +2893,40 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool if (m_current_tool < m_used_filament_length.size()) m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length(); - return construct_tcr(writer, false, old_tool, true, false, 0.f, false); + return construct_tcr(writer, false, old_tool, true, false, 0.f,false); +} +#endif +WipeTower::WipeTowerInfo::ToolChange WipeTower::set_toolchange(int old_tool, int new_tool, float layer_height, float wipe_volume, float purge_volume,int layer_id) +{ + float depth = 0.f; + float width = m_wipe_tower_width - 2 * m_perimeter_width; + float nozzle_change_width = m_wipe_tower_width - (m_nozzle_change_perimeter_width + m_perimeter_width); + float length_to_extrude = volume_to_length(wipe_volume, m_perimeter_width, layer_height); + float toolchange_gap_width = get_block_gap_width(new_tool,false); + float nozzlechange_gap_width = get_block_gap_width(old_tool,true); + float filament_change_length = !is_same_extruder(old_tool, new_tool, layer_id) ? m_filaments_change_length.first[old_tool] : m_filaments_change_length.second[old_tool]; + depth += std::ceil(length_to_extrude / width) * toolchange_gap_width; + // depth *= m_extra_spacing; + + float nozzle_change_depth = 0; + float nozzle_change_length = 0; + if (is_need_ramming(old_tool, new_tool, layer_id)) { + double e_flow = nozzle_change_extrusion_flow(layer_height); + double length = filament_change_length / e_flow; + int nozzle_change_line_count = std::ceil(length / nozzle_change_width); + nozzle_change_depth = nozzle_change_line_count * nozzlechange_gap_width; + depth += nozzle_change_depth; + nozzle_change_length = length; + } + WipeTowerInfo::ToolChange tool_change = WipeTowerInfo::ToolChange(old_tool, new_tool, depth, 0.f, 0.f, wipe_volume, length_to_extrude, purge_volume); + tool_change.nozzle_change_depth = nozzle_change_depth; + tool_change.nozzle_change_length = nozzle_change_length; + return tool_change; } // Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, - unsigned int new_tool, float wipe_volume, float purge_volume) + unsigned int new_tool, float wipe_volume_ec,float wipe_volume_nc,float purge_volume) { assert(m_plan.empty() || m_plan.back().z <= z_par + WT_EPSILON); // refuses to add a layer below the last one @@ -2570,7 +2946,8 @@ void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned in // BBS: if the wipe tower width is too small, the depth will be infinity if (width <= EPSILON) return; - + int layer_id = static_cast(m_plan.size()) - 1; + float wipe_volume = is_same_extruder(old_tool, new_tool, layer_id) && !is_same_nozzle(old_tool, new_tool, layer_id) ? wipe_volume_nc : wipe_volume_ec; // BBS: remove old filament ramming and first line #if 0 float length_to_extrude = volume_to_length(0.25f * std::accumulate(m_filpar[old_tool].ramming_speed.begin(), m_filpar[old_tool].ramming_speed.end(), 0.f), @@ -2592,39 +2969,24 @@ void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned in depth += std::ceil(length_to_extrude / width) * m_perimeter_width; //depth *= m_extra_spacing; - + float filament_change_length = !is_same_extruder(old_tool, new_tool, layer_id) ? m_filaments_change_length.first[old_tool] : m_filaments_change_length.second[old_tool]; float nozzle_change_depth = 0; - if (!m_filament_map.empty() && m_filament_map[old_tool] != m_filament_map[new_tool]) { + float nozzle_change_length = 0; + if (is_need_ramming(old_tool, new_tool, layer_id)) { double e_flow = nozzle_change_extrusion_flow(layer_height_par); - double length = m_filaments_change_length[old_tool] / e_flow; - int nozzle_change_line_count = length / (m_wipe_tower_width - 2*m_nozzle_change_perimeter_width) + 1; - if (has_tpu_filament()) - nozzle_change_depth = m_tpu_fixed_spacing * nozzle_change_line_count * m_nozzle_change_perimeter_width; - else - nozzle_change_depth = nozzle_change_line_count * m_nozzle_change_perimeter_width; - depth += nozzle_change_depth; - } - if (nozzle_change_depth == 0 - && !m_filament_nozzle_map.empty() - && old_tool < m_filament_nozzle_map.size() && new_tool < m_filament_nozzle_map.size() - && m_filament_nozzle_map[old_tool] != m_filament_nozzle_map[new_tool]) { - double e_flow = nozzle_change_extrusion_flow(layer_height_par); - double length = m_filaments_change_length[old_tool] / e_flow; - int nozzle_change_line_count = length / (m_wipe_tower_width - 2*m_nozzle_change_perimeter_width) + 1; - if (has_tpu_filament()) - nozzle_change_depth = m_tpu_fixed_spacing * nozzle_change_line_count * m_nozzle_change_perimeter_width; - else - nozzle_change_depth = nozzle_change_line_count * m_nozzle_change_perimeter_width; + double length = filament_change_length / e_flow; + int nozzle_change_line_count = std::ceil(length / (m_wipe_tower_width - 2*m_nozzle_change_perimeter_width)); + nozzle_change_depth = nozzle_change_line_count * m_nozzle_change_perimeter_width; depth += nozzle_change_depth; + nozzle_change_length = length; } WipeTowerInfo::ToolChange tool_change = WipeTowerInfo::ToolChange(old_tool, new_tool, depth, 0.f, 0.f, wipe_volume, length_to_extrude, purge_volume); tool_change.nozzle_change_depth = nozzle_change_depth; + tool_change.nozzle_change_length = nozzle_change_length; m_plan.back().tool_changes.push_back(tool_change); #endif } - - - +#if 0 void WipeTower::plan_tower() { // BBS @@ -2755,7 +3117,7 @@ void WipeTower::save_on_last_wipe() } } } - +#endif bool WipeTower::is_tpu_filament(int filament_id) const { return m_filpar[filament_id].material == "TPU"; @@ -2766,11 +3128,11 @@ bool WipeTower::is_petg_filament(int filament_id) const return m_filpar[filament_id].material == "PETG"; } -bool WipeTower::is_need_reverse_travel(int filament_id, bool extruder_change) const +bool WipeTower::is_need_reverse_travel(int filament_id,bool extruder_change) const { if (extruder_change) - return m_filpar[filament_id].ramming_travel_time.first > EPSILON; - return m_filpar[filament_id].ramming_travel_time.second > EPSILON; + return m_filpar[filament_id].ramming_travel_time.first > EPSILON && m_filaments_change_length.first[filament_id]>EPSILON; + return m_filpar[filament_id].ramming_travel_time.second > EPSILON && m_filaments_change_length.second[filament_id] > EPSILON; } // BBS: consider both soluable and support properties @@ -2785,15 +3147,13 @@ int WipeTower::first_toolchange_to_nonsoluble_nonsupport( return -1; } -static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult& first, - WipeTower::ToolChangeResult& second) +WipeTower::ToolChangeResult WipeTower::merge_tcr(ToolChangeResult &first, ToolChangeResult &second) { assert(first.new_tool == second.initial_tool); WipeTower::ToolChangeResult out = first; - out.is_contact = first.is_contact || second.is_contact; if ((first.end_pos - second.start_pos).norm() > (float)EPSILON) { std::string travel_gcode = "G1 X" + Slic3r::float_to_string_decimal_point(second.start_pos.x(), 3) + " Y" + - Slic3r::float_to_string_decimal_point(second.start_pos.y(), 3) + " F5400" + "\n"; + Slic3r::float_to_string_decimal_point(second.start_pos.y(), 3) + " F" + std::to_string(m_max_speed) + "\n"; bool need_insert_travel = true; if (second.is_tool_change && is_approx(second.start_pos.x(), second.tool_change_start_pos.x()) @@ -2811,7 +3171,7 @@ static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult& first, out.wipe_path = second.wipe_path; out.initial_tool = first.initial_tool; out.new_tool = second.new_tool; - + out.is_contact = first.is_contact || second.is_contact; if (!first.nozzle_change_result.gcode.empty()) out.nozzle_change_result = first.nozzle_change_result; else if (!second.nozzle_change_result.gcode.empty()) @@ -2834,75 +3194,108 @@ static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult& first, return out; } -void WipeTower::get_wall_skip_points(const WipeTowerInfo &layer) -{ +void WipeTower::get_all_wall_skip_points() { m_wall_skip_points.clear(); + m_wall_skip_points.resize(m_plan.size()); + for (int i = 0; i < m_plan.size(); i++) { + const WipeTowerInfo &layer = m_plan[i]; + get_wall_skip_points(m_plan[i],i); + } +} + + +void WipeTower::get_wall_skip_points(const WipeTowerInfo &layer, int layer_id) +{ + const int pre_access_layer = 4; std::unordered_map cur_block_depth; for (int i = 0; i < int(layer.tool_changes.size()); ++i) { const WipeTowerInfo::ToolChange &tool_change = layer.tool_changes[i]; size_t old_filament = tool_change.old_tool; size_t new_filament = tool_change.new_tool; - float spacing = m_layer_info->extra_spacing; - if (has_tpu_filament() && m_layer_info->extra_spacing < m_tpu_fixed_spacing) spacing = 1; - float nozzle_change_depth = tool_change.nozzle_change_depth * spacing; - // Drop the nozzle-change depth on an extruder's final layer above its printable height - // (inert unless is_valid_last_layer clamps, i.e. multi-extruder near Z-max). - if (!is_valid_last_layer(old_filament, m_cur_layer_id, layer.z)) nozzle_change_depth = 0.f; - //float nozzle_change_depth = tool_change.nozzle_change_depth * (has_tpu_filament() ? m_tpu_fixed_spacing : layer.extra_spacing); - auto* block = get_block_by_category(m_filpar[new_filament].category, false); - if (!block) - continue; - //float wipe_depth = tool_change.required_depth - nozzle_change_depth; - float wipe_depth = ceil(tool_change.wipe_length / (m_wipe_tower_width - 2 * m_perimeter_width)) * m_perimeter_width*layer.extra_spacing; - float process_depth = 0.f; - if (!cur_block_depth.count(m_filpar[new_filament].category)) - cur_block_depth[m_filpar[new_filament].category] = block->start_depth; + float nozzle_change_depth = tool_change.nozzle_change_depth; + float wipe_depth = tool_change.required_depth - nozzle_change_depth; + if (!is_valid_last_layer(old_filament, layer_id, m_plan[layer_id].z)) nozzle_change_depth = 0.f; + auto *block = get_block_by_category(m_filpar[new_filament].category, false); + if (!block) continue; + float process_depth = 0.f; + if (!cur_block_depth.count(m_filpar[new_filament].category)) cur_block_depth[m_filpar[new_filament].category] = block->start_depth; process_depth = cur_block_depth[m_filpar[new_filament].category]; - if (!m_filament_map.empty() && new_filament < m_filament_map.size() && m_filament_map[old_filament] != m_filament_map[new_filament]) { + if (is_need_ramming(new_filament, old_filament, layer_id)) { if (m_filament_categories[new_filament] == m_filament_categories[old_filament]) process_depth += nozzle_change_depth; else { if (!cur_block_depth.count(m_filpar[old_filament].category)) { - auto* old_block = get_block_by_category(m_filpar[old_filament].category, false); - if (!old_block) - continue; + auto *old_block = get_block_by_category(m_filpar[old_filament].category, false); + if (!old_block) continue; cur_block_depth[m_filpar[old_filament].category] = old_block->start_depth; } cur_block_depth[m_filpar[old_filament].category] += nozzle_change_depth; } } - { - Vec2f res; - int index = m_cur_layer_id % 4; - switch (index % 4) { - case 0: res = Vec2f(0, process_depth); break; - case 1: res = Vec2f(m_wipe_tower_width, process_depth + wipe_depth - layer.extra_spacing*m_perimeter_width); break; - case 2: res = Vec2f(m_wipe_tower_width, process_depth); break; - case 3: res = Vec2f(0, process_depth + wipe_depth - layer.extra_spacing * m_perimeter_width); break; - default: break; - } - m_wall_skip_points.emplace_back(res); + float infill_gap_width = get_block_gap_width(new_filament, false); + Vec2f res; + int index = layer_id % 4; + switch (index % 4) { + case 0: res = Vec2f(0, process_depth); break; + case 1: res = Vec2f(m_wipe_tower_width, process_depth + wipe_depth - m_plan[layer_id].extra_spacing * infill_gap_width); break; + case 2: res = Vec2f(m_wipe_tower_width, process_depth); break; + case 3: res = Vec2f(0, process_depth + wipe_depth - m_plan[layer_id].extra_spacing * infill_gap_width); break; + default: break; + } + + m_wall_skip_points[layer_id].emplace_back(res); + + cur_block_depth[m_filpar[new_filament].category] = process_depth + wipe_depth; + + bool solid_toolchange = block->layers_type[layer_id] == WipeTowerLayerType::Contact; + if (solid_toolchange && m_enable_tower_interface_features) { + for (int j = 0; j < pre_access_layer; j++) { + int pre_layer_id = layer_id - j; + if (pre_layer_id < 0) break; + m_wall_skip_points[pre_layer_id].push_back(res); + } } - cur_block_depth[m_filpar[new_filament].category] = process_depth + tool_change.required_depth - tool_change.nozzle_change_depth * layer.extra_spacing; } + if (m_enable_tower_interface_features) { + for (auto &block : m_wipe_tower_blocks) { + float block_depth = cur_block_depth.count(block.filament_adhesiveness_category) ? cur_block_depth[block.filament_adhesiveness_category] : block.start_depth; + if (block_depth + EPSILON >= block.start_depth + block.layer_depths[layer_id] - m_perimeter_width) { continue; } + bool block_solid = block.layers_type[layer_id] == WipeTowerLayerType::Contact; + bool add_skip_point = block_solid && std::abs(block_depth - block.start_depth) < EPSILON; + if (add_skip_point) { + Vec2f res; + int index = layer_id % 4; + + float dy_skip = block.layer_depths[layer_id] - m_perimeter_width; + int n_skip = (int) ((dy_skip + 0.25f * m_perimeter_width) / m_perimeter_width + 1); + float gird_depth = m_perimeter_width * (n_skip - 1); // in sync with finish_block_solid + switch (index % 4) { + case 0: res = Vec2f(0, block_depth); break; + case 1: res = Vec2f(m_wipe_tower_width, block_depth + gird_depth); break; + case 2: res = Vec2f(m_wipe_tower_width, block_depth); break; + case 3: res = Vec2f(0, block_depth + gird_depth); break; + default: break; + } + m_wall_skip_points[layer_id].emplace_back(res); + for (int j = 0; j < pre_access_layer; j++) { + int pre_layer_id = layer_id - j; + if (pre_layer_id < 0) break; + m_wall_skip_points[pre_layer_id].push_back(res); + } + } + } } +} WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool solid_toolchange,bool solid_nozzlechange) { m_nozzle_change_result.gcode.clear(); - // Skip the cross-extruder nozzle change (ramming) on an extruder's final layer above its printable - // height. is_valid_last_layer is inert unless multi-extruder near Z-max. - if (!m_filament_map.empty() && new_tool < m_filament_map.size() && m_filament_map[m_current_tool] != m_filament_map[new_tool] - && is_valid_last_layer(m_current_tool, m_cur_layer_id, m_z_pos)) { - m_nozzle_change_result = nozzle_change_new(m_current_tool, new_tool, solid_nozzlechange); - } - if (m_nozzle_change_result.gcode.empty() - && !m_filament_nozzle_map.empty() - && m_current_tool < m_filament_nozzle_map.size() && new_tool < m_filament_nozzle_map.size() - && m_filament_nozzle_map[m_current_tool] != m_filament_nozzle_map[new_tool] - && is_valid_last_layer(m_current_tool, m_cur_layer_id, m_z_pos)) { - m_nozzle_change_result = nozzle_change_new(m_current_tool, new_tool, solid_nozzlechange); + bool hotend_change = false; + if (is_need_ramming(m_current_tool,new_tool, m_cur_layer_id)) { + hotend_change = is_same_extruder(m_current_tool, new_tool, m_cur_layer_id); + //If it is the last layer and exceeds the printable height, cancel ramming + if (is_valid_last_layer(m_current_tool, m_cur_layer_id, m_z_pos)) m_nozzle_change_result = ramming(m_current_tool, new_tool, solid_nozzlechange, !hotend_change); } size_t old_tool = m_current_tool; @@ -2919,32 +3312,19 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol wipe_depth = b.required_depth; purge_volume = b.purge_volume; nozzle_change_depth = b.nozzle_change_depth; - if (has_tpu_filament()) - nozzle_change_line_count = ((b.nozzle_change_depth + WT_EPSILON) / m_nozzle_change_perimeter_width) / 2; - else - nozzle_change_line_count = (b.nozzle_change_depth + WT_EPSILON) / m_nozzle_change_perimeter_width; break; } } - - bool interface_layer = solid_toolchange && m_enable_tower_interface_features; - if (interface_layer && new_tool < m_filpar.size()) { - float extra_purge_length = m_filpar[new_tool].tower_interface_purge_length; - if (extra_purge_length > 0.f) { - purge_volume += extra_purge_length * m_filpar[new_tool].filament_area; - wipe_length += extra_purge_length; - } - } - + m_current_tool = new_tool; WipeTowerBlock* block = get_block_by_category(m_filpar[new_tool].category, false); if (!block) { assert(block != nullptr); return WipeTower::ToolChangeResult(); } m_cur_block = block; - box_coordinates cleaning_box(Vec2f(m_perimeter_width, block->cur_depth), m_wipe_tower_width - 2 * m_perimeter_width, wipe_depth-m_layer_info->extra_spacing*nozzle_change_depth); + box_coordinates cleaning_box(Vec2f(m_perimeter_width, block->cur_depth), m_wipe_tower_width - 2 * m_perimeter_width, wipe_depth-nozzle_change_depth); - WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); + WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar, m_enable_arc_fitting); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) .set_initial_tool(m_current_tool) @@ -2953,6 +3333,8 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol "; CP TOOLCHANGE START\n") .comment_with_value(" toolchange #", m_num_tool_changes + 1); // the number is zero-based + set_for_wipe_tower_writer(writer); + if (new_tool != (unsigned) (-1)) writer.append( std::string("; material : " + (m_current_tool < m_filpar.size() ? m_filpar[m_current_tool].material : "(NONE)") + " -> " + m_filpar[new_tool].material + "\n").c_str()) .append(";--------------------\n"); @@ -2962,7 +3344,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. if (new_tool != (unsigned int) -1) { // This is not the last change. - Vec2f initial_position = get_next_pos(cleaning_box, wipe_length, interface_layer, new_tool); + Vec2f initial_position = get_next_pos(cleaning_box, wipe_length, solid_toolchange); writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n"); @@ -2970,25 +3352,8 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol is_first_layer() ? m_filpar[new_tool].nozzle_temperature_initial_layer : m_filpar[new_tool].nozzle_temperature); toolchange_Change(writer, new_tool, m_filpar[new_tool].material); // Change the tool, set a speed override for soluble and flex materials. toolchange_Load(writer, cleaning_box); - - int base_temp = is_first_layer() ? m_filpar[new_tool].nozzle_temperature_initial_layer : m_filpar[new_tool].nozzle_temperature; - if (interface_layer) { - int interface_temp = m_filpar[new_tool].interface_print_temperature; - if (interface_temp > 0 && interface_temp != base_temp) - writer.set_extruder_temp(interface_temp, true); - if (m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp) - writer.set_extruder_temp(base_temp, false); - float pre_dist = m_filpar[new_tool].tower_interface_pre_extrusion_dist; - float pre_len = m_filpar[new_tool].tower_interface_pre_extrusion_length; - if (pre_dist > 0.f && pre_len > 0.f) { - bool start_left = (m_cur_layer_id % 4 == 0 || m_cur_layer_id % 4 == 3); - float target_x = writer.x() + (start_left ? pre_dist : -pre_dist); - target_x = std::max(cleaning_box.ld.x(), std::min(cleaning_box.rd.x(), target_x)); - writer.extrude_explicit(target_x, writer.y(), pre_len, 600.f); - } - } - - if (m_is_multi_extruder && is_tpu_filament(new_tool)) { +# if 0 + if (m_is_multi_extruder && is_need_reverse_travel(new_tool)) { float dy = m_layer_info->extra_spacing * m_nozzle_change_perimeter_width; if (m_layer_info->extra_spacing < m_tpu_fixed_spacing) { dy = m_tpu_fixed_spacing * m_nozzle_change_perimeter_width; @@ -3019,22 +3384,15 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol } writer.travel(initial_position); } - +#endif toolchange_wipe_new(writer, cleaning_box, wipe_length, solid_toolchange); - if (interface_layer) { - int base_temp = is_first_layer() ? m_filpar[new_tool].nozzle_temperature_initial_layer : m_filpar[new_tool].nozzle_temperature; - int interface_temp = m_filpar[new_tool].interface_print_temperature; - if (!m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp) - writer.set_extruder_temp(base_temp, false); - } - writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n"); ++m_num_tool_changes; } else toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, m_filpar[m_current_tool].nozzle_temperature); - block->cur_depth += (wipe_depth - nozzle_change_depth * m_layer_info->extra_spacing); + block->cur_depth += (wipe_depth - nozzle_change_depth); block->last_filament_change_id = new_tool; // BBS @@ -3050,192 +3408,187 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol if (m_current_tool < m_used_filament_length.size()) m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length(); - return construct_tcr(writer, false, old_tool, false, true, purge_volume, interface_layer); + return construct_tcr(writer, false, old_tool, false, true, purge_volume, solid_toolchange); } -WipeTower::NozzleChangeResult WipeTower::nozzle_change_new(int old_filament_id, int new_filament_id, bool solid_infill) +//for extruder change and nozzle change +WipeTower::NozzleChangeResult WipeTower::ramming(int old_filament_id, int new_filament_id, bool solid_infill, bool extruder_change) { + auto format_line_M106 = []() { return std::string{"M106 S255\n"};}; + auto format_line_M633 = []() { return std::string{"M633\n"};}; + auto format_line_M632 = [](int filament_id, int nozzle_id) { + std::string buffer = "M632 S" + std::to_string(filament_id); + if (nozzle_id >= 0) + buffer += " H" + std::to_string(nozzle_id); + buffer += " M N\n"; + return buffer; + }; + int nozzle_change_line_count = 0; + float x_offset = m_perimeter_width + (m_nozzle_change_perimeter_width - m_perimeter_width) / 2; + float nozzle_change_box_width = m_wipe_tower_width - 2 * x_offset; + float nozzle_change_depth = 0.f; if (new_filament_id != (unsigned int) (-1)) { for (const auto &b : m_layer_info->tool_changes) if (b.new_tool == new_filament_id) { - if (has_tpu_filament()) - nozzle_change_line_count = ((b.nozzle_change_depth + WT_EPSILON) / m_nozzle_change_perimeter_width) / 2; - else - nozzle_change_line_count = (b.nozzle_change_depth + WT_EPSILON) / m_nozzle_change_perimeter_width; + nozzle_change_line_count = std::ceil(b.nozzle_change_length / nozzle_change_box_width); + nozzle_change_depth = b.nozzle_change_depth; break; } } + auto format_nozzle_change_line = [this](bool start, int old_filament_id, int new_filament_id) -> std::string { + char buff[64]; + // Orca: the nozzle-change markers are standalone tag constants, not ETags entries + // (the Reserved_Tags parallel arrays have a non-BBL variant that must stay aligned). + std::string tag = start ? GCodeProcessor::Nozzle_Change_Start_Tag : GCodeProcessor::Nozzle_Change_End_Tag; + int old_nozzle_id = get_nozzle_id(old_filament_id, m_cur_layer_id); + int new_nozzle_id = get_nozzle_id(new_filament_id, m_cur_layer_id); + snprintf(buff, sizeof(buff), ";%s OF%d NF%d ON%d NN%d\n", tag.c_str(), old_filament_id, new_filament_id,old_nozzle_id,new_nozzle_id); + return std::string(buff); + }; float nz_extrusion_flow = nozzle_change_extrusion_flow(m_layer_height); - bool extruder_change = !is_in_same_extruder(old_filament_id, new_filament_id); - float max_e_ramming = extruder_change - ? m_filpar[m_current_tool].max_e_ramming_speed.first - : m_filpar[m_current_tool].max_e_ramming_speed.second; - if (max_e_ramming < EPSILON) max_e_ramming = m_filpar[m_current_tool].max_e_speed; // fallback - float nozzle_change_speed = 60.0f * max_e_ramming / nz_extrusion_flow; - nozzle_change_speed = solid_infill ? 40.f * 60.f : nozzle_change_speed; - - if (is_tpu_filament(m_current_tool)) { - nozzle_change_speed *= 0.25; - } - float bridge_speed = std::min(60.0f * max_e_ramming / nozzle_change_extrusion_flow(0.2), nozzle_change_speed); - - WipeTowerWriter writer(m_layer_height, m_nozzle_change_perimeter_width, m_gcode_flavor, m_filpar); + WipeTowerWriter writer(m_layer_height, m_nozzle_change_perimeter_width, m_gcode_flavor, m_filpar, m_enable_arc_fitting); writer.set_extrusion_flow(nz_extrusion_flow) .set_z(m_z_pos) .set_initial_tool(m_current_tool) - .set_y_shift(m_y_shift + (new_filament_id != (unsigned int) (-1) && (m_current_shape == SHAPE_REVERSED) ? m_layer_info->depth - m_layer_info->toolchanges_depth() : 0.f)) - .append(format_nozzle_change_tag(true, old_filament_id, new_filament_id)); - - if (!extruder_change && m_is_multiple_nozzle) { - writer.append("M632 S" + std::to_string(new_filament_id) + " M N\n"); - // Use m_physical_extruder_map for heater index (matches format_line_M104 in add_M104_by_requirement) - if (m_filpar[m_current_tool].precool_target_temp.second != 0) { - int logical_ext = m_filament_map.empty() ? 0 : m_filament_map[m_current_tool] - 1; - int phys_ext = (logical_ext >= 0 && logical_ext < (int)m_physical_extruder_map.size()) - ? m_physical_extruder_map[logical_ext] : logical_ext; - writer.append("M400\n"); - writer.append("M104 T" + std::to_string(phys_ext) + " S" + - std::to_string(m_filpar[m_current_tool].precool_target_temp.second) + " N0\n"); - writer.append("M106 S255\n"); - } - writer.append("M633\n"); - } + .set_y_shift(m_y_shift + (new_filament_id != (unsigned int) (-1) && (m_current_shape == SHAPE_REVERSED) ? m_layer_info->depth - m_layer_info->toolchanges_depth() : 0.f)); + set_for_wipe_tower_writer(writer); WipeTowerBlock* block = get_block_by_category(m_filpar[old_filament_id].category, false); if (!block) { assert(false); return WipeTower::NozzleChangeResult(); } - m_cur_block = block; - float dy = m_layer_info->extra_spacing * m_nozzle_change_perimeter_width; - if (has_tpu_filament() && m_extra_spacing < m_tpu_fixed_spacing) - dy = m_tpu_fixed_spacing * m_nozzle_change_perimeter_width; - - float x_offset = m_perimeter_width + (m_nozzle_change_perimeter_width - m_perimeter_width) / 2; - box_coordinates cleaning_box(Vec2f(x_offset,block->cur_depth + (m_nozzle_change_perimeter_width - m_perimeter_width) / 2), - m_wipe_tower_width - 2 * x_offset, - nozzle_change_line_count * dy - (m_nozzle_change_perimeter_width - m_perimeter_width) / 2); + m_cur_block = block; + float dy = is_first_layer() ? m_nozzle_change_perimeter_width : m_layer_info->extra_spacing * get_block_gap_width(m_current_tool, true); + box_coordinates cleaning_box(Vec2f(x_offset, block->cur_depth + (m_nozzle_change_perimeter_width - m_perimeter_width) / 2), + nozzle_change_box_width, + nozzle_change_depth); Vec2f initial_position = cleaning_box.ld; writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); - const float &xl = cleaning_box.ld.x(); - const float &xr = cleaning_box.rd.x(); - dy = solid_infill ? m_nozzle_change_perimeter_width : dy; - nozzle_change_line_count = solid_infill ? std::numeric_limits::max() : nozzle_change_line_count; - m_left_to_right = true; - - if (extruder_change) { - float ramming_length = nozzle_change_line_count * (xr - xl); - int extruder_id = m_filament_map.empty() ? 0 : m_filament_map[m_current_tool] - 1; - float precool_t = (extruder_id >= 0 && extruder_id < (int)m_filpar[m_current_tool].precool_t.first.size()) - ? m_filpar[m_current_tool].precool_t.first[extruder_id] : 0.f; - float precool_t_fl = (extruder_id >= 0 && extruder_id < (int)m_filpar[m_current_tool].precool_t_first_layer.first.size()) - ? m_filpar[m_current_tool].precool_t_first_layer.first[extruder_id] : 0.f; - float per_cooling_max_speed = nozzle_change_speed; - if (is_first_layer() && precool_t_fl > EPSILON) - per_cooling_max_speed = ramming_length / precool_t_fl * 60.f; - else if (precool_t > EPSILON) - per_cooling_max_speed = ramming_length / precool_t * 60.f; - if (nozzle_change_speed > per_cooling_max_speed) nozzle_change_speed = per_cooling_max_speed; - if (bridge_speed > per_cooling_max_speed) bridge_speed = per_cooling_max_speed; - } - - int real_nozzle_change_line_count = 0; - bool need_change_flow = false; - for (int i = 0; true; ++i) { - if (need_thick_bridge_flow(writer.pos().y())) { - writer.set_extrusion_flow(nozzle_change_extrusion_flow(0.2)); - writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) + std::to_string(0.2) + "\n"); - need_change_flow = true; + // --- Nozzle change preamble: notify firmware + precool --- + writer.append(format_nozzle_change_line(true, old_filament_id, new_filament_id)); + if (!extruder_change) { + int new_nozzle_id = m_multi_nozzle_group_result->is_support_dynamic_nozzle_map() + ? get_nozzle_id(new_filament_id, m_cur_layer_id) : -1; + writer.append(format_line_M632(new_filament_id, new_nozzle_id)); + if (m_filpar[m_current_tool].precool_target_temp.second != 0) { + writer.format_line_M104(m_filpar[m_current_tool].precool_target_temp.second, get_extruder_id(m_current_tool, m_cur_layer_id)) + .append(format_line_M106()); } - if (m_left_to_right) - writer.extrude(xr + wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), need_change_flow ? bridge_speed : nozzle_change_speed); - else - writer.extrude(xl - wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), need_change_flow ? bridge_speed : nozzle_change_speed); - real_nozzle_change_line_count++; - if (i == nozzle_change_line_count - 1) - break; - if ((writer.y() + dy - cleaning_box.ru.y()+(m_nozzle_change_perimeter_width+m_perimeter_width)/2) > (float)EPSILON) break; - if (need_change_flow) { - writer.set_extrusion_flow(nozzle_change_extrusion_flow(m_layer_height)); - writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) + std::to_string(m_layer_height) + "\n"); - need_change_flow = false; - } - writer.extrude(writer.x(), writer.y() + dy, nozzle_change_speed); - m_left_to_right = !m_left_to_right; + writer.append(format_line_M633()); } - if (need_change_flow) { - writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) + std::to_string(m_layer_height) + "\n"); - } - writer.set_extrusion_flow(nz_extrusion_flow); // Reset the extrusion flow. - block->cur_depth += real_nozzle_change_line_count * dy; - block->last_nozzle_change_id = old_filament_id; NozzleChangeResult result; - if (!extruder_change && m_is_multiple_nozzle) { - writer.append("M632 S" + std::to_string(new_filament_id) + " M N\n"); - } - if (is_need_reverse_travel(m_current_tool, extruder_change)) { - bool left_to_right = !m_left_to_right; - int tpu_line_count = real_nozzle_change_line_count; - float reverse_speed = nozzle_change_speed * 2; // reverse travel runs at double the nozzle-change speed - float rt_time = extruder_change ? m_filpar[m_current_tool].ramming_travel_time.first - : m_filpar[m_current_tool].ramming_travel_time.second; - float need_reverse_travel_dis = rt_time * reverse_speed / 60.f; - float real_travel_dis = tpu_line_count * (xr - xl - 2 * m_perimeter_width); - if (real_travel_dis < need_reverse_travel_dis) - reverse_speed *= real_travel_dis / need_reverse_travel_dis; - writer.travel(writer.x(), writer.y() + dy/2); + if (nozzle_change_line_count > 0) { + float max_e_ramming_speed = extruder_change ? m_filpar[m_current_tool].max_e_ramming_speed.first : m_filpar[m_current_tool].max_e_ramming_speed.second; + float nozzle_change_speed = 60.0f * max_e_ramming_speed / nz_extrusion_flow; + if (solid_infill) + nozzle_change_speed = std::min(40.f * 60.f, nozzle_change_speed); + float bridge_speed = std::min(60.0f * max_e_ramming_speed / nozzle_change_extrusion_flow(0.2), nozzle_change_speed); + const float &xl = cleaning_box.ld.x(); + const float &xr = cleaning_box.rd.x(); + dy = solid_infill ? m_nozzle_change_perimeter_width : dy; + if (solid_infill) + nozzle_change_line_count = std::floor(EPSILON + (cleaning_box.ru[1] - cleaning_box.rd[1] + (m_nozzle_change_perimeter_width - m_perimeter_width) / 2.f) / + m_nozzle_change_perimeter_width); + m_left_to_right = true; + bool need_change_flow = false; + float ramming_length = nozzle_change_line_count * (xr - xl); + int extruder_id = get_extruder_id(m_current_tool, m_cur_layer_id); + float precool_t = extruder_change ? m_filpar[m_current_tool].precool_t.first[extruder_id] : m_filpar[m_current_tool].precool_t.second[extruder_id]; + float precool_t_first_layer = extruder_change ? m_filpar[m_current_tool].precool_t_first_layer.first[extruder_id] : + m_filpar[m_current_tool].precool_t_first_layer.second[extruder_id]; + float per_cooling_max_speed = nozzle_change_speed; + if (extruder_change) { + if (is_first_layer() && precool_t_first_layer > EPSILON) + per_cooling_max_speed = ramming_length / precool_t_first_layer * 60.f; + else if (precool_t > EPSILON) + per_cooling_max_speed = ramming_length / precool_t * 60.f; + }//BBS:nozzle change does not require forcing a cooldown to a specific temperature. + if (nozzle_change_speed > per_cooling_max_speed) nozzle_change_speed = per_cooling_max_speed; + if (bridge_speed > per_cooling_max_speed) bridge_speed = per_cooling_max_speed; + LimitFlow LimitRamming = extruder_change ? LimitFlow::LimitRammingFlow : LimitFlow::LimitRammingFlowNC; for (int i = 0; true; ++i) { - need_reverse_travel_dis -= (xr - xl - 2 * m_perimeter_width); - float offset_dis = 0.f; - if (need_reverse_travel_dis < 0) - offset_dis = -need_reverse_travel_dis; - if (left_to_right) - writer.travel(xr - m_perimeter_width - offset_dis, writer.y(), reverse_speed); + if (need_thick_bridge_flow(writer.pos().y())) { + writer.set_extrusion_flow(nozzle_change_extrusion_flow(0.2)); + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) + std::to_string(0.2) + "\n"); + need_change_flow = true; + } + if (m_left_to_right) + writer.extrude(xr + wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), need_change_flow ? bridge_speed : nozzle_change_speed, LimitRamming); else - writer.travel(xl + m_perimeter_width + offset_dis, writer.y(), reverse_speed); - if (need_reverse_travel_dis < EPSILON) break; - if (i == tpu_line_count - 1) + writer.extrude(xl - wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), need_change_flow ? bridge_speed : nozzle_change_speed, LimitRamming); + if (i == nozzle_change_line_count - 1) break; - writer.travel(writer.x(), writer.y() - dy); - left_to_right = !left_to_right; + if ((writer.y() + dy - cleaning_box.ru.y()+(m_nozzle_change_perimeter_width+m_perimeter_width)/2) > (float)EPSILON) break; + if (need_change_flow) { + writer.set_extrusion_flow(nozzle_change_extrusion_flow(m_layer_height)); + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) + std::to_string(m_layer_height) + "\n"); + need_change_flow = false; + } + writer.extrude(writer.x(), writer.y() + dy, nozzle_change_speed, LimitRamming); + m_left_to_right = !m_left_to_right; } - } else if (is_tpu_filament(m_current_tool)) { - bool left_to_right = !m_left_to_right; - int tpu_line_count = (real_nozzle_change_line_count + 2 - 1) / 2; - nozzle_change_speed *= 2; - writer.travel(writer.x(), writer.y() - m_nozzle_change_perimeter_width); - - for (int i = 0; true; ++i) { - if (left_to_right) - writer.travel(xr - m_perimeter_width, writer.y(), nozzle_change_speed); - else - writer.travel(xl + m_perimeter_width, writer.y(), nozzle_change_speed); - - if (i == tpu_line_count - 1) - break; - - writer.travel(writer.x(), writer.y() - dy); - left_to_right = !left_to_right; + if (need_change_flow) { + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) + std::to_string(m_layer_height) + "\n"); } - } else { - result.wipe_path.push_back(writer.pos_rotated()); - if (m_left_to_right) { - result.wipe_path.push_back(Vec2f(0, writer.pos_rotated().y())); + + writer.set_extrusion_flow(nz_extrusion_flow); + block->cur_depth += nozzle_change_depth; + block->last_nozzle_change_id = old_filament_id; + // --- Post-ramming: re-arm nozzle change for travel phase --- + if (!extruder_change) { + int new_nozzle_id = m_multi_nozzle_group_result->is_support_dynamic_nozzle_map() + ? get_nozzle_id(new_filament_id, m_cur_layer_id) : -1; + writer.append(format_line_M632(new_filament_id, new_nozzle_id)); + } + + if (is_need_reverse_travel(m_current_tool, extruder_change)) { + bool left_to_right = !m_left_to_right; + int tpu_line_count = nozzle_change_line_count; + nozzle_change_speed *= 2; // due to nozzle change 2 perimeter + float ramming_travel_time = extruder_change ? m_filpar[m_current_tool].ramming_travel_time.first : m_filpar[m_current_tool].ramming_travel_time.second; + float need_reverse_travel_dis = ramming_travel_time * nozzle_change_speed / 60.f; + float real_travel_dis = tpu_line_count * (xr - xl - 2 * m_perimeter_width); + if (real_travel_dis < need_reverse_travel_dis) + nozzle_change_speed *= real_travel_dis / need_reverse_travel_dis; + writer.travel(writer.x(), writer.y() + dy/2); + + for (int i = 0; true; ++i) { + need_reverse_travel_dis -= (xr - xl - 2 * m_perimeter_width); + float offset_dis = 0.f; + if (need_reverse_travel_dis < 0) { + offset_dis = -need_reverse_travel_dis; + } + if (left_to_right) + writer.travel(xr - m_perimeter_width - offset_dis, writer.y(), nozzle_change_speed); + else + writer.travel(xl + m_perimeter_width + offset_dis , writer.y(), nozzle_change_speed); + if (need_reverse_travel_dis < EPSILON) break; + if (i == tpu_line_count - 1) + break; + + writer.travel(writer.x(), writer.y() - dy); + left_to_right = !left_to_right; + } } else { - result.wipe_path.push_back(Vec2f(m_wipe_tower_width, writer.pos_rotated().y())); + result.wipe_path.push_back(writer.pos_rotated()); + if (m_left_to_right) { + result.wipe_path.push_back(Vec2f(0, writer.pos_rotated().y())); + } else { + result.wipe_path.push_back(Vec2f(m_wipe_tower_width, writer.pos_rotated().y())); + } } + if (!extruder_change) writer.append(format_line_M633()); } - if (!extruder_change && m_is_multiple_nozzle) writer.append("M633\n"); - - writer.append(format_nozzle_change_tag(false, old_filament_id, new_filament_id)); + writer.append(format_nozzle_change_line(false, old_filament_id, new_filament_id)); result.start_pos = writer.start_pos_rotated(); result.origin_start_pos = initial_position; @@ -3250,91 +3603,110 @@ WipeTower::ToolChangeResult WipeTower::finish_layer_new(bool extrude_perimeter, assert(!this->layer_finished()); m_current_layer_finished = true; - WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); + WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar, m_enable_arc_fitting); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) .set_initial_tool(m_current_tool) .set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)); + set_for_wipe_tower_writer(writer); + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n"); // Slow down on the 1st layer. bool first_layer = is_first_layer(); // BBS: speed up perimeter speed to 90mm/s for non-first layer - float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, 5400.f); - - float fill_box_depth = m_wipe_tower_depth - 2 * m_perimeter_width; - if (m_wipe_tower_blocks.size() == 1) { - fill_box_depth = m_layer_info->depth - 2 * m_perimeter_width; - } - box_coordinates fill_box(Vec2f(m_perimeter_width, m_perimeter_width), m_wipe_tower_width - 2 * m_perimeter_width, fill_box_depth); - - writer.set_initial_position((m_left_to_right ? fill_box.ru : fill_box.lu), m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); + float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, m_max_speed) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, m_max_speed); bool toolchanges_on_layer = m_layer_info->toolchanges_depth() > WT_EPSILON; std::vector finish_rect_wipe_path; - if (extrude_fill_wall) { - // inner perimeter of the sparse section, if there is space for it: - if (fill_box.ru.y() - fill_box.rd.y() > WT_EPSILON) { - writer.rectangle_fill_box(this, fill_box, finish_rect_wipe_path, feedrate); + const bool multi_block_fill = (m_wipe_tower_blocks.size() > 1) && (extrude_fill_wall || extrude_fill); + + // Build list of fill boxes: one per block when multi_block_fill, else one for whole tower. + std::vector fill_boxes; + if (multi_block_fill) { + for (const WipeTowerBlock &block : m_wipe_tower_blocks) { + float block_fill_height = block.depth - 2 * m_perimeter_width; + if (m_cur_layer_id >= 0 && size_t(m_cur_layer_id) < block.layer_depths.size()) + block_fill_height = block.layer_depths[m_cur_layer_id] - 2 * m_perimeter_width; + if (block_fill_height <= WT_EPSILON) + continue; + fill_boxes.emplace_back( + Vec2f(m_perimeter_width, block.start_depth + m_perimeter_width), + m_wipe_tower_width - 2 * m_perimeter_width, + block_fill_height); } } + if (fill_boxes.empty()) { + float fill_box_depth = m_wipe_tower_depth - 2 * m_perimeter_width; + if (m_wipe_tower_blocks.size() == 1) + fill_box_depth = m_layer_info->depth - 2 * m_perimeter_width; + fill_boxes.emplace_back(Vec2f(m_perimeter_width, m_perimeter_width), m_wipe_tower_width - 2 * m_perimeter_width, fill_box_depth); + } - // Extrude infill to support the material to be printed above. - const float dy = (fill_box.lu.y() - fill_box.ld.y() - m_perimeter_width); - float left = fill_box.lu.x() + 2 * m_perimeter_width; - float right = fill_box.ru.x() - 2 * m_perimeter_width; - if (extrude_fill && dy > m_perimeter_width) { - writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f)) - .append(";--------------------\n" - "; CP EMPTY GRID START\n") - .comment_with_value(" layer #", m_num_layer_changes + 1); + writer.set_initial_position((m_left_to_right ? fill_boxes.front().ru : fill_boxes.front().lu), m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); - // Is there a soluble filament wiped/rammed at the next layer? - // If so, the infill should not be sparse. - bool solid_infill = m_layer_info + 1 == m_plan.end() ? - false : - std::any_of((m_layer_info + 1)->tool_changes.begin(), (m_layer_info + 1)->tool_changes.end(), - [this](const WipeTowerInfo::ToolChange &tch) { return m_filpar[tch.new_tool].is_soluble || m_filpar[tch.old_tool].is_soluble; }); - solid_infill |= first_layer && m_adhesion; + bool solid_infill = (m_layer_info + 1 == m_plan.end()) ? false : + std::any_of((m_layer_info + 1)->tool_changes.begin(), (m_layer_info + 1)->tool_changes.end(), + [this](const WipeTowerInfo::ToolChange &tch) { return m_filpar[tch.new_tool].is_soluble || m_filpar[tch.old_tool].is_soluble; }); + solid_infill |= first_layer && m_adhesion; - if (solid_infill) { - float sparse_factor = 1.5f; // 1=solid, 2=every other line, etc. - if (first_layer) { // the infill should touch perimeters - left -= m_perimeter_width; - right += m_perimeter_width; - sparse_factor = 1.f; - } - float y = fill_box.ld.y() + m_perimeter_width; - int n = dy / (m_perimeter_width * sparse_factor); - float spacing = (dy - m_perimeter_width) / (n - 1); - int i = 0; - for (i = 0; i < n; ++i) { - writer.extrude(writer.x(), y, feedrate).extrude(i % 2 ? left : right, y); - y = y + spacing; - } - writer.extrude(writer.x(), fill_box.lu.y()); - } else { - // Extrude an inverse U at the left of the region and the sparse infill. - writer.extrude(fill_box.lu + Vec2f(m_perimeter_width * 2, 0.f), feedrate); + for (size_t i = 0; i < fill_boxes.size(); ++i) { + const box_coordinates &fill_box = fill_boxes[i]; + if (i > 0) + writer.travel(m_left_to_right ? fill_box.ru : fill_box.lu); - const int n = 1 + int((right - left) / m_bridging); - const float dx = (right - left) / n; - for (int i = 1; i <= n; ++i) { - float x = left + dx * i; - writer.travel(x, writer.y()); - writer.extrude(x, i % 2 ? fill_box.rd.y() : fill_box.ru.y()); + if (extrude_fill_wall && (fill_box.ru.y() - fill_box.rd.y() > WT_EPSILON)) + writer.rectangle_fill_box(this, fill_box, finish_rect_wipe_path, feedrate); + // Extrude infill to support the material to be printed above. + const float dy = (fill_box.lu.y() - fill_box.ld.y() - m_perimeter_width); + float left = fill_box.lu.x() + 2 * m_perimeter_width; + float right = fill_box.ru.x() - 2 * m_perimeter_width; + + if (extrude_fill && dy > m_perimeter_width) { + writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f)) + .append(";--------------------\n" + "; CP EMPTY GRID START\n") + .comment_with_value(" layer #", m_num_layer_changes + 1); + + if (solid_infill) { + float sparse_factor = 1.5f; // 1=solid, 2=every other line, etc. + if (first_layer) { // the infill should touch perimeters + left -= m_perimeter_width; + right += m_perimeter_width; + sparse_factor = 1.f; + } + float y = fill_box.ld.y() + m_perimeter_width; + int n = dy / (m_perimeter_width * sparse_factor); + float spacing = (dy - m_perimeter_width) / (n - 1); + int i = 0; + for (i = 0; i < n; ++i) { + writer.extrude(writer.x(), y, feedrate).extrude(i % 2 ? left : right, y); + y = y + spacing; + } + writer.extrude(writer.x(), fill_box.lu.y()); + } else { + // Extrude an inverse U at the left of the region and the sparse infill. + writer.extrude(fill_box.lu + Vec2f(m_perimeter_width * 2, 0.f), feedrate); + + const int n = 1 + int((right - left) / m_bridging); + const float dx = (right - left) / n; + for (int i = 1; i <= n; ++i) { + float x = left + dx * i; + writer.travel(x, writer.y()); + writer.extrude(x, i % 2 ? fill_box.rd.y() : fill_box.ru.y()); + } + + finish_rect_wipe_path.clear(); + // BBS: add wipe_path for this case: only with finish rectangle + finish_rect_wipe_path.emplace_back(writer.pos()); + finish_rect_wipe_path.emplace_back(Vec2f(left + dx * n, n % 2 ? fill_box.ru.y() : fill_box.rd.y())); } - finish_rect_wipe_path.clear(); - // BBS: add wipe_path for this case: only with finish rectangle - finish_rect_wipe_path.emplace_back(writer.pos()); - finish_rect_wipe_path.emplace_back(Vec2f(left + dx * n, n % 2 ? fill_box.ru.y() : fill_box.rd.y())); + writer.append("; CP EMPTY GRID END\n" + ";------------------\n\n\n\n\n\n\n"); } - - writer.append("; CP EMPTY GRID END\n" - ";------------------\n\n\n\n\n\n\n"); } // outer perimeter (always): @@ -3419,23 +3791,25 @@ WipeTower::ToolChangeResult WipeTower::finish_layer_new(bool extrude_perimeter, m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length(); m_nozzle_change_result.gcode.clear(); - return construct_tcr(writer, false, m_current_tool, true, false, 0.f, false); + return construct_tcr(writer, false, m_current_tool, true, false, 0.f,false); } WipeTower::ToolChangeResult WipeTower::finish_block(const WipeTowerBlock &block, int filament_id, bool extrude_fill) { - WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); + WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar, m_enable_arc_fitting); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) .set_initial_tool(filament_id) .set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)); + set_for_wipe_tower_writer(writer); + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n"); // Slow down on the 1st layer. bool first_layer = is_first_layer(); // BBS: speed up perimeter speed to 90mm/s for non-first layer - float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[filament_id].max_e_speed / m_extrusion_flow, 5400.f); + float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, m_max_speed) : std::min(60.0f * m_filpar[filament_id].max_e_speed / m_extrusion_flow, m_max_speed); box_coordinates fill_box(Vec2f(0, 0), 0, 0); fill_box = box_coordinates(Vec2f(m_perimeter_width, block.cur_depth), m_wipe_tower_width - 2 * m_perimeter_width, block.start_depth + block.layer_depths[m_cur_layer_id] - block.cur_depth - m_perimeter_width); @@ -3529,49 +3903,96 @@ WipeTower::ToolChangeResult WipeTower::finish_block(const WipeTowerBlock &block, return construct_block_tcr(writer, false, filament_id, true, 0.f); } -WipeTower::ToolChangeResult WipeTower::finish_block_solid(const WipeTowerBlock &block, int filament_id, bool extrude_fill, bool interface_solid) +WipeTower::ToolChangeResult WipeTower::finish_block_solid(const WipeTowerBlock &block, int filament_id, bool extrude_fill, WipeTowerLayerType layer_type) { float layer_height = m_layer_height; float e_flow = m_extrusion_flow; - if (m_cur_layer_id > 1 && !block.solid_infill[m_cur_layer_id - 1] && m_extrusion_flow < extrusion_flow(0.2)) { + if (m_cur_layer_id > 1 && block.layers_type[m_cur_layer_id - 1]==WipeTowerLayerType::Normal && m_extrusion_flow < extrusion_flow(0.2)) { layer_height = 0.2; e_flow = extrusion_flow(0.2); } - WipeTowerWriter writer(layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); + WipeTowerWriter writer(layer_height, m_perimeter_width, m_gcode_flavor, m_filpar, m_enable_arc_fitting); writer.set_extrusion_flow(e_flow) .set_z(m_z_pos) .set_initial_tool(filament_id) .set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)); + set_for_wipe_tower_writer(writer); + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n"); // Slow down on the 1st layer. bool first_layer = is_first_layer(); // BBS: speed up perimeter speed to 90mm/s for non-first layer - float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[filament_id].max_e_speed / m_extrusion_flow, 5400.f); - feedrate = interface_solid ? 20.f * 60.f : feedrate; + float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, m_max_speed) : std::min(60.0f * m_filpar[filament_id].max_e_speed / m_extrusion_flow, m_max_speed); + feedrate = (layer_type == WipeTowerLayerType::Contact || layer_type == WipeTowerLayerType::Contact_UP) ? 20.f * 60.f : feedrate; box_coordinates fill_box(Vec2f(0, 0), 0, 0); fill_box = box_coordinates(Vec2f(m_perimeter_width, block.cur_depth), m_wipe_tower_width - 2 * m_perimeter_width, block.start_depth + block.layer_depths[m_cur_layer_id] - block.cur_depth - m_perimeter_width); - - writer.set_initial_position((m_left_to_right ? fill_box.rd : fill_box.ld), m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); - m_left_to_right = !m_left_to_right; bool toolchanges_on_layer = m_layer_info->toolchanges_depth() > WT_EPSILON; - + const float dy = (fill_box.lu.y() - fill_box.ld.y()); + int n = (dy + 0.25 * m_perimeter_width) / m_perimeter_width+1; + float spacing = m_perimeter_width; + Vec2f initial_pos(0, 0); + bool up_to_down = false; + //set initial pos + { + int index = m_cur_layer_id % 4; + float gird_depth = spacing * (n-1); + switch (index % 4) { + case 0: + initial_pos = fill_box.ld; + m_left_to_right = true; + up_to_down = false; + break; + case 1: + initial_pos = Vec2f(fill_box.rd.x(), fill_box.rd.y() + gird_depth); + m_left_to_right = false; + up_to_down = true; + break; + case 2: + initial_pos = fill_box.rd; + m_left_to_right = false; + up_to_down = false; + break; + case 3: + initial_pos = Vec2f(fill_box.ld.x(), gird_depth + fill_box.ld.y()); + m_left_to_right = true; + up_to_down = true; + break; + default: break; + } + } // Extrude infill to support the material to be printed above. - const float dy = (fill_box.lu.y() - fill_box.ld.y()); float left = fill_box.lu.x(); float right = fill_box.ru.x(); std::vector finish_rect_wipe_path; { - writer.append(";--------------------\n" + writer + .append(";--------------------\n" "; CP EMPTY GRID START\n") .comment_with_value(" layer #", m_num_layer_changes + 1); + bool is_full_block = std::abs(block.cur_depth - block.start_depth) < EPSILON; + if (is_full_block && layer_type == WipeTowerLayerType::Contact && m_enable_tower_interface_features ) { + Vec2f stop_pos = initial_pos; + float filament_tower_interface_pre_extrusion_dist = m_filpar[m_current_tool].filament_tower_interface_pre_extrusion_dist; + // Orca: unscaled(BoundingBox) here is a template returning BoundingBoxBase, not BoundingBoxf + auto printer_bbx = unscaled(get_extents(m_shared_print_bed)); + printer_bbx.translate((- m_wipe_tower_pos - m_rib_offset).cast()); // first layer never be contact + if (stop_pos.x() < m_wipe_tower_width/2.f) + stop_pos = Vec2f(stop_pos.x() - filament_tower_interface_pre_extrusion_dist, stop_pos.y()); + else + stop_pos = Vec2f(stop_pos.x() + filament_tower_interface_pre_extrusion_dist, stop_pos.y()); + if (stop_pos.x() < printer_bbx.min[0]) stop_pos.x() = printer_bbx.min[0]; + if (stop_pos.x() > printer_bbx.max[0]) stop_pos.x() = printer_bbx.max[0]; + initial_pos = stop_pos; + if (m_filpar[m_current_tool].filament_tower_interface_print_temp != m_filpar[m_current_tool].nozzle_temperature) + writer.format_line_M109(m_filpar[m_current_tool].filament_tower_interface_print_temp, get_extruder_id(m_current_tool, m_cur_layer_id)); + writer.retract(-m_filpar[m_current_tool].filament_tower_interface_pre_extrusion_length - 2.f, 100.f); + } + writer.set_initial_position(initial_pos, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); - float y = fill_box.ld.y(); - int n = (dy + 0.25 * m_perimeter_width) / m_perimeter_width + 1; - float spacing = m_perimeter_width; int i = 0; for (i = 0; i < n; ++i) { writer.extrude(m_left_to_right ? right : left, writer.y(), feedrate); @@ -3580,10 +4001,10 @@ WipeTower::ToolChangeResult WipeTower::finish_block_solid(const WipeTowerBlock & break; } m_left_to_right = !m_left_to_right; - y = y + spacing; - writer.extrude(writer.x(), y, feedrate); + writer.extrude(writer.x(), writer.y()+spacing*(up_to_down?-1:1), feedrate); } - + if (layer_type == WipeTowerLayerType::Contact && m_enable_tower_interface_features && m_filpar[m_current_tool].filament_tower_interface_print_temp != m_filpar[m_current_tool].nozzle_temperature) + writer.format_line_M104(m_filpar[m_current_tool].nozzle_temperature, get_extruder_id(m_current_tool, m_cur_layer_id)); writer.append("; CP EMPTY GRID END\n" ";------------------\n\n\n\n\n\n\n"); } @@ -3601,50 +4022,53 @@ WipeTower::ToolChangeResult WipeTower::finish_block_solid(const WipeTowerBlock & void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinates &cleaning_box, float wipe_length,bool solid_tool_toolchange) { - writer.set_extrusion_flow(m_extrusion_flow * (is_first_layer() ? 1.15f : 1.f)).append("; CP TOOLCHANGE WIPE\n"); - + writer.set_extrusion_flow(m_extrusion_flow * (is_first_layer() ? m_first_layer_flow_ratio : 1.f)) + // Orca: CP_TOOLCHANGE_WIPE is a standalone tag constant, not an ETags entry + .append(";" + GCodeProcessor::Toolchange_Wipe_Tag + " CT" + std::to_string(solid_tool_toolchange) + " FL" + std::to_string(is_first_layer()) + "\n"); if (!m_nozzle_change_result.gcode.empty()) writer.change_analyzer_line_width(m_perimeter_width); // BBS: add the note for gcode-check, when the flow changed, the width should follow the change if (is_first_layer()) { - writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Width) + std::to_string(1.15 * m_perimeter_width) + "\n"); + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Width) + std::to_string(m_first_layer_flow_ratio * m_perimeter_width) + "\n"); } + + //if (solid_tool_toolchange && m_filpar[m_current_tool].filament_tower_interface_print_temp != m_filpar[m_current_tool].nozzle_temperature) + // writer.append(format_line_M109(m_filpar[m_current_tool].filament_tower_interface_print_temp, m_filament_map[this->m_current_tool] - 1)); + //if (solid_tool_toolchange && m_filpar[m_current_tool].filament_tower_interface_pre_extrusion_length != 0) + // writer.retract(-m_filpar[m_current_tool].filament_tower_interface_pre_extrusion_length, 100.f); + float retract_length = m_filpar[m_current_tool].retract_length; float retract_speed = m_filpar[m_current_tool].retract_speed * 60; - const float ironing_area = m_filpar[m_current_tool].tower_ironing_area; - const bool do_ironing = m_flat_ironing && (!solid_tool_toolchange || !m_enable_tower_interface_features); - const float &xl = cleaning_box.ld.x(); const float &xr = cleaning_box.rd.x(); - + bool should_flat_ironging = m_flat_ironing; + bool should_line_ironing = true; + if (!m_contact_ironing && solid_tool_toolchange) { + should_flat_ironging = false; + should_line_ironing = false; + } + bool should_cooling_before_tower = !solid_tool_toolchange; + bool should_cooling_before_object = false;//interface layer heating print tower, then cooling print object + int cooling_begin_line = 2; float x_to_wipe = wipe_length; - float dy = solid_tool_toolchange ? m_perimeter_width :m_layer_info->extra_spacing * m_perimeter_width; + float dy = is_first_layer() ? m_perimeter_width : m_layer_info->extra_spacing * get_block_gap_width(m_current_tool,false); + if (solid_tool_toolchange) + dy = m_perimeter_width; x_to_wipe = solid_tool_toolchange ? std::numeric_limits::max(): x_to_wipe; - float target_speed = is_first_layer() ? std::min(m_first_layer_speed * 60.f, 4800.f) : 4800.f; - target_speed = solid_tool_toolchange ? 20.f * 60.f : target_speed; - // Nominal wipe-speed schedule. The applied wipe_speed is nominal_speed * speed_factor; speed_factor - // stays 1.0 unless the H2C prime-tower heating-during-wipe model below slows the wipe so the hotend - // can reach temperature (nominal_speed == wipe_speed when speed_factor == 1, i.e. single-nozzle). - float nominal_speed = 0.33f * target_speed; + float target_speed = is_first_layer() ? std::min(m_first_layer_speed * 60.f, m_max_speed) : m_max_speed; + target_speed = solid_tool_toolchange ? m_contact_speed : target_speed; + const std::vector WipeSpeedMap{0.33f * target_speed, 0.375f * target_speed, 0.458f * target_speed, 0.875f * target_speed, + std::min(target_speed, 0.875f * target_speed + 50.f)}; + float wipe_speed = WipeSpeedMap[0]; m_left_to_right = ((m_cur_layer_id + 3) % 4 >= 2); bool is_from_up = (m_cur_layer_id % 2 == 1); - // Prime-tower heating during wipe. Everything here is gated on m_is_multiple_nozzle (false for every - // current printer); the lambdas emit nothing until add_M104_by_requirement's gate opens, so the - // single-nozzle wipe is untouched. - // WipeSpeedMap mirrors the nominal schedule above and is read only by estimate_wipe_time. It is a - // std::array (stack, no per-call heap allocation); values depend on runtime target_speed so it - // cannot be static const. - const std::array WipeSpeedMap{0.33f * target_speed, 0.375f * target_speed, 0.458f * target_speed, - 0.875f * target_speed, std::min(target_speed, 0.875f * target_speed + 50.f)}; - auto estimate_wipe_time = [&cleaning_box, &x_to_wipe, &xr, &xl, &dy, &WipeSpeedMap, &solid_tool_toolchange]() -> float { - int n = std::ceil(x_to_wipe / (xr - xl)); - if (solid_tool_toolchange) n = (cleaning_box.lu[1] - cleaning_box.ld[1]) / dy; + auto estimate_time_kernel = [&WipeSpeedMap,&xr,&xl](int n) { + float time = std::numeric_limits::max(); float one_line_len = xr - xl; - float time = std::numeric_limits::max(); if (n <= 1) time = one_line_len / WipeSpeedMap[0]; else if (n <= 2) @@ -3659,65 +4083,51 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat } return time * 60.f; }; - // Emit the arriving-hotend pre-heat inside the M632/M633 nozzle-change barrier. `M632 S[ H] - // M N` opens the barrier (M = firmware nozzle-change flag, N = slicer generated), the M104 sets the - // arriving hotend temp, and `M633` closes it. H2C's grouping is static (no dynamic nozzle map), so the - // H field is omitted (a dynamic nozzle map would supply a real nozzle id, a static map -1 =>no - // H). The counterproductive fan-on (M106 S255) used for departing-tool cooldown is intentionally - // omitted, since this is a pre-HEAT of the arriving tool. The whole helper is only ever called from - // add_M104_by_requirement, which is gated on m_is_multiple_nozzle (extruder_max_nozzle_count>1) => H2C - // only; every other printer's wipe tower is untouched. - // BBS: extruder change preheat uses M400 + M104 WITHOUT M632/M633 barrier. - // M632 barriers are only for carousel nozzle changes (emitted in nozzle_change_new/ramming). - auto format_line_M104 = [this](int target_temp, int target_extruder = -1, bool wait_for_moves = true, const std::string &comment = "") { - std::string buffer; - if (wait_for_moves) - buffer += "M400\n"; - buffer += "M104"; - if (target_extruder != -1 && target_extruder < (int) m_physical_extruder_map.size()) - buffer += (" T" + std::to_string(m_physical_extruder_map[target_extruder])); - buffer += " S" + std::to_string(target_temp) + " N0"; // N0 means the gcode is generated by the slicer - if (!comment.empty()) buffer += " ;" + comment; - buffer += '\n'; - return buffer; + auto estimate_wipe_time = [&estimate_time_kernel, & cleaning_box, &target_speed, &x_to_wipe, &xr, &xl, &dy, &WipeSpeedMap, &solid_tool_toolchange](int begin_line) -> float { + int n = std::ceil(x_to_wipe / (xr - xl)); + if (solid_tool_toolchange) n = (cleaning_box.lu[1] - cleaning_box.ld[1]) / dy; + float total_time = estimate_time_kernel(n); + float beg_time = n <= 0 ? 0 : estimate_time_kernel(begin_line); + return total_time-beg_time; }; - // m_is_multiple_nozzle gate needed because Orca calls toolchange_wipe_new for ALL printers (BBS has it H2C-only). - bool should_heating = m_is_multiple_nozzle && m_filpar[m_current_tool].filament_cooling_before_tower > EPSILON && - !solid_tool_toolchange && !is_first_layer(); - auto add_M104_by_requirement = [&writer, &format_line_M104, &should_heating, this]() { + + bool should_heating = m_filpar[m_current_tool].filament_cooling_before_tower > EPSILON && !solid_tool_toolchange && !is_first_layer(); + auto add_M104_by_requirement = [&writer, &should_heating, this]() { if (m_filpar[m_current_tool].filament_cooling_before_tower < EPSILON) return; if (!should_heating) return; float target_temp = is_first_layer() ? m_filpar[m_current_tool].nozzle_temperature_initial_layer : m_filpar[m_current_tool].nozzle_temperature; - writer.append(format_line_M104(target_temp, m_filament_map[m_current_tool] - 1)); + writer.format_line_M104(target_temp, get_extruder_id(m_current_tool, m_cur_layer_id)); }; float speed_factor = 1.f; - if (should_heating) { - // The heating-slowdown scaling is disabled — no additional heating time is required, so - // speed_factor stays 1.0. The structure and estimate_wipe_time/WipeSpeedMap are retained for - // future H2C tuning; the divide-by-zero/bounds guard is preserved in the commented body below. - // int extruder_id = m_filament_map[m_current_tool] - 1; - // if (extruder_id >= 0 && extruder_id < (int) m_hotend_heating_rate.size() && m_hotend_heating_rate[extruder_id] > 0.) { - // float estimate_time = estimate_wipe_time(); - // float heat_time = m_filpar[m_current_tool].filament_cooling_before_tower / m_hotend_heating_rate[extruder_id]; - // if (estimate_time < heat_time) speed_factor = estimate_time / heat_time; - // } - (void) estimate_wipe_time; // retain scaffolding above without an unused-lambda warning + if (should_heating) + { + //No additional heating time is required. + //float estimate_time = estimate_wipe_time(0); + //int extruder_id = m_filament_map[m_current_tool] - 1; + //float heat_time = m_filpar[m_current_tool].filament_cooling_before_tower / m_hotend_heating_rate[extruder_id]; + //heat_time /= 2.f; + //speed_factor = estimate_time / (heat_time+estimate_time); + //wipe_speed *= speed_factor; } - float wipe_speed = nominal_speed * speed_factor; - - // now the wiping itself: - for (int i = 0; true; ++i) { - if (i != 0) { - if (nominal_speed < 0.34f * target_speed) - nominal_speed = 0.375f * target_speed; - else if (nominal_speed < 0.377 * target_speed) - nominal_speed = 0.458f * target_speed; - else if (nominal_speed < 0.46f * target_speed) - nominal_speed = 0.875f * target_speed; - else - nominal_speed = std::min(target_speed, nominal_speed + 50.f); - wipe_speed = nominal_speed * speed_factor; + if (should_cooling_before_object) { + int n = (cleaning_box.lu[1] - cleaning_box.ld[1]) / dy; + int extruder_id = get_extruder_id(m_current_tool, m_cur_layer_id); + float cooling_time = (m_filpar[m_current_tool].filament_tower_interface_print_temp - m_filpar[m_current_tool].nozzle_temperature) / m_hotend_cooling_rate[extruder_id]; + if (n < 2) { + float estimate_time = estimate_wipe_time(0); + speed_factor = estimate_time > cooling_time? 1: estimate_time / cooling_time; + cooling_begin_line = 0; + } else { + float estimate_time = estimate_wipe_time(2); + speed_factor = estimate_time > cooling_time ? 1 : estimate_time / cooling_time; + cooling_begin_line = 2; //TODO: No slowdown for the first two lines. } + wipe_speed *= speed_factor; + } + + + for (int i = 0; true; ++i) { + if (i < WipeSpeedMap.size()) wipe_speed = WipeSpeedMap[i] * speed_factor; bool need_change_flow = need_thick_bridge_flow(writer.y()); // BBS: check the bridging area and use the bridge flow @@ -3725,44 +4135,53 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat writer.set_extrusion_flow(extrusion_flow(0.2)); writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) + std::to_string(0.2) + "\n"); } - + float flat_iron_area = m_filpar[m_current_tool].flat_iron_area; float ironing_length = 3.; + + if (should_cooling_before_object && i == cooling_begin_line) { + writer.format_line_M104(m_filpar[m_current_tool].nozzle_temperature, get_extruder_id(m_current_tool, m_cur_layer_id)); + } + if (i == 0 && m_use_gap_wall) { // BBS: add ironing after extruding start if (m_left_to_right) { - float dx = xr + wipe_tower_wall_infill_overlap * m_perimeter_width - writer.pos().x(); - if (abs(dx) < ironing_length) ironing_length = abs(dx); - writer.extrude(writer.x() + ironing_length, writer.y(), wipe_speed); - writer.retract(retract_length, retract_speed); - writer.travel(writer.x() - 1.5 * ironing_length, writer.y(), 600.); - if (do_ironing && ironing_area > 0.f) { - writer.travel(writer.x() + 0.5f * ironing_length, writer.y(), 240.); - Vec2f pos{writer.x() + 1.f * ironing_length, writer.y()}; - writer.spiral_flat_ironing(writer.pos(), ironing_area, m_perimeter_width, flat_iron_speed); - writer.travel(pos, wipe_speed); - } else - writer.travel(writer.x() + 1.5 * ironing_length, writer.y(), 240.); - writer.retract(-retract_length, retract_speed); - add_M104_by_requirement(); // Pre-heat the arriving hotend during the wipe + if (should_line_ironing) { + float dx = xr + wipe_tower_wall_infill_overlap * m_perimeter_width - writer.pos().x(); + if (abs(dx) < ironing_length) ironing_length = abs(dx); + writer.extrude(writer.x() + ironing_length, writer.y(), wipe_speed); + writer.retract(retract_length, retract_speed); + writer.travel(writer.x() - 1.5 * ironing_length, writer.y(), 600.); + if (should_flat_ironging) { + writer.travel(writer.x() + 0.5f * ironing_length, writer.y(), 240.); + Vec2f pos{writer.x() + 1.f * ironing_length, writer.y()}; + writer.spiral_flat_ironing(writer.pos(), flat_iron_area, m_perimeter_width, flat_iron_speed); + writer.travel(pos, wipe_speed); + } else + writer.travel(writer.x() + 1.5 * ironing_length, writer.y(), 240.); + writer.retract(-retract_length, retract_speed); + } + add_M104_by_requirement(); writer.extrude(xr + wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed); } else { - float dx = xl - wipe_tower_wall_infill_overlap * m_perimeter_width - writer.pos().x(); - if (abs(dx) < ironing_length) ironing_length = abs(dx); - writer.extrude(writer.x() - ironing_length, writer.y(), wipe_speed); - writer.retract(retract_length, retract_speed); - writer.travel(writer.x() + 1.5 * ironing_length, writer.y(), 600.); - if (do_ironing && ironing_area > 0.f) { - writer.travel(writer.x() - 0.5f * ironing_length, writer.y(), 240.); - Vec2f pos{writer.x() - 1.0f * ironing_length, writer.y()}; - writer.spiral_flat_ironing(writer.pos(), ironing_area, m_perimeter_width, flat_iron_speed); - writer.travel(pos, wipe_speed); - }else - writer.travel(writer.x() - 1.5 * ironing_length, writer.y(), 240.); - writer.retract(-retract_length, retract_speed); - add_M104_by_requirement(); // Pre-heat the arriving hotend during the wipe + if (should_line_ironing) { + float dx = xl - wipe_tower_wall_infill_overlap * m_perimeter_width - writer.pos().x(); + if (abs(dx) < ironing_length) ironing_length = abs(dx); + writer.extrude(writer.x() - ironing_length, writer.y(), wipe_speed); + writer.retract(retract_length, retract_speed); + writer.travel(writer.x() + 1.5 * ironing_length, writer.y(), 600.); + if (should_flat_ironging) { + writer.travel(writer.x() - 0.5f * ironing_length, writer.y(), 240.); + Vec2f pos{writer.x() - 1.0f * ironing_length, writer.y()}; + writer.spiral_flat_ironing(writer.pos(), flat_iron_area, m_perimeter_width, flat_iron_speed); + writer.travel(pos, wipe_speed); + } else + writer.travel(writer.x() - 1.5 * ironing_length, writer.y(), 240.); + writer.retract(-retract_length, retract_speed); + } + add_M104_by_requirement(); writer.extrude(xl - wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed); } } else { - if (i == 0) add_M104_by_requirement(); // Pre-heat the arriving hotend during the wipe + if (i == 0) add_M104_by_requirement(); if (m_left_to_right) writer.extrude(xr + wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed); else @@ -3855,67 +4274,6 @@ int WipeTower::get_filament_category(int filament_id) return m_filament_categories[filament_id]; } -bool WipeTower::is_in_same_extruder(int filament_id_1, int filament_id_2) -{ - if (filament_id_1 >= m_filament_map.size() || filament_id_2 >= m_filament_map.size()) - return true; - - return m_filament_map[filament_id_1] == m_filament_map[filament_id_2]; -} - -std::string WipeTower::format_nozzle_change_tag(bool start, int old_filament_id, int new_filament_id) const -{ - const std::string &tag = start ? GCodeProcessor::Nozzle_Change_Start_Tag : GCodeProcessor::Nozzle_Change_End_Tag; - int old_nozzle = (old_filament_id >= 0 && old_filament_id < (int)m_filament_nozzle_map.size()) - ? m_filament_nozzle_map[old_filament_id] : -1; - int new_nozzle = (new_filament_id >= 0 && new_filament_id < (int)m_filament_nozzle_map.size()) - ? m_filament_nozzle_map[new_filament_id] : -1; - char buff[96]; - snprintf(buff, sizeof(buff), ";%s OF%d NF%d ON%d NN%d\n", tag.c_str(), old_filament_id, new_filament_id, old_nozzle, new_nozzle); - return std::string(buff); -} - -// Per-extruder printable-height clamp: is an extruder still allowed to print on this wipe-tower layer, -// or is it its final layer above the extruder's printable height? -// Orca: the arriving extruder id is resolved as m_filament_map[tool]-1 (1-based map, layer-static), -// because Orca's wipe tower is extruder-level rather than tracking a per-layer nozzle map (the same -// idiom the pre-heat path uses in toolchange_wipe_new). Gated on m_is_multi_extruder so that -// single-extruder printers (including ones whose extruder_printable_height defaults to {0}) always -// return true and leave wipe-tower g-code unchanged. -bool WipeTower::is_valid_last_layer(int tool, int layer_id, double layer_z) const -{ - if (!m_is_multi_extruder) - return true; - int extruder_id = (tool >= 0 && tool < (int) m_filament_map.size()) ? m_filament_map[tool] - 1 : -1; - if (extruder_id < 0 || extruder_id >= (int) m_printable_height.size() || extruder_id >= (int) m_last_layer_id.size()) - return true; - if (m_last_layer_id[extruder_id] == layer_id && layer_z > m_printable_height[extruder_id]) - return false; - return true; -} - -// Records, per extruder, the last wipe-tower layer index that uses it, so is_valid_last_layer can -// recognise the extruder's final layer. Inert for single-extruder printers (early return); -// bounds-checked because m_filament_map may be empty/short. -void WipeTower::set_nozzle_last_layer_id() -{ - if (!m_is_multi_extruder) - return; - for (int idx = 0; idx < (int) m_plan.size(); ++idx) { - const auto &info = m_plan[idx]; - for (const auto &tc : info.tool_changes) { - int old_tool = (int) tc.old_tool; - int new_tool = (int) tc.new_tool; - int old_ext = (old_tool >= 0 && old_tool < (int) m_filament_map.size()) ? m_filament_map[old_tool] - 1 : -1; - int new_ext = (new_tool >= 0 && new_tool < (int) m_filament_map.size()) ? m_filament_map[new_tool] - 1 : -1; - if (old_ext >= 0 && old_ext < (int) m_last_layer_id.size()) - m_last_layer_id[old_ext] = idx; - if (new_ext >= 0 && new_ext < (int) m_last_layer_id.size()) - m_last_layer_id[new_ext] = idx; - } - } -} - void WipeTower::reset_block_status() { for (auto &block : m_wipe_tower_blocks) { @@ -3924,6 +4282,39 @@ void WipeTower::reset_block_status() block.last_nozzle_change_id = -1; } } +void WipeTower::set_nozzle_last_layer_id() +{ + for (int idx = 0; idx < m_plan.size(); idx++) { + auto &info = m_plan[idx]; + for(int i =0 ; i= 0) m_last_layer_id[get_extruder_id(old_tool, idx)] = idx; + m_last_layer_id[get_extruder_id(new_tool, idx)] = idx; + } + } +} + +void WipeTower::set_first_layer_flow_ratio(const float flow_ratio) +{ + m_first_layer_flow_ratio = flow_ratio; +} + +// Orca: default/initial-layer/travel acceleration are object-scope options here (PrintConfig +// members read directly in the BBS ctor), so Print resolves the columns and pushes them in. +void WipeTower::set_accelerations(const std::vector &normal, const std::vector &first_layer_normal, + const std::vector &travel, const std::vector &first_layer_travel) +{ + auto to_accels = [](const std::vector &values, std::vector &accels) { + accels.clear(); + for (double value : values) + accels.emplace_back((unsigned int) floor(value + 0.5)); + }; + to_accels(normal, m_normal_accels); + to_accels(first_layer_normal, m_first_layer_normal_accels); + to_accels(travel, m_travel_accels); + to_accels(first_layer_travel, m_first_layer_travel_accels); +} void WipeTower::update_all_layer_depth(float wipe_tower_depth) { @@ -3956,7 +4347,7 @@ void WipeTower::update_all_layer_depth(float wipe_tower_depth) } } -void WipeTower::generate_wipe_tower_blocks() +void WipeTower::generate_wipe_tower_blocks(bool add_solid_flag) { // 1. generate all layer depth m_all_layers_depth.clear(); @@ -3964,7 +4355,7 @@ void WipeTower::generate_wipe_tower_blocks() m_cur_layer_id = 0; for (auto& info : m_plan) { for (const WipeTowerInfo::ToolChange &tool_change : info.tool_changes) { - if (is_in_same_extruder(tool_change.old_tool, tool_change.new_tool)) { + if (!is_need_ramming(tool_change.old_tool, tool_change.new_tool, m_cur_layer_id)) { int filament_adhesiveness_category = get_filament_category(tool_change.new_tool); add_depth_to_block(tool_change.new_tool, filament_adhesiveness_category, tool_change.required_depth); } @@ -3997,35 +4388,13 @@ void WipeTower::generate_wipe_tower_blocks() auto* block = get_block_by_category(iter->first, true); if (block->layer_depths.empty()) { block->layer_depths.resize(all_layer_category_to_depth.size(), 0); - block->solid_infill.resize(all_layer_category_to_depth.size(), false); block->finish_depth.resize(all_layer_category_to_depth.size(), 0); + block->layers_type.resize(all_layer_category_to_depth.size(), WipeTowerLayerType::Normal); } block->depth = std::max(block->depth, iter->second); block->layer_depths[layer_id] = iter->second; } } - - // add solid infill flag - int solid_infill_layer = 4; - for (WipeTowerBlock& block : m_wipe_tower_blocks) { - for (int layer_id = 0; layer_id < all_layer_category_to_depth.size(); ++layer_id) { - std::unordered_map &category_to_depth = all_layer_category_to_depth[layer_id]; - if (is_approx(category_to_depth[block.filament_adhesiveness_category], 0.f)) { - int layer_count = solid_infill_layer; - while (layer_count > 0) { - if (layer_id + layer_count < all_layer_category_to_depth.size()) { - std::unordered_map& up_layer_depth = all_layer_category_to_depth[layer_id + layer_count]; - if (!is_approx(up_layer_depth[block.filament_adhesiveness_category], 0.f)) { - block.solid_infill[layer_id] = true; - break; - } - } - --layer_count; - } - } - } - } - // 4. get real depth for every layer for (int layer_id = m_plan.size() - 1; layer_id >= 0; --layer_id) { m_plan[layer_id].depth = 0; @@ -4045,54 +4414,166 @@ void WipeTower::generate_wipe_tower_blocks() } } } + + // add solid infill flag + if (add_solid_flag) { + int solid_infill_layer_low = 4; + std::vector> layers_used_tools; + + int first_tool = -1; + for (const auto &layer : m_plan) { + if (!layer.tool_changes.empty()) { + first_tool = layer.tool_changes.front().old_tool; + break; + } + } + for (auto &info : m_plan) { + std::unordered_set used_tools; + if (info.tool_changes.empty()) { + used_tools.insert(get_filament_category(first_tool)); + } else { + for (const WipeTowerInfo::ToolChange &tool_change : info.tool_changes) { + used_tools.insert(get_filament_category(tool_change.old_tool)); + used_tools.insert(get_filament_category(tool_change.new_tool)); + } + first_tool = info.tool_changes.back().new_tool; + } + layers_used_tools.push_back(used_tools); + } + + for (WipeTowerBlock &block : m_wipe_tower_blocks) { + for (int layer_id = 0; layer_id < all_layer_category_to_depth.size(); ++layer_id) { + std::unordered_map &category_to_depth = all_layer_category_to_depth[layer_id]; + if (category_to_depth[block.filament_adhesiveness_category] < block.layer_depths[layer_id] - m_perimeter_width) { + bool cur_has_block_category = layers_used_tools[layer_id].count(block.filament_adhesiveness_category); + int layer_count = solid_infill_layer_low; + while (layer_count > 0) { + if (layer_id + layer_count < all_layer_category_to_depth.size()) { + std::unordered_map &up_layer_depth = all_layer_category_to_depth[layer_id + layer_count]; + { + bool up_has_block_category = layers_used_tools[layer_id + layer_count].count(block.filament_adhesiveness_category); + if (cur_has_block_category != up_has_block_category) { + block.layers_type[layer_id] = WipeTowerLayerType::Solid; + break; + } + } + } + --layer_count; + } + } + if (layer_id > 0) { + bool cur_has_block_category = layers_used_tools[layer_id].count(block.filament_adhesiveness_category); + bool pre_has_block_category = layers_used_tools[layer_id - 1].count(block.filament_adhesiveness_category); + if (cur_has_block_category != pre_has_block_category) { block.layers_type[layer_id] = WipeTowerLayerType::Contact; } + if (block.layers_type[layer_id - 1] == WipeTowerLayerType::Contact && block.layers_type[layer_id] != WipeTowerLayerType::Contact) { + block.layers_type[layer_id] = WipeTowerLayerType::Contact_UP; + } + } + } + } + } + +} +void WipeTower::calc_block_infill_gap() +{ + //1.calc block infill gap width + struct BlockInfo + { + bool has_ramming = false; + bool has_reverse_travel = false; + float depth = 0.f; + }; + std::unordered_map block_info; + std::unordered_map high_block_info; + for (int i= (int)m_plan.size()-1;i>=0;i--) + { + for (auto &toolchange : m_plan[i].tool_changes) { + int new_tool =toolchange.new_tool; + int old_tool =toolchange.old_tool; + if (is_need_ramming(old_tool,new_tool, i)) { + bool extruder_change = !is_same_extruder(new_tool, old_tool, i); + block_info[m_filpar[old_tool].category].has_ramming=true; + if (is_need_reverse_travel(old_tool, extruder_change)) block_info[m_filpar[old_tool].category].has_reverse_travel = true; + block_info[m_filpar[old_tool].category].depth += toolchange.nozzle_change_depth; + } + if (!block_info.count(m_filpar[new_tool].category)) block_info.insert({m_filpar[new_tool].category,BlockInfo{}}); + block_info[m_filpar[new_tool].category].depth += toolchange.required_depth - toolchange.nozzle_change_depth; + } + for (auto &block : block_info) { + if (high_block_info.count(block.first) && high_block_info[block.first].depth > block.second.depth) + block.second.depth = high_block_info[block.first].depth; + } + high_block_info = block_info; + + for (auto &block : block_info) { block.second.depth = 0.f;} + if (i == 0) block_info = high_block_info; + } + float max_depth = std::accumulate(block_info.begin(), block_info.end(), 0.f, [](float value, const std::pair &block) { return value + block.second.depth; }); + float height_to_depth = get_limit_depth_by_height(m_wipe_tower_height); + float height_to_spacing = max_depth > height_to_depth ? 1.f : height_to_depth / max_depth; + + float spacing_ratio = m_extra_spacing - 1.f; + float extra_width = spacing_ratio * m_perimeter_width; + float line_gap_tol = 2.f * m_nozzle_change_perimeter_width; //If the block's line_gap is greater than it, the block should be aligned. + for (auto &info : block_info) { + //case1: no ramming, it can always align + if (!info.second.has_ramming) { + m_block_infill_gap_width[info.first].first = m_block_infill_gap_width[info.first].second = extra_width + m_perimeter_width; + } + // case2: has ramming, but no reverse travel + // + else if (!info.second.has_reverse_travel) { + float line_gap = m_nozzle_change_perimeter_width + extra_width; + if (!m_use_rib_wall) line_gap *= height_to_spacing; + if (line_gap < line_gap_tol) { + m_block_infill_gap_width[info.first].first = m_perimeter_width + extra_width; + m_block_infill_gap_width[info.first].second = m_nozzle_change_perimeter_width + extra_width; + } else { + m_block_infill_gap_width[info.first].first = m_block_infill_gap_width[info.first].second = m_nozzle_change_perimeter_width + extra_width; + } + } + // case 3: has ramming and reverse travel + else { + float extra_tpu_fix_spacing = m_tpu_fixed_spacing - 1.f; + float line_gap = m_nozzle_change_perimeter_width + std::max(extra_tpu_fix_spacing * m_perimeter_width, extra_width); + if (!m_use_rib_wall) line_gap = height_to_spacing * line_gap; + if (line_gap < line_gap_tol) { + m_block_infill_gap_width[info.first].first = m_perimeter_width + extra_width; + m_block_infill_gap_width[info.first].second = m_nozzle_change_perimeter_width + std::max(extra_tpu_fix_spacing * m_perimeter_width, extra_width); + } else { + m_block_infill_gap_width[info.first].first = m_block_infill_gap_width[info.first].second = m_nozzle_change_perimeter_width + + std::max(extra_tpu_fix_spacing * m_perimeter_width, extra_width); + } + } + } + + //2. recalculate toolchange depth + for (int idx = 0; idx < m_plan.size(); idx++) { + for (auto &toolchange : m_plan[idx].tool_changes) { + toolchange = set_toolchange(toolchange.old_tool, toolchange.new_tool, m_plan[idx].height, toolchange.wipe_volume, toolchange.purge_volume,idx); + } + } + m_extra_spacing = 1.f; } void WipeTower::plan_tower_new() { if (m_wipe_tower_brim_width < 0) m_wipe_tower_brim_width = get_auto_brim_by_height(m_wipe_tower_height); + calc_block_infill_gap(); if (m_use_rib_wall) { // recalculate wipe_tower_with and layer's depth - generate_wipe_tower_blocks(); + generate_wipe_tower_blocks(false); float max_depth = std::accumulate(m_wipe_tower_blocks.begin(), m_wipe_tower_blocks.end(), 0.f, [](float a, const auto &t) { return a + t.depth; }) + m_perimeter_width; float square_width = align_ceil(std::sqrt(max_depth * m_wipe_tower_width * m_extra_spacing), m_perimeter_width); - //std::cout << " before m_wipe_tower_width = " << m_wipe_tower_width << " max_depth = " << max_depth << std::endl; m_wipe_tower_width = square_width; - float width = m_wipe_tower_width - 2 * m_perimeter_width; for (int idx = 0; idx < m_plan.size(); idx++) { for (auto &toolchange : m_plan[idx].tool_changes) { - float length_to_extrude = toolchange.wipe_length; - float depth = std::ceil(length_to_extrude / width) * m_perimeter_width; - float nozzle_change_depth = 0; - if (!m_filament_map.empty() && m_filament_map[toolchange.old_tool] != m_filament_map[toolchange.new_tool]) { - double e_flow = nozzle_change_extrusion_flow(m_plan[idx].height); - double length = m_filaments_change_length[toolchange.old_tool] / e_flow; - int nozzle_change_line_count = length / (m_wipe_tower_width - 2*m_nozzle_change_perimeter_width) + 1; - if (has_tpu_filament()) - nozzle_change_depth = m_tpu_fixed_spacing * nozzle_change_line_count * m_nozzle_change_perimeter_width; - else - nozzle_change_depth = nozzle_change_line_count * m_nozzle_change_perimeter_width; - depth += nozzle_change_depth; - } - if (nozzle_change_depth == 0 - && !m_filament_nozzle_map.empty() - && toolchange.old_tool < (int)m_filament_nozzle_map.size() && toolchange.new_tool < (int)m_filament_nozzle_map.size() - && m_filament_nozzle_map[toolchange.old_tool] != m_filament_nozzle_map[toolchange.new_tool]) { - double e_flow = nozzle_change_extrusion_flow(m_plan[idx].height); - double length = m_filaments_change_length[toolchange.old_tool] / e_flow; - int nozzle_change_line_count = length / (m_wipe_tower_width - 2*m_nozzle_change_perimeter_width) + 1; - if (has_tpu_filament()) - nozzle_change_depth = m_tpu_fixed_spacing * nozzle_change_line_count * m_nozzle_change_perimeter_width; - else - nozzle_change_depth = nozzle_change_line_count * m_nozzle_change_perimeter_width; - depth += nozzle_change_depth; - } - toolchange.nozzle_change_depth = nozzle_change_depth; - toolchange.required_depth = depth; + toolchange = set_toolchange(toolchange.old_tool, toolchange.new_tool, m_plan[idx].height, toolchange.wipe_volume, toolchange.purge_volume,idx); } } } - generate_wipe_tower_blocks(); + generate_wipe_tower_blocks(true); float max_depth = 0.f; for (const auto &block : m_wipe_tower_blocks) { @@ -4126,28 +4607,29 @@ void WipeTower::plan_tower_new() for (int idx = 0; idx < m_plan.size(); idx++) { auto &info = m_plan[idx]; - if (idx == 0 && m_extra_spacing > 1.f + EPSILON) { + if (idx == 0 /*&& m_extra_spacing > 1.f + EPSILON*/) { // apply solid fill for the first layer info.extra_spacing = 1.f; for (auto &toolchange : info.tool_changes) { - float x_to_wipe = volume_to_length(toolchange.wipe_volume, m_perimeter_width, info.height); + //float x_to_wipe = volume_to_length(toolchange.wipe_volume, m_perimeter_width, info.height); float line_len = m_wipe_tower_width - 2 * m_perimeter_width; - float x_to_wipe_new = x_to_wipe * m_extra_spacing; - x_to_wipe_new = std::floor(x_to_wipe_new / line_len) * line_len; - x_to_wipe_new = std::max(x_to_wipe_new, x_to_wipe); + float wipe_depth = (toolchange.required_depth - toolchange.nozzle_change_depth) * m_extra_spacing; + float wipe_line_count = wipe_depth / m_perimeter_width; + float nozzle_change_depth = toolchange.nozzle_change_depth * m_extra_spacing; - int line_count = std::ceil((x_to_wipe_new - WT_EPSILON) / line_len); - // nozzle change length - int nozzle_change_line_count = (toolchange.nozzle_change_depth + WT_EPSILON) / m_nozzle_change_perimeter_width; + int nozzle_change_line_count = (toolchange.nozzle_change_depth * m_extra_spacing + WT_EPSILON) / m_nozzle_change_perimeter_width; - toolchange.required_depth = line_count * m_perimeter_width + nozzle_change_line_count * m_nozzle_change_perimeter_width; - toolchange.wipe_volume = x_to_wipe_new / x_to_wipe * toolchange.wipe_volume; - toolchange.wipe_length = x_to_wipe_new; + toolchange.required_depth = wipe_depth + nozzle_change_depth; + toolchange.wipe_length = wipe_line_count * line_len; + toolchange.wipe_volume = length_to_volume(toolchange.wipe_length, m_perimeter_width, info.height); + toolchange.nozzle_change_length = nozzle_change_line_count * (m_wipe_tower_width - (m_nozzle_change_perimeter_width + m_perimeter_width)); + toolchange.nozzle_change_depth = nozzle_change_depth; } } else { info.extra_spacing = m_extra_spacing; for (auto &toolchange : info.tool_changes) { toolchange.required_depth *= m_extra_spacing; + toolchange.nozzle_change_depth *= m_extra_spacing; toolchange.wipe_length = volume_to_length(toolchange.wipe_volume, m_perimeter_width, info.height); } } @@ -4155,7 +4637,8 @@ void WipeTower::plan_tower_new() } update_all_layer_depth(max_depth); - set_nozzle_last_layer_id(); // record per-extruder last layer for is_valid_last_layer + set_nozzle_last_layer_id(); + if(m_use_gap_wall) get_all_wall_skip_points(); float diagonal = sqrt(m_wipe_tower_depth * m_wipe_tower_depth + m_wipe_tower_width * m_wipe_tower_width); m_rib_length = std::max({m_rib_length, diagonal}); m_rib_length += m_extra_rib_length; @@ -4227,7 +4710,6 @@ void WipeTower::generate_new(std::vector layer_result; int index = 0; - std::unordered_set solid_blocks_id;// The contact surface of different bonded materials is solid. for (auto layer : m_plan) { reset_block_status(); m_cur_layer_id = index++; - m_prev_layer_had_interface = m_current_layer_has_interface; - m_current_layer_has_interface = !solid_blocks_id.empty(); set_layer(layer.z, layer.height, 0, false, layer.z == m_plan.back().z); - if (m_layer_info->depth < m_perimeter_width) continue; - if (m_wipe_tower_blocks.size() == 1) { if (m_layer_info->depth < m_wipe_tower_depth - m_perimeter_width) { // align y shift to perimeter width @@ -4263,32 +4740,30 @@ void WipeTower::generate_new(std::vector int { + auto get_wall_filament_for_this_layer = [this, &layer, &wall_filament]() -> int { if (layer.tool_changes.size() == 0) return -1; int candidate_id = -1; for (size_t idx = 0; idx < layer.tool_changes.size(); ++idx) { if (idx == 0) { - // An extruder's last-layer filament above its printable height cannot supply the - // outer wall. is_valid_last_layer is inert unless it clamps. - if (layer.tool_changes[idx].old_tool == wall_filament_id && is_valid_last_layer(layer.tool_changes[idx].old_tool, m_cur_layer_id, layer.z)) - return wall_filament_id; - else if (m_filpar[layer.tool_changes[idx].old_tool].category == m_filpar[wall_filament_id].category && - is_valid_last_layer(layer.tool_changes[idx].old_tool, m_cur_layer_id, layer.z)) { + if (layer.tool_changes[idx].old_tool == wall_filament && is_valid_last_layer(layer.tool_changes[idx].old_tool, this->m_cur_layer_id, layer.z)) + return wall_filament; + else if (m_filpar[layer.tool_changes[idx].old_tool].category == m_filpar[wall_filament].category && + is_valid_last_layer(layer.tool_changes[idx].old_tool, this->m_cur_layer_id, layer.z)) { candidate_id = layer.tool_changes[idx].old_tool; } } - if (layer.tool_changes[idx].new_tool == wall_filament_id) { - return wall_filament_id; + if (layer.tool_changes[idx].new_tool == wall_filament) { + return wall_filament; } - if ((candidate_id == -1) && (m_filpar[layer.tool_changes[idx].new_tool].category == m_filpar[wall_filament_id].category)) + if ((candidate_id == -1) && (m_filpar[layer.tool_changes[idx].new_tool].category == m_filpar[wall_filament].category)) candidate_id = layer.tool_changes[idx].new_tool; } return candidate_id == -1 ? layer.tool_changes[0].new_tool : candidate_id; @@ -4300,7 +4775,7 @@ void WipeTower::generate_new(std::vectorlayers_type[m_cur_layer_id] == WipeTowerLayerType::Contact; const auto * block2 = get_block_by_category(m_filpar[layer.tool_changes[i].old_tool].category, false); - id = std::find_if(m_wipe_tower_blocks.begin(), m_wipe_tower_blocks.end(), [&](const WipeTowerBlock &b) { return &b == block2; }) - m_wipe_tower_blocks.begin(); - bool solid_nozzlechange = solid_blocks_id.count(id); + if(block2) solid_nozzlechange = block2->layers_type[m_cur_layer_id] == WipeTowerLayerType::Contact; layer_result.emplace_back(tool_change_new(layer.tool_changes[i].new_tool, solid_toolchange,solid_nozzlechange)); if (i == 0 && (layer.tool_changes[i].old_tool == wall_idx)) { @@ -4348,7 +4822,6 @@ void WipeTower::generate_new(std::vector next_solid_blocks_id; // insert finish block if (wall_idx != -1) { if (layer.tool_changes.empty()) { @@ -4361,7 +4834,8 @@ void WipeTower::generate_new(std::vector> &result) @@ -4521,7 +4985,7 @@ void WipeTower::generate(std::vector> & } if (i == idx) { - layer_result.emplace_back(tool_change(layer.tool_changes[i].new_tool, m_enable_timelapse_print ? false : true)); + layer_result.emplace_back(tool_change(layer.tool_changes[i].new_tool, m_enable_timelapse_print ? false : true, false)); // finish_layer will be called after this toolchange finish_layer_tcr = finish_layer(false, layer.extruder_fill); } @@ -4529,7 +4993,7 @@ void WipeTower::generate(std::vector> & if (idx == -1 && i == 0) { layer_result.emplace_back(tool_change(layer.tool_changes[i].new_tool, false, true)); } else { - layer_result.emplace_back(tool_change(layer.tool_changes[i].new_tool)); + layer_result.emplace_back(tool_change(layer.tool_changes[i].new_tool, false, false)); } } } @@ -4552,21 +5016,23 @@ void WipeTower::generate(std::vector> & result.emplace_back(std::move(layer_result)); } } - +#endif WipeTower::ToolChangeResult WipeTower::only_generate_out_wall(bool is_new_mode) { size_t old_tool = m_current_tool; - WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); + WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar, m_enable_arc_fitting); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) .set_initial_tool(m_current_tool) .set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)); + set_for_wipe_tower_writer(writer); + // Slow down on the 1st layer. bool first_layer = is_first_layer(); // BBS: speed up perimeter speed to 90mm/s for non-first layer - float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, 5400.f); + float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, m_max_speed) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, m_max_speed); float fill_box_y = m_layer_info->toolchanges_depth() + m_perimeter_width; box_coordinates fill_box(Vec2f(m_perimeter_width, fill_box_y), m_wipe_tower_width - 2 * m_perimeter_width, m_layer_info->depth - fill_box_y); @@ -4679,7 +5145,9 @@ Polygon WipeTower::generate_support_wall_new(WipeTowerWriter &writer, const box_ } if (!extrude_perimeter) return wall_polygon; - if (skip_points) { result_wall = contrust_gap_for_skip_points(wall_polygon,m_wall_skip_points,m_wipe_tower_width,2.5*m_perimeter_width,insert_skip_polygon); } + if (skip_points) { + result_wall = construct_gap_for_skip_points(wall_polygon, m_wall_skip_points[m_cur_layer_id], m_wipe_tower_width, 2.5 * m_perimeter_width, insert_skip_polygon); + } else { result_wall.push_back(to_polyline(wall_polygon)); insert_skip_polygon = wall_polygon; @@ -4689,7 +5157,6 @@ Polygon WipeTower::generate_support_wall_new(WipeTowerWriter &writer, const box_ BoundingBox bbox = get_extents(result_wall); m_rib_offset = Vec2f(-unscaled(bbox.min.x()), -unscaled(bbox.min.y())); } - return insert_skip_polygon; } @@ -4699,7 +5166,7 @@ Polygon WipeTower::generate_support_wall(WipeTowerWriter &writer, const box_coor float retract_speed = m_filpar[m_current_tool].retract_speed *60 ; bool is_left = false; bool is_right = false; - for (auto pt : m_wall_skip_points) { + for (auto pt : m_wall_skip_points[m_cur_layer_id]) { if (abs(pt.x()) < EPSILON) { is_left = true; } else if (abs(pt.x() - m_wipe_tower_width) < EPSILON) { @@ -4750,7 +5217,7 @@ Polygon WipeTower::generate_support_wall(WipeTowerWriter &writer, const box_coor index = (index + 1) % 4; if (index == 2) { if (is_right) { - std::vector break_segments = remove_points_from_segment(Segment(wt_box.rd, wt_box.ru), m_wall_skip_points, 2.5 * m_perimeter_width); + std::vector break_segments = remove_points_from_segment(Segment(wt_box.rd, wt_box.ru), m_wall_skip_points[m_cur_layer_id], 2.5 * m_perimeter_width); for (auto iter = break_segments.begin(); iter != break_segments.end(); ++iter) { float dx = iter->start.x() - writer.pos().x(); float dy = iter->start.y() - writer.pos().y(); @@ -4770,7 +5237,7 @@ Polygon WipeTower::generate_support_wall(WipeTowerWriter &writer, const box_coor } } else if (index == 0) { if (is_left) { - std::vector break_segments = remove_points_from_segment(Segment(wt_box.ld, wt_box.lu), m_wall_skip_points, 2.5 * m_perimeter_width); + std::vector break_segments = remove_points_from_segment(Segment(wt_box.ld, wt_box.lu), m_wall_skip_points[m_cur_layer_id], 2.5 * m_perimeter_width); for (auto iter = break_segments.rbegin(); iter != break_segments.rend(); ++iter) { float dx = iter->end.x() - writer.pos().x(); float dy = iter->end.y() - writer.pos().y(); @@ -4831,4 +5298,43 @@ bool WipeTower::need_thick_bridge_flow(float pos_y) const { return false; } +bool WipeTower::is_valid_last_layer(int tool, int layer_id, double layer_z) const +{ + int extruder_id = get_extruder_id(tool, layer_id); + if (extruder_id < 0 || extruder_id >= m_printable_height.size()) return true; + if (m_last_layer_id[extruder_id] == layer_id && layer_z > m_printable_height[extruder_id]) return false; + return true; +} +float WipeTower::get_block_gap_width(int tool,bool is_nozzlechangle) +{ + //assert(m_block_infill_gap_width.count(m_filpar[tool].category));//The code contains logic that attempts to access non-existent blocks, + // such as in case of involving two extruders with only a single head and a single layer, + // some code will attempt to access the block's nozzle_change_gap_width, even though the block does not exist. + if (!m_block_infill_gap_width.count(m_filpar[tool].category)) { + return is_nozzlechangle ? m_nozzle_change_perimeter_width : m_perimeter_width; + } + return is_nozzlechangle ? m_block_infill_gap_width[m_filpar[tool].category].second : m_block_infill_gap_width[m_filpar[tool].category].first; + +} + +bool WipeTower::is_need_ramming(int filament_id_1, int filament_id_2, int layer_id) const +{ + return !m_multi_nozzle_group_result->are_filaments_same_nozzle(filament_id_1, filament_id_2, layer_id); +} +bool WipeTower::is_same_extruder(int filament_id_1, int filament_id_2, int layer_id) const +{ + return m_multi_nozzle_group_result->are_filaments_same_extruder(filament_id_1, filament_id_2, layer_id); +} + +bool WipeTower::is_same_nozzle(int filament_id_1, int filament_id_2, int layer_id) const +{ + return m_multi_nozzle_group_result->are_filaments_same_nozzle(filament_id_1, filament_id_2, layer_id); +} + +int WipeTower::get_nozzle_id(int filament_id, int layer_id) const { return m_multi_nozzle_group_result->get_nozzle_id(filament_id, layer_id); } + +int WipeTower::get_extruder_id(int filament_id, int layer_id) const { + return m_multi_nozzle_group_result->get_extruder_id(filament_id, layer_id); +} + } // namespace Slic3r diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index 508765824e..045c82cbf3 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -12,7 +12,7 @@ #include "libslic3r/Polyline.hpp" #include "libslic3r/TriangleMesh.hpp" #include - +#include "libslic3r/MultiNozzleUtils.hpp" namespace Slic3r { @@ -20,6 +20,17 @@ class WipeTowerWriter; class PrintConfig; enum GCodeFlavor : unsigned char; +// Cuts the tower wall polygon open at each skip point (a toolchange's entry position) +// so the entry travel can pass through instead of crossing the printed wall. Defined in +// WipeTower.cpp, shared by WipeTower and WipeTower2. +Polylines construct_gap_for_skip_points( + const Polygon& polygon, const std::vector& skip_points, float wt_width, float gap_length, Polygon& insert_skip_polygon); + +// Klipper acts on commands the instant it parses them, and its G4 reads only P (milliseconds), +// so the zero-second and seconds-valued dwells every other flavor uses neither synchronize nor +// pause there. Both defined in WipeTower.cpp, shared by WipeTower and WipeTower2. +const char* flush_planner_queue_command(GCodeFlavor flavor); // finish queued moves, e.g. around M104/M109 +std::string wait_command(GCodeFlavor flavor, float seconds); // pause for `seconds` class WipeTower { @@ -34,7 +45,11 @@ public: static TriangleMesh its_make_rib_tower(float width, float depth, float height, float rib_length, float rib_width, bool fillet_wall); static TriangleMesh its_make_rib_brim(const Polygon& brim, float layer_height); static Polygon rib_section(float width, float depth, float rib_length, float rib_width, bool fillet_wall); - static Vec2f move_box_inside_box(const BoundingBox &box1, const BoundingBox &box2, int offset = 0); + // Translation that brings a footprint inside the printable outline, padded by offset. The prime + // tower is validated against the real outline (see layered_print_cleareance_valid), so clamping + // against the bounding box alone would leave it off a delta or hexagonal bed. box and polygons + // must share one scaled coordinate frame; the translation comes back in millimeters. + static Vec2f move_box_inside_polygon(const BoundingBox &box, const Polygons &polygons, coord_t offset = 0); static Polygon rounding_polygon(Polygon &polygon, double rounding = 2., double angle_tol = 30. / 180. * PI); struct Extrusion { @@ -84,7 +99,6 @@ public: bool priming; bool is_tool_change{false}; - bool is_contact{false}; Vec2f tool_change_start_pos; // Pass a polyline so that normal G-code generator can do a wipe for us. @@ -108,6 +122,7 @@ public: // executing the gcode finish_layer_tcr. bool is_finish_first = false; + bool is_contact = false; NozzleChangeResult nozzle_change_result; // Sum the total length of the extrusion. @@ -122,6 +137,8 @@ public: } return e_length; } + // Orca: set by WipeTower2 (non-BBL tower) to force a travel to the tower even when the + // previous position is unknown; read by WipeTowerIntegration::append_tcr2 (GCode.cpp). bool force_travel = false; }; @@ -162,15 +179,12 @@ public: bool priming, size_t old_tool, bool is_finish, - bool is_tool_change, - float purge_volume, - bool is_contact = false) const; + bool is_tool_change, float purge_volume, bool is_contact) const; ToolChangeResult construct_block_tcr(WipeTowerWriter& writer, bool priming, size_t filament_id, - bool is_finish, - float purge_volume) const; + bool is_finish, float purge_volume) const; // x -- x coordinates of wipe tower in mm ( left bottom corner ) @@ -184,9 +198,14 @@ public: // Set the extruder properties. void set_extruder(size_t idx, const PrintConfig& config); + void set_shared_print_bed(const Polygons &bed) { m_shared_print_bed = bed; } + // Orca: has_filament_switcher is not a static PrintConfig member here, so it is pushed in from + // Print via a setter rather than read in the ctor. Device-set only. + void set_has_filament_switcher(bool v) { m_has_filament_switcher = v; } // Appends into internal structure m_plan containing info about the future wipe tower // to be used before building begins. The entries must be added ordered in z. - void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, float wipe_volume = 0.f, float prime_volume = 0.f); + void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, float wipe_volume_ec = 0.f, float wipe_volume_nc = 0.f, float prime_volume = 0.f); + // Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result" void generate(std::vector> &result); @@ -219,9 +238,6 @@ public: } } - void set_wipe_volume(std::vector>& wiping_matrix) { - wipe_volumes = wiping_matrix; - } // Switch to a next layer. void set_layer( @@ -250,7 +266,6 @@ public: // Calculate extrusion flow from desired line width, nozzle diameter, filament diameter and layer_height: m_extrusion_flow = extrusion_flow(layer_height); - // Advance m_layer_info iterator, making sure we got it right while (!m_plan.empty() && m_layer_info->z < print_z - WT_EPSILON && m_layer_info+1 != m_plan.end()) ++m_layer_info; @@ -309,20 +324,9 @@ public: std::vector get_used_filament() const { return m_used_filament_length; } int get_number_of_toolchanges() const { return m_num_tool_changes; } - void set_filament_map(const std::vector &filament_map) { m_filament_map = filament_map; } - // Vortek H2C: filament_id → physical nozzle_id for carousel rotation detection - void set_filament_nozzle_map(const std::vector &nozzle_map) { m_filament_nozzle_map = nozzle_map; } - void set_has_tpu_filament(bool has_tpu) { m_has_tpu_filament = has_tpu; } + bool has_tpu_filament() const { return m_has_tpu_filament; } - - // Orca: has_filament_switcher is not a static PrintConfig member, so it is pushed in from Print - // via a setter rather than read in the ctor. Device-set only. - void set_has_filament_switcher(bool v) { m_has_filament_switcher = v; } - // The region every extruder can reach, used to clamp the PETG pre-extrusion offset to the - // printable bed. - void set_shared_print_bed(const Polygons &bed) { m_shared_print_bed = bed; } - struct FilamentParameters { std::string material = "PLA"; int category; @@ -331,15 +335,15 @@ public: bool is_support = false; int nozzle_temperature = 0; int nozzle_temperature_initial_layer = 0; - int interface_print_temperature = 0; - float loading_speed = 0.f; - float loading_speed_start = 0.f; - float unloading_speed = 0.f; - float unloading_speed_start = 0.f; - float delay = 0.f ; - int cooling_moves = 0; - float cooling_initial_speed = 0.f; - float cooling_final_speed = 0.f; + // BBS: remove useless config + //float loading_speed = 0.f; + //float loading_speed_start = 0.f; + //float unloading_speed = 0.f; + //float unloading_speed_start = 0.f; + //float delay = 0.f ; + //int cooling_moves = 0; + //float cooling_initial_speed = 0.f; + //float cooling_final_speed = 0.f; float ramming_line_width_multiplicator = 1.f; float ramming_step_multiplicator = 1.f; float max_e_speed = std::numeric_limits::max(); @@ -349,41 +353,41 @@ public: float retract_length; float retract_speed; float wipe_dist; - float tower_interface_pre_extrusion_dist = 0.f; - float tower_interface_pre_extrusion_length = 0.f; - // Outward shift of the wipe start for a PETG pre-extrusion on filament-switcher devices; - // set from filament_tower_interface_pre_extrusion_dist. - float petg_pre_extrusion_offset_dist = 0.f; - float tower_ironing_area = 4.f; - float tower_interface_purge_length = 0.f; - // Distance (in mm of filament) that a hotend is allowed to pre-cool before the - // tower is reached; drives the prime-tower heating-during-wipe model (multi-nozzle only). - float filament_cooling_before_tower = 0.f; - // .first = extruder change, .second = nozzle change (carousel) - std::pair max_e_ramming_speed{0.f, 0.f}; - std::pair ramming_travel_time{0.f, 0.f}; - std::pair precool_target_temp{0, 0}; - std::pair,std::vector> precool_t; - std::pair,std::vector> precool_t_first_layer; + std::pair max_e_ramming_speed;//[0]extruder change [1]nozzle change + std::pair ramming_travel_time; // Travel time after ramming + std::pair,std::vector> precool_t;//Pre-cooling time, set to 0 to ensure the ramming speed is controlled solely by ramming volumetric speed. + std::pair, std::vector> precool_t_first_layer; + std::pair precool_target_temp; + float filament_cooling_before_tower = 0.f; + float flat_iron_area; + float filament_tower_interface_print_temp; + float filament_tower_interface_pre_extrusion_dist = 0; + float filament_tower_interface_pre_extrusion_length = 0; + float filament_petg_pre_extrusion_offset_dist = 0; }; - void set_used_filament_ids(const std::vector &used_filament_ids) { m_used_filament_ids = used_filament_ids; }; + void set_used_filament_ids(const std::vector &used_filament_ids) { m_used_filament_ids = used_filament_ids; }; void set_filament_categories(const std::vector & filament_categories) { m_filament_categories = filament_categories;}; - std::vector m_used_filament_ids; + void set_nozzle_group_result(const MultiNozzleUtils::LayeredNozzleGroupResult &multi_nozzle_group_result) { m_multi_nozzle_group_result = &multi_nozzle_group_result; }; + std::vector m_used_filament_ids; std::vector m_filament_categories; + const MultiNozzleUtils::LayeredNozzleGroupResult *m_multi_nozzle_group_result{nullptr}; + + enum class WipeTowerLayerType : unsigned char { Normal, Contact, Solid, Contact_UP};// Contact layer should be solid and reduce feed struct WipeTowerBlock { int block_id{0}; int filament_adhesiveness_category{0}; std::vector layer_depths; - std::vector solid_infill; + //std::vector solid_infill; std::vector finish_depth{0}; // the start pos of finish frame for every layer + std::vector layers_type; // type of the layer, normal, Contact or Solid float depth{0}; float start_depth{0}; float cur_depth{0}; - int last_filament_change_id{-1}; + int last_filament_change_id{-1}; int last_nozzle_change_id{-1}; }; @@ -403,25 +407,33 @@ public: WipeTowerBlock* get_block_by_category(int filament_adhesiveness_category, bool create); void add_depth_to_block(int filament_id, int filament_adhesiveness_category, float depth, bool is_nozzle_change = false); int get_filament_category(int filament_id); - bool is_in_same_extruder(int filament_id_1, int filament_id_2); - // Vortek H2C: format BBS-compatible NOZZLE_CHANGE_START/END tag with OF/NF/ON/NN payload - std::string format_nozzle_change_tag(bool start, int old_filament_id, int new_filament_id) const; void reset_block_status(); int get_wall_filament_for_all_layer(); // for generate new wipe tower void generate_new(std::vector> &result); void plan_tower_new(); - void generate_wipe_tower_blocks(); + void generate_wipe_tower_blocks(bool add_solid_flag); void update_all_layer_depth(float wipe_tower_depth); - + void set_nozzle_last_layer_id(); + void set_first_layer_flow_ratio(const float flow_ratio); + // Orca: default/initial-layer/travel acceleration are object-scope options here (PrintConfig + // members in BBS), so Print pushes the resolved per-variant columns in via this setter. + void set_accelerations(const std::vector &normal, const std::vector &first_layer_normal, + const std::vector &travel, const std::vector &first_layer_travel); + void calc_block_infill_gap(); ToolChangeResult tool_change_new(size_t new_tool, bool solid_change = false, bool solid_nozzlechange=false); - NozzleChangeResult nozzle_change_new(int old_filament_id, int new_filament_id, bool solid_change = false); + NozzleChangeResult ramming(int old_filament_id, int new_filament_id, bool solid_change = false, bool extruder_change = true); // extruder_chang means nozzle_change ToolChangeResult finish_layer_new(bool extrude_perimeter = true, bool extrude_fill = true, bool extrude_fill_wall = true); ToolChangeResult finish_block(const WipeTowerBlock &block, int filament_id, bool extrude_fill = true); - ToolChangeResult finish_block_solid(const WipeTowerBlock &block, int filament_id, bool extrude_fill = true ,bool interface_solid =false); + ToolChangeResult finish_block_solid(const WipeTowerBlock &block, int filament_id, bool extrude_fill = true, WipeTowerLayerType layer_type = WipeTowerLayerType::Normal); void toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinates &cleaning_box, float wipe_length,bool solid_toolchange=false); Vec2f get_rib_offset() const { return m_rib_offset; } + bool is_need_ramming(int filament_id_1, int filament_id_2, int layer_id) const; + bool is_same_extruder(int filament_id_1, int filament_id_2, int layer_id) const; + bool is_same_nozzle(int filament_id_1, int filament_id_2, int layer_id) const; + int get_nozzle_id(int filament_id, int layer_id) const; + int get_extruder_id(int filament_id, int layer_id) const; private: enum wipe_shape // A fill-in direction @@ -441,7 +453,6 @@ private: bool m_enable_wrapping_detection = false; bool m_enable_timelapse_print = false; bool m_semm = true; // Are we using a single extruder multimaterial printer? - bool m_purge_in_prime_tower = false; // Do we purge in the prime tower? Vec2f m_wipe_tower_pos; // Left front corner of the wipe tower in mm. float m_wipe_tower_width; // Width of the wipe tower. float m_wipe_tower_depth = 0.f; // Depth of the wipe tower @@ -459,12 +470,11 @@ private: float m_travel_speed = 0.f; float m_first_layer_speed = 0.f; size_t m_first_layer_idx = size_t(-1); - - std::vector m_filaments_change_length; + Vec2f m_origin; + std::vector m_last_layer_id; + std::pair,std::vector> m_filaments_change_length;//[0]extruder change [1]nozzle change size_t m_cur_layer_id; NozzleChangeResult m_nozzle_change_result; - std::vector m_filament_map; - std::vector m_filament_nozzle_map; // Vortek H2C: filament_id → physical nozzle_id bool m_has_tpu_filament{false}; bool m_is_multi_extruder{false}; bool m_use_gap_wall{false}; @@ -475,33 +485,32 @@ private: bool m_used_fillet{false}; Vec2f m_rib_offset{Vec2f(0.f, 0.f)}; bool m_tower_framework{false}; - + bool m_need_reverse_travel{false}; + bool m_enable_tower_interface_features{false}; // G-code generator parameters. - float m_cooling_tube_retraction = 0.f; - float m_cooling_tube_length = 0.f; - float m_parking_pos_retraction = 0.f; - float m_extra_loading_move = 0.f; + // BBS: remove useless config + //float m_cooling_tube_retraction = 0.f; + //float m_cooling_tube_length = 0.f; + //float m_parking_pos_retraction = 0.f; + //float m_extra_loading_move = 0.f; float m_bridging = 0.f; bool m_no_sparse_layers = false; - bool m_set_extruder_trimpot = false; + // BBS: remove useless config + //bool m_set_extruder_trimpot = false; bool m_adhesion = true; GCodeFlavor m_gcode_flavor; - - // Multi-nozzle prime-tower heating during wipe. m_is_multiple_nozzle gates the whole - // feature; it is false for every current (single-nozzle) printer (extruder_max_nozzle_count - // defaults to 1), so the pre-heat/pre-cool path is inert and wipe-tower g-code is unchanged. - bool m_is_multiple_nozzle = false; - std::vector m_hotend_heating_rate; // config.hotend_heating_rate (deg/s per extruder) - std::vector m_physical_extruder_map; // logical extruder -> physical tool number (M104 T param) - - // Per-extruder printable-height clamp. m_printable_height = config.extruder_printable_height - // (per-extruder Z limit; empty for single-extruder printers, [320,325] for H2D). m_last_layer_id - // records, per extruder, the last wipe-tower layer that uses it. is_valid_last_layer() is gated on - // m_is_multi_extruder so single-extruder wipe-tower g-code is unchanged; the clamp only bites a - // multi-extruder wipe tower whose final per-extruder layer exceeds that extruder's printable - // height (near the Z limit). - std::vector m_printable_height; - std::vector m_last_layer_id; + bool m_is_multiple_nozzle = false; + std::vector m_normal_accels; + std::vector m_first_layer_normal_accels; + std::vector m_travel_accels; + std::vector m_first_layer_travel_accels; + unsigned int m_max_accels; + bool m_accel_to_decel_enable; + float m_accel_to_decel_factor; + bool m_enable_arc_fitting = true; + std::vector m_hotend_heating_rate; + std::vector m_hotend_cooling_rate; + Polygons m_shared_print_bed; // Bed properties enum { @@ -512,10 +521,11 @@ private: float m_bed_width; // width of the bed bounding box Vec2f m_bed_bottom_left; // bottom-left corner coordinates (for rectangular beds) + float m_first_layer_flow_ratio; float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill. float m_nozzle_change_perimeter_width = 0.4f * Width_To_Nozzle_Ratio; float m_extrusion_flow = 0.038f; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter. - + std::unordered_map> m_block_infill_gap_width; // categories to infill_gap: toolchange gap, nozzlechange gap // Extruder specific parameters. std::vector m_filpar; @@ -528,50 +538,52 @@ private: // A fill-in direction (positive Y, negative Y) alternates with each layer. wipe_shape m_current_shape = SHAPE_NORMAL; size_t m_current_tool = 0; - // Orca: support mmu wipe tower - std::vector> wipe_volumes; + // BBS + //const std::vector> wipe_volumes; float m_depth_traversed = 0.f; // Current y position at the wipe tower. bool m_current_layer_finished = false; bool m_left_to_right = true; float m_extra_spacing = 1.f; float m_tpu_fixed_spacing = 2; - std::vector m_wall_skip_points; + float m_max_speed = 5400.f; // the maximum printing speed on the prime tower. + std::vector> m_wall_skip_points; std::map m_outer_wall; + std::vector m_printable_height; bool is_first_layer() const { return size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; } + bool is_valid_last_layer(int tool, int layer_id, double layer_z) const; bool m_flat_ironing=false; - bool m_enable_tower_interface_features=false; - bool m_enable_tower_interface_cooldown_during_tower=false; - // Filament-switcher device flag + shared printable bed for the PETG pre-extrusion offset. - // m_has_filament_switcher is false for the whole shipping fleet (no profile sets the key), so - // the PETG branch in get_next_pos never runs -> no change fleet-wide. - bool m_has_filament_switcher=false; - Polygons m_shared_print_bed; - bool m_prev_layer_had_interface=false; - bool m_current_layer_has_interface=false; + bool m_contact_ironing = false; + bool m_has_filament_switcher = false; + float m_contact_speed = 20 * 60.f; + std::vector m_physical_extruder_map; // Calculates length of extrusion line to extrude given volume float volume_to_length(float volume, float line_width, float layer_height) const { return std::max(0.f, volume / (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f)))); } - + // Calculates volume of extrusion line + float length_to_volume(float length,float line_width, float layer_height) const + { + return std::max(0.f, length * (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f)))); + } // Calculates depth for all layers and propagates them downwards void plan_tower(); // Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental void make_wipe_tower_square(); - Vec2f get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length, bool interface_layer, size_t interface_tool); + Vec2f get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length, bool solid_toolchange); // Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe void save_on_last_wipe(); bool is_tpu_filament(int filament_id) const; bool is_petg_filament(int filament_id) const; - bool is_need_reverse_travel(int filament_id, bool extruder_change) const; - + bool is_need_reverse_travel(int filament, bool extruder_change) const; // BBS box_coordinates align_perimeter(const box_coordinates& perimeter_box); + void set_for_wipe_tower_writer(WipeTowerWriter &writer); // to store information about tool changes for a given layer struct WipeTowerInfo{ @@ -584,6 +596,7 @@ private: float wipe_volume; float wipe_length; float nozzle_change_depth{0}; + float nozzle_change_length{0}; // BBS float purge_volume; ToolChange(size_t old, size_t newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f, float wl = 0, float pv = 0) @@ -613,7 +626,7 @@ private: // ot -1 if there is no such toolchange. int first_toolchange_to_nonsoluble_nonsupport( const std::vector& tool_changes) const; - + WipeTowerInfo::ToolChange set_toolchange(int old_tool, int new_tool, float layer_height, float wipe_volume, float purge_volume,int layer_id); void toolchange_Unload( WipeTowerWriter &writer, const box_coordinates &cleaning_box, @@ -633,13 +646,10 @@ private: WipeTowerWriter &writer, const box_coordinates &cleaning_box, float wipe_volume); - void get_wall_skip_points(const WipeTowerInfo &layer); - - // Per-extruder printable-height clamp (see m_printable_height). is_valid_last_layer returns - // false only for a multi-extruder wipe tower's final per-extruder layer that exceeds that - // extruder's printable height; returns true (no clamp) in every other case. - bool is_valid_last_layer(int tool, int layer_id, double layer_z) const; - void set_nozzle_last_layer_id(); + void get_wall_skip_points(const WipeTowerInfo &layer,int layer_id); + void get_all_wall_skip_points(); + ToolChangeResult merge_tcr(ToolChangeResult &first, ToolChangeResult &second); + float get_block_gap_width(int tool, bool is_nozzlechangle = false); }; diff --git a/src/libslic3r/GCode/WipeTower2.cpp b/src/libslic3r/GCode/WipeTower2.cpp index 34b385d4be..ee0f9c375a 100644 --- a/src/libslic3r/GCode/WipeTower2.cpp +++ b/src/libslic3r/GCode/WipeTower2.cpp @@ -24,7 +24,6 @@ namespace Slic3r { -static constexpr float flat_iron_area = 4.f; constexpr float flat_iron_speed = 10.f * 60.f; static const double wipe_tower_wall_infill_overlap = 0.0; static constexpr double WIPE_TOWER_RESOLUTION = 0.1; @@ -234,24 +233,6 @@ static Polygon rounding_rectangle(Polygon& polygon, double rounding = 2., double return res; } -static std::pair ray_intersetion_line(const Vec2f& a, const Vec2f& v1, const Vec2f& b, const Vec2f& c) -{ - const Vec2f v2 = c - b; - double denom = cross2(v1, v2); - if (fabs(denom) < EPSILON) - return {false, Vec2f(0, 0)}; - const Vec2f v12 = (a - b); - double nume_a = cross2(v2, v12); - double nume_b = cross2(v1, v12); - double t1 = nume_a / denom; - double t2 = nume_b / denom; - if (t1 >= 0 && t2 >= 0 && t2 <= 1.) { - // Get the intersection point. - Vec2f res = a + t1 * v1; - return std::pair(true, res); - } - return std::pair(false, Vec2f{0, 0}); -} static Polygon scale_polygon(const std::vector& points) { Polygon res; @@ -296,6 +277,7 @@ static Polygon generate_rectange(const Line& line, coord_t offset) return poly; }; +// Straight or arc-fitted wall segment used by WipeTowerWriter2::generate_path(). struct Segment { Vec2f start; @@ -306,234 +288,6 @@ struct Segment bool is_valid() const { return start.y() < end.y(); } }; -static std::vector remove_points_from_segment(const Segment& segment, const std::vector& skip_points, double range) -{ - std::vector result; - result.push_back(segment); - float x = segment.start.x(); - - for (const Vec2f& point : skip_points) { - std::vector newResult; - for (const auto& seg : result) { - if (point.y() + range <= seg.start.y() || point.y() - range >= seg.end.y()) { - newResult.push_back(seg); - } else { - if (point.y() - range > seg.start.y()) { - newResult.push_back(Segment(Vec2f(x, seg.start.y()), Vec2f(x, point.y() - range))); - } - if (point.y() + range < seg.end.y()) { - newResult.push_back(Segment(Vec2f(x, point.y() + range), Vec2f(x, seg.end.y()))); - } - } - } - - result = newResult; - } - - result.erase(std::remove_if(result.begin(), result.end(), [](const Segment& seg) { return !seg.is_valid(); }), result.end()); - return result; -} - -struct IntersectionInfo -{ - Vec2f pos; - int idx; - int pair_idx; // gap_pair idx - float dis_from_idx; - bool is_forward; -}; - -struct PointWithFlag -{ - Vec2f pos; - int pair_idx; // gap_pair idx - bool is_forward; -}; -static IntersectionInfo move_point_along_polygon( - const std::vector& points, const Vec2f& startPoint, int startIdx, float offset, bool forward, int pair_idx) -{ - float remainingDistance = offset; - IntersectionInfo res; - int mod = points.size(); - if (forward) { - int next = (startIdx + 1) % mod; - remainingDistance -= (points[next] - startPoint).norm(); - if (remainingDistance <= 0) { - res.idx = startIdx; - res.pos = startPoint + (points[next] - startPoint).normalized() * offset; - res.pair_idx = pair_idx; - res.dis_from_idx = (points[startIdx] - res.pos).norm(); - return res; - } else { - for (int i = (startIdx + 1) % mod; i != startIdx; i = (i + 1) % mod) { - float segmentLength = (points[(i + 1) % mod] - points[i]).norm(); - if (remainingDistance <= segmentLength) { - float ratio = remainingDistance / segmentLength; - res.idx = i; - res.pos = points[i] + ratio * (points[(i + 1) % mod] - points[i]); - res.dis_from_idx = remainingDistance; - res.pair_idx = pair_idx; - return res; - } - remainingDistance -= segmentLength; - } - res.idx = (startIdx - 1 + mod) % mod; - res.pos = points[startIdx]; - res.pair_idx = pair_idx; - res.dis_from_idx = (res.pos - points[res.idx]).norm(); - } - } else { - int next = (startIdx + 1) % mod; - remainingDistance -= (points[startIdx] - startPoint).norm(); - if (remainingDistance <= 0) { - res.idx = startIdx; - res.pos = startPoint - (points[next] - points[startIdx]).normalized() * offset; - res.dis_from_idx = (res.pos - points[startIdx]).norm(); - res.pair_idx = pair_idx; - return res; - } - for (int i = (startIdx - 1 + mod) % mod; i != startIdx; i = (i - 1 + mod) % mod) { - float segmentLength = (points[(i + 1) % mod] - points[i]).norm(); - if (remainingDistance <= segmentLength) { - float ratio = remainingDistance / segmentLength; - res.idx = i; - res.pos = points[(i + 1) % mod] - ratio * (points[(i + 1) % mod] - points[i]); - res.dis_from_idx = segmentLength - remainingDistance; - res.pair_idx = pair_idx; - return res; - } - remainingDistance -= segmentLength; - } - res.idx = startIdx; - res.pos = points[res.idx]; - res.pair_idx = pair_idx; - res.dis_from_idx = 0; - } - return res; -}; - -static void insert_points(std::vector& pl, int idx, Vec2f pos, int pair_idx, bool is_forward) -{ - int next = (idx + 1) % pl.size(); - Vec2f pos1 = pl[idx].pos; - Vec2f pos2 = pl[next].pos; - if ((pos - pos1).squaredNorm() < EPSILON) { - pl[idx].pair_idx = pair_idx; - pl[idx].is_forward = is_forward; - } else if ((pos - pos2).squaredNorm() < EPSILON) { - pl[next].pair_idx = pair_idx; - pl[next].is_forward = is_forward; - } else { - pl.insert(pl.begin() + idx + 1, PointWithFlag{pos, pair_idx, is_forward}); - } -} - -static Polylines remove_points_from_polygon( - const Polygon& polygon, const std::vector& skip_points, double range, bool is_left, Polygon& insert_skip_pg) -{ - assert(polygon.size() > 2); - Polylines result; - std::vector new_pl; // add intersection points for gaps, where bool indicates whether it's a gap point. - std::vector inter_info; - Vec2f ray = is_left ? Vec2f(-1, 0) : Vec2f(1, 0); - auto polygon_box = get_extents(polygon); - Point anchor_point = is_left ? Point{polygon_box.max[0], polygon_box.min[1]} : polygon_box.min; // rd:ld - std::vector points; - { - points.reserve(polygon.points.size()); - int idx = polygon.closest_point_index(anchor_point); - Polyline tmp_poly = polygon.split_at_index(idx); - for (auto& p : tmp_poly) - points.push_back(unscale(p).cast()); - points.pop_back(); - } - - for (int i = 0; i < skip_points.size(); i++) { - for (int j = 0; j < points.size(); j++) { - Vec2f& p1 = points[j]; - Vec2f& p2 = points[(j + 1) % points.size()]; - auto [is_inter, inter_pos] = ray_intersetion_line(skip_points[i], ray, p1, p2); - if (is_inter) { - IntersectionInfo forward = move_point_along_polygon(points, inter_pos, j, range, true, i); - IntersectionInfo backward = move_point_along_polygon(points, inter_pos, j, range, false, i); - backward.is_forward = false; - forward.is_forward = true; - inter_info.push_back(backward); - inter_info.push_back(forward); - break; - } - } - } - - // insert point to new_pl - for (const auto& p : points) - new_pl.push_back({p, -1}); - std::sort(inter_info.begin(), inter_info.end(), [](const IntersectionInfo& lhs, const IntersectionInfo& rhs) { - if (rhs.idx == lhs.idx) - return lhs.dis_from_idx < rhs.dis_from_idx; - return lhs.idx < rhs.idx; - }); - for (int i = inter_info.size() - 1; i >= 0; i--) { - insert_points(new_pl, inter_info[i].idx, inter_info[i].pos, inter_info[i].pair_idx, inter_info[i].is_forward); - } - - { - // set insert_pg for wipe_path - for (auto& p : new_pl) - insert_skip_pg.points.push_back(scaled(p.pos)); - } - - int beg = 0; - bool skip = true; - int i = beg; - Polyline pl; - - do { - if (skip || new_pl[i].pair_idx == -1) { - pl.points.push_back(scaled(new_pl[i].pos)); - i = (i + 1) % new_pl.size(); - skip = false; - } else { - if (!pl.points.empty()) { - pl.points.push_back(scaled(new_pl[i].pos)); - result.push_back(pl); - pl.points.clear(); - } - int left = new_pl[i].pair_idx; - int j = (i + 1) % new_pl.size(); - while (j != beg && new_pl[j].pair_idx != left) { - if (new_pl[j].pair_idx != -1 && !new_pl[j].is_forward) - left = new_pl[j].pair_idx; - j = (j + 1) % new_pl.size(); - } - i = j; - skip = true; - } - } while (i != beg); - - if (!pl.points.empty()) { - if (new_pl[i].pair_idx == -1) - pl.points.push_back(scaled(new_pl[i].pos)); - result.push_back(pl); - } - return result; -} - -static Polylines contrust_gap_for_skip_points( - const Polygon& polygon, const std::vector& skip_points, float wt_width, float gap_length, Polygon& insert_skip_polygon) -{ - if (skip_points.empty()) { - insert_skip_polygon = polygon; - return Polylines{to_polyline(polygon)}; - } - bool is_left = false; - const auto& pt = skip_points.front(); - if (abs(pt.x()) < wt_width / 2.f) { - is_left = true; - } - return remove_points_from_polygon(polygon, skip_points, gap_length, is_left, insert_skip_polygon); -}; - static Polygon generate_rectange_polygon(const Vec2f& wt_box_min, const Vec2f& wt_box_max) { Polygon res; @@ -632,7 +386,8 @@ public: } WipeTowerWriter2& switch_filament_monitoring(bool enable) { - m_gcode += std::string("G4 S0\n") + "M591 " + (enable ? "R" : "S0") + "\n"; + flush_planner_queue(); + m_gcode += enable ? "M591 R\n" : "M591 S0\n"; return *this; } @@ -658,6 +413,7 @@ public: const Vec2f& pos() const { return m_current_pos; } const Vec2f start_pos_rotated() const { return m_start_pos; } const Vec2f pos_rotated() const { return this->rotate(m_current_pos); } + const Vec2f rotated(const Vec2f &pt) const { return this->rotate(pt); } float elapsed_time() const { return m_elapsed_time; } float get_and_reset_used_filament_length() { float temp = m_used_filament_length; m_used_filament_length = 0.f; return temp; } @@ -869,10 +625,13 @@ public: } // Set extruder temperature, don't wait by default. - WipeTowerWriter2& set_extruder_temp(int temperature, bool wait = false) + WipeTowerWriter2& set_extruder_temp(int temperature, bool wait = false, const std::string& comment = std::string()) { - m_gcode += "G4 S0\n"; // to flush planner queue - m_gcode += "M" + std::to_string(wait ? 109 : 104) + " S" + std::to_string(temperature) + "\n"; + flush_planner_queue(); + m_gcode += "M" + std::to_string(wait ? 109 : 104) + " S" + std::to_string(temperature); + if (!comment.empty()) + m_gcode += " " + comment; + m_gcode += "\n"; return *this; } @@ -881,7 +640,7 @@ public: { if (time==0.f) return *this; - m_gcode += "G4 S" + Slic3r::float_to_string_decimal_point(time, 3) + "\n"; + m_gcode += wait_command(m_gcode_flavor, time); return *this; } @@ -923,8 +682,8 @@ public: } WipeTowerWriter2& flush_planner_queue() - { - m_gcode += "G4 S0\n"; + { + m_gcode += flush_planner_queue_command(m_gcode_flavor); return *this; } @@ -1245,6 +1004,19 @@ WipeTower::ToolChangeResult WipeTower2::construct_tcr(WipeTowerWriter2& writer, +bool WipeTower2::use_gap_wall(const PrintConfig& config) +{ + // The cone wall has its own fully separate generator with no gap machinery. + return config.prime_tower_skip_points.value && config.wipe_tower_wall_type.value != wtwCone; +} + +bool WipeTower2::wait_for_temp_enabled(const PrintConfig& config) +{ + // SEMM runs its own unload/load temperature sequence; the GUI hides the option + // there but a profile may still carry it set. + return config.wait_for_temp_on_wipe_tower.value && !config.single_extruder_multi_material.value; +} + WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& default_region_config,int plate_idx, Vec3d plate_origin, const std::vector>& wiping_matrix, size_t initial_tool) : m_semm(config.single_extruder_multi_material.value), m_enable_filament_ramming(config.enable_filament_ramming.value), @@ -1272,9 +1044,10 @@ WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& defau m_rib_width(config.wipe_tower_rib_width), m_extra_rib_length(config.wipe_tower_extra_rib_length), m_wall_type((int)config.wipe_tower_wall_type), - m_flat_ironing(config.prime_tower_flat_ironing.value), + m_use_gap_wall(use_gap_wall(config)), m_enable_tower_interface_features(config.enable_tower_interface_features.value), - m_enable_tower_interface_cooldown_during_tower(config.enable_tower_interface_cooldown_during_tower.value) + m_enable_tower_interface_cooldown_during_tower(config.enable_tower_interface_cooldown_during_tower.value), + m_wait_for_temp_on_wipe_tower(wait_for_temp_enabled(config)) { // Read absolute value of first layer speed, if given as percentage, // it is taken over following default. Speeds from config are not @@ -1324,6 +1097,7 @@ WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& defau m_bed_bottom_left = m_bed_shape == RectangularBed ? Vec2f(bed_points.front().x(), bed_points.front().y()) : Vec2f::Zero(); + m_bed_polygon = Polygon::new_scale(bed_points); } @@ -1342,6 +1116,7 @@ void WipeTower2::set_extruder(size_t idx, const PrintConfig& config) m_filpar[idx].is_soluble = (idx != size_t(m_wipe_tower_filament - 1)); else m_filpar[idx].is_soluble = config.filament_soluble.get_at(idx); + m_filpar[idx].is_support = config.filament_is_support.get_at(idx); m_filpar[idx].temperature = config.nozzle_temperature.get_at(idx); m_filpar[idx].first_layer_temperature = config.nozzle_temperature_initial_layer.get_at(idx); m_filpar[idx].filament_minimal_purge_on_wipe_tower = config.filament_minimal_purge_on_wipe_tower.get_at(idx); @@ -1474,15 +1249,15 @@ std::vector WipeTower2::prime( unsigned int tool = tools[idx_tool]; m_left_to_right = true; - toolchange_Change(writer, tool, m_filpar[tool].material); // Select the tool, set a speed override for soluble and flex materials. + toolchange_Change(writer, tool, m_filpar[tool].material, m_filpar[tool].first_layer_temperature, false); // Select the tool, set a speed override for soluble and flex materials. toolchange_Load(writer, cleaning_box); // Prime the tool. if (idx_tool + 1 == tools.size()) { // Last tool should not be unloaded, but it should be wiped enough to become of a pure color. - toolchange_Wipe(writer, cleaning_box, wipe_volumes[tools[idx_tool-1]][tool], false); + toolchange_Wipe(writer, cleaning_box, wipe_volumes[tools[idx_tool-1]][tool], false, true); } else { // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. //writer.travel(writer.x(), writer.y() + m_perimeter_width, 7200); - toolchange_Wipe(writer, cleaning_box , 20.f, false); + toolchange_Wipe(writer, cleaning_box , 20.f, false, true); WipeTower::box_coordinates box = cleaning_box; box.translate(0.f, writer.y() - cleaning_box.ld.y() + m_perimeter_width); toolchange_Unload(writer, box , m_filpar[m_current_tool].material, m_filpar[m_current_tool].first_layer_temperature, m_filpar[tools[idx_tool + 1]].first_layer_temperature); @@ -1525,8 +1300,9 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool) float wipe_area = 0.f; float wipe_volume = 0.f; + float ramming_depth = 0.f; bool interface_layer = m_enable_tower_interface_features && m_current_layer_has_interface; - + // Finds this toolchange info if (tool != (unsigned int)(-1)) { @@ -1534,6 +1310,7 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool) if ( b.new_tool == tool ) { wipe_volume = b.wipe_volume; wipe_area = b.required_depth; + ramming_depth = b.ramming_depth; break; } } @@ -1571,7 +1348,9 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool) writer.speed_override_backup(); writer.speed_override(100); - Vec2f initial_position = cleaning_box.ld + Vec2f(0.f, m_depth_traversed); + // On a boundary wipe start this enters at the wall gap on the first wipe row; + // toolchange_Unload() then climbs back up to the ram band along the box interior. + Vec2f initial_position = toolchange_entry_pos(m_depth_traversed, ramming_depth, is_first_layer()); writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); // Increase the extruder driver current to allow fast ramming. @@ -1580,17 +1359,28 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool) // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. if (tool != (unsigned int)-1){ // This is not the last change. + // Without a ram — or with the boundary wipe start, where the ram band is + // quantized to whole rows — the box is planned as whole wipe rows; the wipe + // then fills it completely so adjacent purge blocks stay contiguous. Uses the + // old tool (m_current_tool before toolchange_Change). + const bool fill_box = !tool_ramming_enabled(m_current_tool) || boundary_wipe_start_enabled(m_current_tool); auto new_tool_temp = is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature; toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, (is_first_layer() ? m_filpar[m_current_tool].first_layer_temperature : m_filpar[m_current_tool].temperature), new_tool_temp); - toolchange_Change(writer, tool, m_filpar[tool].material); // Change the tool, set a speed override for soluble and flex materials. + // Wait-at-tower target: the interface temp when an interface boost applies on this layer, + // otherwise the print temp (nozzle_temperature == 0 means "use the first layer temp"). + int wait_for_temp = interface_layer && m_filpar[tool].interface_print_temperature > 0 ? + m_filpar[tool].interface_print_temperature : + (is_first_layer() || m_filpar[tool].temperature == 0 ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature); + toolchange_Change(writer, tool, m_filpar[tool].material, wait_for_temp, true); // Change the tool, set a speed override for soluble and flex materials. toolchange_Load(writer, cleaning_box); writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road int base_temp = is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature; if (interface_layer) { int interface_temp = m_filpar[tool].interface_print_temperature; - if (interface_temp > 0 && interface_temp != base_temp) + // With wait-for-temp-on-wipe-tower the toolchange already blocked for the interface temp. + if (interface_temp > 0 && interface_temp != base_temp && !m_wait_for_temp_on_wipe_tower) writer.set_extruder_temp(interface_temp, true); if (m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp) writer.set_extruder_temp(base_temp, false); @@ -1602,7 +1392,7 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool) writer.extrude_explicit(target_x, writer.y(), pre_len, 600.f); } } - toolchange_Wipe(writer, cleaning_box, wipe_volume, interface_layer); // Wipe the newly loaded filament until the end of the assigned wipe area. + toolchange_Wipe(writer, cleaning_box, wipe_volume, interface_layer, false, fill_box); // Wipe the newly loaded filament until the end of the assigned wipe area. if (interface_layer) { int interface_temp = m_filpar[tool].interface_print_temperature; if (!m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp) @@ -1657,11 +1447,20 @@ void WipeTower2::toolchange_Unload( float remaining = xr - xl ; // keeps track of distance to the next turnaround float e_done = 0; // measures E move done from each segment - // Orca: Do ramming when SEMM and ramming is enabled or when multi tool head when ramming is enabled on the multi tool. - const bool do_ramming = (m_semm && m_enable_filament_ramming) || m_filpar[m_current_tool].multitool_ramming; + const bool do_ramming = tool_ramming_enabled(m_current_tool); const bool cold_ramming = m_is_mk4mmu3; + // Orca: see set_toolchange() — quantized ram band + wipe restart at the boundary. + const bool boundary_wipe_start = boundary_wipe_start_enabled(m_current_tool); + float planned_ramming_depth = 0.f; + if (boundary_wipe_start && m_layer_info != m_plan.end()) + for (const auto& tch : m_layer_info->tool_changes) + if (tch.old_tool == m_current_tool) { planned_ramming_depth = tch.ramming_depth; break; } if (do_ramming) { + if (boundary_wipe_start) + // The entry sits at the wall gap on the first wipe row past the reserved + // ram band; step inward first, then move to the band clear of the wall. + writer.travel(Vec2f(ramming_start_pos.x(), writer.y())); writer.travel(ramming_start_pos); // move to starting position if (! m_is_mk4mmu3) writer.disable_linear_advance(); @@ -1672,7 +1471,8 @@ void WipeTower2::toolchange_Unload( writer.set_position(ramming_start_pos); // if the ending point of the ram would end up in mid air, align it with the end of the wipe tower: - if (do_ramming && (m_layer_info > m_plan.begin() && m_layer_info < m_plan.end() && (m_layer_info-1!=m_plan.begin() || !m_adhesion ))) { + // (with a boundary wipe start the band is quantized to whole rows below, so no phase alignment is needed) + if (do_ramming && !boundary_wipe_start && (m_layer_info > m_plan.begin() && m_layer_info < m_plan.end() && (m_layer_info-1!=m_plan.begin() || !m_adhesion ))) { // this is y of the center of previous sparse infill border float sparse_beginning_y = 0.f; @@ -1731,6 +1531,28 @@ void WipeTower2::toolchange_Unload( e_done = 0; } } + + // Orca: quantize the ram band up to the whole reserved rows (BBL quantizes the + // old-tool purge the same way) so no unprinted void is left between the band and + // the wipe restarting at the boundary below it. + if (planned_ramming_depth > 0.f) { + const int reserved_rows = std::max(1, int(std::round(planned_ramming_depth / y_step))); + const float last_row_y = ramming_start_pos.y() + (reserved_rows - 1) * y_step; + // Same bead model as the ramming segments above: E per mm of ram line. + const float e_per_mm = 1.f / (volume_to_length(1.f, line_width, m_layer_height) * filament_area()); + const float fill_feed = m_filpar[m_current_tool].ramming_speed.empty() ? 3000.f : + 60.f * volume_to_length(m_filpar[m_current_tool].ramming_speed.back(), line_width, m_layer_height); + while (true) { + const float target_x = m_left_to_right ? xr : xl; + if (std::abs(target_x - writer.x()) > WT_EPSILON) + writer.ram(writer.x(), target_x, 0.f, 0.f, e_per_mm * std::abs(target_x - writer.x()), fill_feed); + if (writer.y() + 0.5f * y_step > last_row_y) + break; + writer.travel(writer.x(), writer.y() + y_step, 7200); + m_left_to_right = !m_left_to_right; + } + } + Vec2f end_of_ramming(writer.x(),writer.y()); writer.change_analyzer_line_width(m_perimeter_width); // so the next lines are not affected by ramming_line_width_multiplier @@ -1838,10 +1660,27 @@ void WipeTower2::toolchange_Unload( // this is to align ramming and future wiping extrusions, so the future y-steps can be uniform from the start: // the perimeter_width will later be subtracted, it is there to not load while moving over just extruded material Vec2f pos = Vec2f(end_of_ramming.x(), end_of_ramming.y() + (y_step/m_extra_spacing_ramming-m_perimeter_width) / 2.f + m_perimeter_width); - if (do_ramming) + if (planned_ramming_depth > 0.f) { + // Orca: restart the wipe at the left-edge boundary on a fresh row below the + // quantized ram band so the entry scrub always runs at the wall gap (BBL keeps + // CP_TOOLCHANGE_WIPE starting at a box corner the same way). Same lattice + // formula as the no-ram branch below, offset by the ram band. + writer.travel(Vec2f(ramming_start_pos.x(), + cleaning_box.ld.y() + m_depth_traversed + + wipe_start_offset_after_ram(planned_ramming_depth, is_first_layer()) + m_perimeter_width), 2400.f); + m_left_to_right = true; + } + else if (do_ramming) writer.travel(pos, 2400.f); - else - writer.set_position(pos); + else { + // Orca: with no ram printed there is no ramming geometry to align with. Start the + // first wipe row so the purge row lattice continues across the block boundary + // (previous box's last row top edge sits at its box top): with the planned depth + // of rows * dy, the last row's top edge then lands exactly on this box's top and + // no blank band is left between adjacent purge blocks. + writer.set_position(Vec2f(end_of_ramming.x(), + cleaning_box.ld.y() + m_depth_traversed + wipe_start_offset_after_ram(0.f, is_first_layer()) + m_perimeter_width)); + } writer.resume_preview() .flush_planner_queue(); @@ -1851,7 +1690,9 @@ void WipeTower2::toolchange_Unload( void WipeTower2::toolchange_Change( WipeTowerWriter2 &writer, const size_t new_tool, - const std::string& new_material) + const std::string& new_material, + const int wait_for_temp, + const bool wait_beside_tower) { // Ask the writer about how much of the old filament we consumed: if (m_current_tool < m_used_filament_length.size()) @@ -1865,6 +1706,90 @@ void WipeTower2::toolchange_Change( if (m_is_mk4mmu3) writer.switch_filament_monitoring(true); + const bool wait_for_temp_here = m_wait_for_temp_on_wipe_tower && wait_for_temp > 0; + + // The Tn above was issued without a blocking temperature wait (GCode::set_extruder only raises + // the target, ahead of the Tn); block here, before the deretraction below, which must not + // extrude on a cold nozzle. Like the Bambu H2C, park beside the tower for the heat-up so drool lands + // next to it instead of on its top surface — nearest x side first, then that side clamped + // toward the bed edge, then the far side, in place if all would leave the bed. Raw + // pre-rotated moves (see the repositioning move below) keep the writer's tracked position + // at the tower entry. The tag keeps the + // interface-temp deduplication pass in append_tcr2 from stripping the M109. + if (wait_for_temp_here && wait_beside_tower) { + // The rib wall and the stabilization cone bulge past the nominal width rectangle + // (widest near the bottom), and the first-layer brim is printed around the wall later + // in the layer — clear the widest of them, not just the rectangle, so the park point + // and its drool stay off the tower. + float min_x = 0.f, max_x = m_wipe_tower_width; + if (m_wall_type == (int)wtwRib) { + WipeTower::box_coordinates wt_box(Vec2f(0.f, 0.f), m_wipe_tower_width, m_layer_info->depth + m_perimeter_width); + const BoundingBox rib_bbox = get_extents(generate_rib_polygon(wt_box)); // the fillet stays within this bbox + min_x = std::min(min_x, unscaled(rib_bbox.min.x())); + max_x = std::max(max_x, unscaled(rib_bbox.max.x())); + } else if (m_wall_type == (int)wtwCone) { + const double support_scale = get_wipe_tower_cone_base(m_wipe_tower_width, m_wipe_tower_height, m_wipe_tower_depth, + m_wipe_tower_cone_angle).second; + const double z = m_no_sparse_layers ? (m_current_height + m_layer_info->height) : m_layer_info->z; + const double r = std::tan(Geometry::deg2rad(m_wipe_tower_cone_angle / 2.f)) * (m_wipe_tower_height - z); + const double w = m_layer_info->depth + m_perimeter_width; + if (r > 0.5 * w + 0.01) { // same guard as generate_support_cone_wall + const float bulge = float(std::sqrt(r * r - 0.25 * w * w) / support_scale); + min_x = std::min(min_x, m_wipe_tower_width / 2.f - bulge); + max_x = std::max(max_x, m_wipe_tower_width / 2.f + bulge); + } + } + if (is_first_layer()) { + const float brim = m_wipe_tower_brim_width < 0.f ? WipeTower::get_auto_brim_by_height(m_wipe_tower_height) : + m_wipe_tower_brim_width; + min_x -= brim; + max_x += brim; + } + constexpr float gap = 2.f; + constexpr float min_gap = 0.5f; + const bool on_left = writer.x() < m_wipe_tower_width / 2.f; + const float near_x = on_left ? min_x - gap : max_x + gap; + const float far_x = on_left ? max_x + gap : min_x - gap; + const Eigen::Rotation2Df to_bed(float(Geometry::deg2rad(m_wipe_tower_rotation_angle))); + auto park_pt_on_bed = [this, &writer, to_bed](float side_x) { + const Vec2f bed_pt = to_bed * (writer.rotated(Vec2f(side_x, writer.y())) + m_rib_offset) + m_wipe_tower_pos; + return m_bed_polygon.contains(Point::new_scale(bed_pt.x(), bed_pt.y())); + }; + float park_x = near_x; + bool have_park = park_pt_on_bed(near_x); + if (!have_park) { + // The ideal near point hangs off the bed: pull it back to the bed edge as long + // as that still clears the tower envelope by min_gap (the BBL tower clamps its + // stop_pos against the bed the same way in append_tcr). Bisection, because with + // tower rotation and non-rectangular beds the bed edge is not axis-aligned. + const float limit_x = on_left ? min_x - min_gap : max_x + min_gap; + if (park_pt_on_bed(limit_x)) { + float on = limit_x, off = near_x; + for (int i = 0; i < 8; ++i) { + const float mid = 0.5f * (on + off); + if (park_pt_on_bed(mid)) + on = mid; + else + off = mid; + } + park_x = on; + have_park = true; + } + } + if (!have_park && park_pt_on_bed(far_x)) { + park_x = far_x; + have_park = true; + } + if (have_park) { + const Vec2f stop = writer.rotated(Vec2f(park_x, writer.y())); + writer.feedrate(m_travel_speed * 60.f) + .append(std::string("G1 X") + Slic3r::float_to_string_decimal_point(stop.x()) + + " Y" + Slic3r::float_to_string_decimal_point(stop.y()) + + never_skip_tag() + "\n"); + } + writer.set_extruder_temp(wait_for_temp, true, wait_for_temp_tag()); + } + // Travel to where we assume we are. Custom toolchange or some special T code handling (parking extruder etc) // gcode could have left the extruder somewhere, we cannot just start extruding. We should also inform the // postprocessor that we absolutely want to have this in the gcode, even if it thought it is the same as before. @@ -1875,6 +1800,10 @@ void WipeTower2::toolchange_Change( + never_skip_tag() + "\n" ); + // Priming has no tower to park beside — wait right at the priming line instead. + if (wait_for_temp_here && !wait_beside_tower) + writer.set_extruder_temp(wait_for_temp, true, wait_for_temp_tag()); + writer.append("[deretraction_from_wipe_tower_generator]"); // The toolchange Tn command will be inserted later, only in case that the user does @@ -1920,7 +1849,9 @@ void WipeTower2::toolchange_Wipe( WipeTowerWriter2 &writer, const WipeTower::box_coordinates &cleaning_box, float wipe_volume, - bool interface_layer) + bool interface_layer, + bool priming, + bool fill_box) { // Increase flow on first layer, slow down print. writer.set_extrusion_flow(m_extrusion_flow * (is_first_layer() ? 1.18f : 1.f)) @@ -1929,7 +1860,7 @@ void WipeTower2::toolchange_Wipe( const float& xr = cleaning_box.rd.x(); writer.set_extrusion_flow(m_extrusion_flow * m_extra_flow); - const float line_width = m_perimeter_width * m_extra_flow; + const float line_width = wipe_line_width(); writer.change_analyzer_line_width(line_width); // Variables x_to_wipe and traversed_x are here to be able to make sure it always wipes at least @@ -1937,7 +1868,7 @@ void WipeTower2::toolchange_Wipe( // wipe until the end of the assigned area. float x_to_wipe = volume_to_length(wipe_volume, m_perimeter_width, m_layer_height) / m_extra_flow; - float dy = (is_first_layer() ? m_extra_flow : m_extra_spacing_wipe) * m_perimeter_width; // Don't use the extra spacing for the first layer, but do use the spacing resulting from increased flow. + float dy = wipe_row_spacing(is_first_layer()); // Don't use the extra spacing for the first layer, but do use the spacing resulting from increased flow. // All the calculations in all other places take the spacing into account for all the layers. // If spare layers are excluded->if 1 or less toolchange has been done, it must be sill the first layer, too.So slow down. @@ -1950,9 +1881,6 @@ void WipeTower2::toolchange_Wipe( m_left_to_right = !m_left_to_right; } - const bool do_ironing = m_flat_ironing && (!interface_layer || !m_enable_tower_interface_features); - const float ironing_area = m_filpar[m_current_tool].tower_ironing_area; - // now the wiping itself: for (int i = 0; true; ++i) { if (i!=0) { @@ -1963,22 +1891,45 @@ void WipeTower2::toolchange_Wipe( } float traversed_x = writer.x(); + + // BBS gap wall: iron the first few mm of the purge, then drag the retracted nozzle + // back out through the wall gap and scrub it with a dry spiral centred on the entry + // point so the toolchange start blob is not left on the wall (same sequence as the + // BBL tower's toolchange_wipe_new; the spiral self-disables when the filament's + // tower ironing area is 0). WT2's entry gap always sits at the left-edge entry + // point, so only iron when the purge actually starts there heading right (in-place + // toolchangers do; SEMM ram/cooling moves leave the nozzle mid-box, far from any gap). + if (i == 0 && m_use_gap_wall && !interface_layer && !priming && m_left_to_right && + writer.x() - xl < 2.5f * line_width) { + float ironing_length = 3.f; + if (xr - writer.x() < ironing_length) + ironing_length = std::max(xr - writer.x(), 0.f); + const float retract_length = m_filpar[m_current_tool].retract_length; + const float retract_speed = m_filpar[m_current_tool].retract_speed * 60.f; + writer.extrude(writer.x() + ironing_length, writer.y(), wipe_speed); + writer.retract(retract_length, retract_speed); + writer.travel(writer.x() - 1.5f * ironing_length, writer.y(), 600.f); + writer.travel(writer.x() + 0.5f * ironing_length, writer.y(), 240.f); + const Vec2f iron_end(writer.x() + ironing_length, writer.y()); + writer.spiral_flat_ironing(writer.pos(), m_filpar[m_current_tool].tower_ironing_area, m_perimeter_width, flat_iron_speed); + writer.travel(iron_end, wipe_speed); + writer.retract(-retract_length, retract_speed); + } + if (m_left_to_right) writer.extrude(xr - (i % 4 == 0 ? 0 : 1.5f*line_width), writer.y(), wipe_speed); else writer.extrude(xl + (i % 4 == 1 ? 0 : 1.5f*line_width), writer.y(), wipe_speed); - if (i == 0 && do_ironing && ironing_area > 0.f) { - writer.travel(writer.x(), writer.y(), 600.f); - writer.spiral_flat_ironing(writer.pos(), ironing_area, m_perimeter_width, 10.f * 60.f); - } - if (writer.y()+float(EPSILON) > cleaning_box.lu.y()-0.5f*line_width) break; // in case next line would not fit traversed_x -= writer.x(); x_to_wipe -= std::abs(traversed_x); - if (x_to_wipe < WT_EPSILON) { + // Orca: with no ram printed the box was planned as whole wipe rows; fill it + // completely (quantizing the purge up to the planned rows) so the next block + // can start right above it without a blank band in between. + if (!fill_box && x_to_wipe < WT_EPSILON) { writer.travel(m_left_to_right ? xl + 1.5f*line_width : xr - 1.5f*line_width, writer.y(), 7200); break; } @@ -2110,7 +2061,7 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer() poly = generate_support_cone_wall(writer, wt_box, feedrate, infill_cone, spacing); } else { WipeTower::box_coordinates wt_box(Vec2f(0.f, 0.f), m_wipe_tower_width, m_layer_info->depth + m_perimeter_width); - poly = generate_support_rib_wall(writer, wt_box, feedrate, first_layer, m_wall_type == (int)wtwRib, true, false); + poly = generate_support_rib_wall(writer, wt_box, feedrate, first_layer, m_wall_type == (int)wtwRib, true); } // brim (first layer only) @@ -2179,31 +2130,68 @@ std::pair WipeTower2::get_wipe_tower_cone_base(double width, dou } // Static method to extract wipe_volumes[from][to] from the configuration. -std::vector> WipeTower2::extract_wipe_volumes(const PrintConfig& config) +// Takes a ConfigBase so the GUI's wipe tower size estimate can pass the plate's +// DynamicPrintConfig directly instead of materializing a full PrintConfig per call. +std::vector> WipeTower2::extract_wipe_volumes(const ConfigBase& config) { - // Get wiping matrix to get number of extruders and convert vector to vector: - std::vector wiping_matrix(cast(config.flush_volumes_matrix.values)); - auto scale = config.flush_multiplier.get_at(0); + // flush_volumes_matrix holds one filaments x filaments block per nozzle (written by + // PresetBundle::update_multi_material_filament_presets), so the filament count is + // sqrt(size / nozzles). One tower serves every nozzle and the filament to nozzle assignment is + // only decided later by ToolOrdering, so fold the blocks with std::max: the depth reserved here + // has to cover the worst nozzle. With a single nozzle the fold has one term. + const std::vector &raw_matrix = config.option("flush_volumes_matrix")->values; + const auto *nozzle_diameter = config.option("nozzle_diameter"); + size_t nozzle_nums = (nozzle_diameter == nullptr || nozzle_diameter->values.empty()) ? 1 : nozzle_diameter->values.size(); + unsigned int number_of_extruders = (unsigned int)(sqrt(raw_matrix.size() / nozzle_nums) + EPSILON); + if (size_t(number_of_extruders) * number_of_extruders * nozzle_nums != raw_matrix.size()) { + // Saved for a different nozzle count (older project, or the printer was just switched): + // fall back to reading the whole option as one block, as this did before. + nozzle_nums = 1; + number_of_extruders = (unsigned int)(sqrt(raw_matrix.size()) + EPSILON); + } // The values shall only be used when SEMM is enabled. The purging for other printers // is determined by filament_minimal_purge_on_wipe_tower. - if (! config.purge_in_prime_tower.value || ! config.single_extruder_multi_material.value) - std::fill(wiping_matrix.begin(), wiping_matrix.end(), 0.f); + const bool purge = config.option("purge_in_prime_tower")->value + && config.option("single_extruder_multi_material")->value; - // Extract purging volumes for each extruder pair: - std::vector> wipe_volumes; - const unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+EPSILON); - for (size_t i = 0; i(wiping_matrix.begin()+i*number_of_extruders, wiping_matrix.begin()+(i+1)*number_of_extruders)); + // Extract purging volumes for each extruder pair, each nozzle's block scaled by its own multiplier: + std::vector> wipe_volumes(number_of_extruders, std::vector(number_of_extruders, 0.f)); + if (purge) { + const auto *multiplier = config.option("flush_multiplier"); + for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) { + const std::vector block = get_flush_volumes_matrix(raw_matrix, nozzle_id, nozzle_nums); + const double scale = multiplier->get_at(nozzle_id); + for (unsigned int i = 0; i(wipe_volumes[i][j], float(block[size_t(i) * number_of_extruders + j]) * scale); + } + } // Also include filament_minimal_purge_on_wipe_tower. This is needed for the preview. + const auto *minimal_purge = config.option("filament_minimal_purge_on_wipe_tower"); for (unsigned int i = 0; i(wipe_volumes[i][j] * scale, config.filament_minimal_purge_on_wipe_tower.get_at(j)); + wipe_volumes[i][j] = std::max(wipe_volumes[i][j], minimal_purge->get_at(j)); return wipe_volumes; } +float WipeTower2::estimate_semm_flush_volume(const ConfigBase& config, size_t filaments_cnt) +{ + const std::vector> wipe_volumes = extract_wipe_volumes(config); + if (wipe_volumes.empty()) // an empty flush matrix would make the average below 0/0 + return 0.f; + float maximum = 0.f; + for (const std::vector &v : wipe_volumes) + maximum += *std::max_element(v.begin(), v.end()); + maximum = maximum * filaments_cnt / wipe_volumes.size(); + + // Orca: it's overshooting a bit, so let's reduce it a bit + maximum *= 0.6; + return maximum; +} + static float get_wipe_depth(float volume, float layer_height, float perimeter_width, float extra_flow, float extra_spacing, float width) { float length_to_extrude = (volume_to_length(volume, perimeter_width, layer_height)) / extra_flow; @@ -2228,15 +2216,32 @@ void WipeTower2::plan_toolchange(float z_par, float layer_height_par, unsigned i return; // this is an actual toolchange - let's calculate depth to reserve on the wipe tower - float width = m_wipe_tower_width - 3*m_perimeter_width; - float length_to_extrude = volume_to_length(0.25f * std::accumulate(m_filpar[old_tool].ramming_speed.begin(), m_filpar[old_tool].ramming_speed.end(), 0.f), - m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator, - layer_height_par); - // Orca: Set ramming depth to 0 if ramming is disabled. - float ramming_depth = m_enable_filament_ramming ? ((int(length_to_extrude / width) + 1) * (m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator * m_filpar[old_tool].ramming_step_multiplicator) * m_extra_spacing_ramming) : 0; - float first_wipe_line = - (width*((length_to_extrude / width)-int(length_to_extrude / width)) - width); + const bool first_layer_plan = (m_plan.size() - 1) == m_first_layer_idx; + m_plan.back().tool_changes.push_back(set_toolchange(old_tool, new_tool, layer_height_par, wipe_volume, first_layer_plan)); +} - float first_wipe_volume = length_to_volume(first_wipe_line, m_perimeter_width * m_extra_flow, layer_height_par); +WipeTower2::WipeTowerInfo::ToolChange WipeTower2::set_toolchange(size_t old_tool, size_t new_tool, float layer_height, float wipe_volume, bool first_layer_plan) +{ + float width = m_wipe_tower_width - 3*m_perimeter_width; + float length_to_extrude = volume_to_length((m_semm ? 0.25f : m_filpar[old_tool].multitool_ramming_time) * std::accumulate(m_filpar[old_tool].ramming_speed.begin(), m_filpar[old_tool].ramming_speed.end(), 0.f), + m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator, + layer_height); + // Orca: Reserve ramming depth only when toolchange_Unload() will actually ram, + // otherwise the unprinted reservation leaves blank bands between the purge boxes. + const bool do_ramming = tool_ramming_enabled(old_tool); + // Orca: with the gap wall on a multi-tool printer the ram band is quantized up to + // the whole reserved rows and the wipe restarts at the left-edge boundary on a + // fresh row below it (BBL parity: the old-tool purge is whole rows and the wipe + // always starts at the box corner, where the entry scrub runs). + const bool boundary_wipe_start = boundary_wipe_start_enabled(old_tool); + float ramming_depth = do_ramming ? ((int(length_to_extrude / width) + 1) * (m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator * m_filpar[old_tool].ramming_step_multiplicator) * m_extra_spacing_ramming) : 0; + // first_wipe_line rides for free on the last (partially used) ramming row, which + // is already covered by ramming_depth. Without ramming that row does not exist + // (and with a boundary wipe start the ram band is quantized to whole rows), so + // the whole wipe volume needs reserved wiping depth. + float first_wipe_line = (do_ramming && !boundary_wipe_start) ? - (width*((length_to_extrude / width)-int(length_to_extrude / width)) - width) : 0.f; + + float first_wipe_volume = length_to_volume(first_wipe_line, m_perimeter_width * m_extra_flow, layer_height); // ORCA: Keep wipe-depth planning consistent with toolchange_Wipe(). // ORCA: On the first layer, toolchange_Wipe() advances purge rows using @@ -2245,12 +2250,11 @@ void WipeTower2::plan_toolchange(float z_par, float layer_height_par, unsigned i // ORCA: float dy = (is_first_layer() ? m_extra_flow : m_extra_spacing_wipe) * m_perimeter_width; // ORCA: Use the same spacing here so reserved depth matches consumed depth // ORCA: and first-layer purge segments do not leave visible gaps. - const bool first_layer_plan = (m_plan.size() - 1) == m_first_layer_idx; const float planning_spacing = first_layer_plan ? m_extra_flow : m_extra_spacing_wipe; - float wiping_depth = get_wipe_depth(wipe_volume - first_wipe_volume, layer_height_par, m_perimeter_width, m_extra_flow, planning_spacing, width); - - m_plan.back().tool_changes.push_back(WipeTowerInfo::ToolChange(old_tool, new_tool, ramming_depth + wiping_depth, ramming_depth, first_wipe_line, wipe_volume)); + float wiping_depth = get_wipe_depth(wipe_volume - first_wipe_volume, layer_height, m_perimeter_width, m_extra_flow, planning_spacing, width); + + return WipeTowerInfo::ToolChange(old_tool, new_tool, ramming_depth + wiping_depth, ramming_depth, first_wipe_line, wipe_volume); } @@ -2288,49 +2292,64 @@ void WipeTower2::save_on_last_wipe() continue; // Which toolchange will finish_layer extrusions be subtracted from? - int idx = first_toolchange_to_nonsoluble(m_layer_info->tool_changes); + int idx = first_toolchange_to_nonsoluble_nonsupport(m_layer_info->tool_changes); if (idx == -1) { // In this case, finish_layer will be called at the very beginning. finish_layer().total_extrusion_length_in_plane(); } + const float width = m_wipe_tower_width - 3*m_perimeter_width; // width we draw into + auto recompute_toolchange = [this, width](WipeTowerInfo::ToolChange& toolchange, float volume_to_save) { + float volume_left_to_wipe = std::max(m_filpar[toolchange.new_tool].filament_minimal_purge_on_wipe_tower, toolchange.wipe_volume_total - volume_to_save); + float volume_we_need_depth_for = std::max(0.f, volume_left_to_wipe - length_to_volume(toolchange.first_wipe_line, m_perimeter_width*m_extra_flow, m_layer_info->height)); + + // ORCA: Keep wipe-depth planning consistent with toolchange_Wipe(). + // ORCA: On the first layer, toolchange_Wipe() advances purge rows using + // ORCA: m_extra_flow * m_perimeter_width, while later layers use + // ORCA: m_extra_spacing_wipe * m_perimeter_width. + // ORCA: float dy = (is_first_layer() ? m_extra_flow : m_extra_spacing_wipe) * m_perimeter_width; + // ORCA: Use the same spacing here so reserved depth matches consumed depth + // ORCA: and first-layer purge segments do not leave visible gaps. + const bool first_layer_plan = size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; + const float planning_spacing = first_layer_plan ? m_extra_flow : m_extra_spacing_wipe; + + float depth_to_wipe = get_wipe_depth(volume_we_need_depth_for, m_layer_info->height, m_perimeter_width, m_extra_flow, planning_spacing, width); + + toolchange.required_depth = toolchange.ramming_depth + depth_to_wipe; + toolchange.wipe_volume = volume_left_to_wipe; + }; + for (int i=0; itool_changes.size()); ++i) { auto& toolchange = m_layer_info->tool_changes[i]; tool_change(toolchange.new_tool); if (i == idx) { - float width = m_wipe_tower_width - 3*m_perimeter_width; // width we draw into - - float volume_to_save = length_to_volume(finish_layer().total_extrusion_length_in_plane(), m_perimeter_width, m_layer_info->height); - float volume_left_to_wipe = std::max(m_filpar[toolchange.new_tool].filament_minimal_purge_on_wipe_tower, toolchange.wipe_volume_total - volume_to_save); - float volume_we_need_depth_for = std::max(0.f, volume_left_to_wipe - length_to_volume(toolchange.first_wipe_line, m_perimeter_width*m_extra_flow, m_layer_info->height)); - - // ORCA: Keep wipe-depth planning consistent with toolchange_Wipe(). - // ORCA: On the first layer, toolchange_Wipe() advances purge rows using - // ORCA: m_extra_flow * m_perimeter_width, while later layers use - // ORCA: m_extra_spacing_wipe * m_perimeter_width. - // ORCA: float dy = (is_first_layer() ? m_extra_flow : m_extra_spacing_wipe) * m_perimeter_width; - // ORCA: Use the same spacing here so reserved depth matches consumed depth - // ORCA: and first-layer purge segments do not leave visible gaps. - const bool first_layer_plan = size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; - const float planning_spacing = first_layer_plan ? m_extra_flow : m_extra_spacing_wipe; - - float depth_to_wipe = get_wipe_depth(volume_we_need_depth_for, m_layer_info->height, m_perimeter_width, m_extra_flow, planning_spacing, width); - - toolchange.required_depth = toolchange.ramming_depth + depth_to_wipe; - toolchange.wipe_volume = volume_left_to_wipe; + recompute_toolchange(toolchange, length_to_volume(finish_layer().total_extrusion_length_in_plane(), m_perimeter_width, m_layer_info->height)); + } else if (toolchange.wipe_volume < m_filpar[toolchange.new_tool].filament_minimal_purge_on_wipe_tower) { + // Keep filament_minimal_purge_on_wipe_tower enforced for toolchanges that get + // no finish-layer saving, e.g. a support/soluble filament skipped as the + // finish filament above. Recomputing only when the clamp binds leaves all + // other toolchanges with their planned values bit-for-bit. + recompute_toolchange(toolchange, 0.f); } } } } -// Return index of first toolchange that switches to non-soluble extruder -// ot -1 if there is no such toolchange. -int WipeTower2::first_toolchange_to_nonsoluble( +// Return the index of the toolchange whose new filament should print the layer's +// finish extrusions (sparse infill + wall + brim), or -1 to print them with the +// layer's incoming filament before any toolchange happens. +// Like WipeTower::first_toolchange_to_nonsoluble_nonsupport(): support and soluble +// filaments bond poorly to the material printed on top of them, so they must not +// print the tower's shell when another filament is available on the layer. +int WipeTower2::first_toolchange_to_nonsoluble_nonsupport( const std::vector& tool_changes) const { + if (tool_changes.empty()) + return -1; + // If a specific wipe tower filament is forced, use it to decide where to finish the layer. if (m_wipe_tower_filament > 0) { for (size_t idx = 0; idx < tool_changes.size(); ++idx) { @@ -2339,8 +2358,19 @@ int WipeTower2::first_toolchange_to_nonsoluble( } return -1; } - // Orca: allow calculation of the required depth and wipe volume for soluble toolchanges as well. - return tool_changes.empty() ? -1 : 0; + + auto is_wall_filament = [this](size_t tool) { + return !m_filpar[tool].is_soluble && !m_filpar[tool].is_support; + }; + for (size_t idx = 0; idx < tool_changes.size(); ++idx) + if (is_wall_filament(tool_changes[idx].new_tool)) + return idx; + if (is_wall_filament(tool_changes.front().old_tool)) + return -1; + // Only support/soluble filaments on this layer: keep the first toolchange so the + // finish-layer saving and the minimal-purge clamp still apply to it (Orca depth + // and wipe volume accounting, see save_on_last_wipe()). + return 0; } static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult& first, @@ -2363,6 +2393,24 @@ static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult& first, } +// Precompute, for every plan layer, the wall openings ("skip points") at each toolchange's +// entry position, like WipeTower::get_all_wall_skip_points(). toolchange_entry_pos() +// reproduces from the finalized plan where tool_change() will start, so each gap coincides +// with the entry travel's target (tcr.start_pos, pre-rotation frame). BBL parity: the gap +// sits at the CP_TOOLCHANGE_WIPE start row, never at the ram band. +void WipeTower2::compute_wall_skip_points() +{ + m_wall_skip_points.assign(m_plan.size(), std::vector()); + for (size_t layer_id = 0; layer_id < m_plan.size(); ++layer_id) { + float depth_traversed = 0.f; + for (const auto& toolchange : m_plan[layer_id].tool_changes) { + m_wall_skip_points[layer_id].emplace_back( + toolchange_entry_pos(depth_traversed, toolchange.ramming_depth, layer_id == m_first_layer_idx)); + depth_traversed += toolchange.required_depth; + } + } +} + // Processes vector m_plan and calls respective functions to generate G-code for the wipe tower // Resulting ToolChangeResults are appended into vector "result" void WipeTower2::generate(std::vector> &result) @@ -2378,12 +2426,41 @@ void WipeTower2::generate(std::vector> } #endif - m_rib_length = std::max({m_rib_length, sqrt(m_wipe_tower_depth * m_wipe_tower_depth + m_wipe_tower_width * m_wipe_tower_width)}); + if (m_wall_type == (int)wtwRib) { + // Rib wall: force a square tower like WipeTower::plan_tower_new(), ignoring the + // configured prime_tower_width (the GUI greys it out in rib mode). The planned depths + // already include the extra-spacing factors, so sqrt(depth * width) preserves the + // purge area. Replan every toolchange for the new width, then re-derive the depths. + float max_depth = 0.f; + for (const auto& current_plan : m_plan) + max_depth = std::max(max_depth, current_plan.depth); + if (max_depth > EPSILON) { + m_wipe_tower_width = align_ceil(std::sqrt(max_depth * m_wipe_tower_width), m_perimeter_width); + for (size_t idx = 0; idx < m_plan.size(); ++idx) + for (auto& toolchange : m_plan[idx].tool_changes) + toolchange = set_toolchange(toolchange.old_tool, toolchange.new_tool, + m_plan[idx].height, toolchange.wipe_volume, + idx == m_first_layer_idx); + plan_tower(); + } + + // Like WipeTower::plan_tower_new(): extend the ribs instead of the tower when the + // tower is smaller than the height-based stability minimum. + const float min_depth = WipeTower::get_limit_depth_by_height(m_wipe_tower_height); + if (m_wipe_tower_depth + EPSILON < min_depth) + m_rib_length = std::max(m_rib_length, min_depth * (float)std::sqrt(2.f)); + } + + const float diagonal = std::sqrt(m_wipe_tower_depth * m_wipe_tower_depth + m_wipe_tower_width * m_wipe_tower_width); + m_rib_length = std::max(m_rib_length, diagonal); m_rib_length += m_extra_rib_length; - m_rib_length = std::max(0.f, m_rib_length); + m_rib_length = std::max(diagonal, m_rib_length); // a negative extra length must not shrink the ribs below the diagonal m_rib_width = std::min(m_rib_width, std::min(m_wipe_tower_depth, m_wipe_tower_width) / 2.f); // Ensure that the rib wall of the wipetower are attached to the infill. + if (m_use_gap_wall) + compute_wall_skip_points(); + m_layer_info = m_plan.begin(); m_current_height = 0.f; @@ -2410,7 +2487,7 @@ void WipeTower2::generate(std::vector> if (m_layer_info->depth < m_wipe_tower_depth - m_perimeter_width) m_y_shift = (m_wipe_tower_depth-m_layer_info->depth-m_perimeter_width)/2.f; - int idx = first_toolchange_to_nonsoluble(layer.tool_changes); + int idx = first_toolchange_to_nonsoluble_nonsupport(layer.tool_changes); WipeTower::ToolChangeResult finish_layer_tcr; if (idx == -1) { @@ -2503,8 +2580,7 @@ Polygon WipeTower2::generate_support_rib_wall(WipeTowerWriter2& double feedrate, bool first_layer, bool rib_wall, - bool extrude_perimeter, - bool skip_points) + bool extrude_perimeter) { float retract_length = m_filpar[m_current_tool].retract_length; @@ -2524,18 +2600,28 @@ Polygon WipeTower2::generate_support_rib_wall(WipeTowerWriter2& if (!extrude_perimeter) return wall_polygon; - if (skip_points) { - result_wall = contrust_gap_for_skip_points(wall_polygon, std::vector(), m_wipe_tower_width, 2.5 * m_perimeter_width, + if (m_use_gap_wall) { + // Cut the wall open at each toolchange's entry (see compute_wall_skip_points()). + // The vector is empty during the save_on_last_wipe planning passes, which therefore + // measure the un-gapped wall — same approximation as the BBL tower. + static const std::vector no_skip_points; + const size_t layer_id = size_t(m_layer_info - m_plan.begin()); + const std::vector& layer_skip_points = + layer_id < m_wall_skip_points.size() ? m_wall_skip_points[layer_id] : no_skip_points; + result_wall = construct_gap_for_skip_points(wall_polygon, layer_skip_points, m_wipe_tower_width, 2.5 * m_perimeter_width, insert_skip_polygon); } else { result_wall.push_back(to_polyline(wall_polygon)); insert_skip_polygon = wall_polygon; } writer.generate_path(result_wall, feedrate, retract_length, retract_speed, m_used_fillet); - //if (m_cur_layer_id == 0) { - // BoundingBox bbox = get_extents(result_wall); - // m_rib_offset = Vec2f(-unscaled(bbox.min.x()), -unscaled(bbox.min.y())); - //} + // Tower-local shift that puts the rib wall's protruding first-layer min corner at the + // configured tower position, like WipeTower::generate_support_wall_new(). Measured on + // the un-gapped outline so a wall gap cannot shift the tower. + if (rib_wall && is_first_layer()) { + BoundingBox bbox = get_extents(insert_skip_polygon); + m_rib_offset = Vec2f(-unscaled(bbox.min.x()), -unscaled(bbox.min.y())); + } return insert_skip_polygon; } diff --git a/src/libslic3r/GCode/WipeTower2.hpp b/src/libslic3r/GCode/WipeTower2.hpp index 7060eefa4a..5b1a474b5d 100644 --- a/src/libslic3r/GCode/WipeTower2.hpp +++ b/src/libslic3r/GCode/WipeTower2.hpp @@ -17,13 +17,20 @@ namespace Slic3r class WipeTowerWriter2; class PrintRegionConfig; +class ConfigBase; class WipeTower2 { public: static const std::string never_skip_tag() { return "_GCODE_WIPE_TOWER_NEVER_SKIP_TAG"; } + // Marks the wait-for-temp-on-wipe-tower M109 so the interface-temp deduplication pass + // in WipeTowerIntegration::append_tcr2 does not strip it. + static const std::string wait_for_temp_tag() { return ";_WAIT_FOR_TEMP_ON_WIPE_TOWER"; } static std::pair get_wipe_tower_cone_base(double width, double height, double depth, double angle_deg); - static std::vector> extract_wipe_volumes(const PrintConfig& config); + static std::vector> extract_wipe_volumes(const ConfigBase& config); + // Estimated total flush volume of a SEMM print with the given number of filaments, + // used to reserve wipe tower space before the tower is generated. + static float estimate_semm_flush_volume(const ConfigBase& config, size_t filaments_cnt); // Construct ToolChangeResult from current state of WipeTower2 and WipeTowerWriter2. @@ -34,6 +41,15 @@ public: bool is_finish, bool is_contact = false) const; + // Whether this print cuts wall openings ("skip points") at the toolchange entries. + // Shared with the entry routing in GCode.cpp so the router and the tower agree. + static bool use_gap_wall(const PrintConfig& config); + + // Whether the blocking toolchange temperature wait moves onto the wipe tower. + // Shared with the defer flag in GCode.cpp append_tcr2 so the deferral and the + // tower's tagged M109 can never disagree. + static bool wait_for_temp_enabled(const PrintConfig& config); + // x -- x coordinates of wipe tower in mm ( left bottom corner ) // y -- y coordinates of wipe tower in mm ( left bottom corner ) // width -- width of wipe tower in mm ( default 60 mm - leave as it is ) @@ -69,9 +85,9 @@ public: const float brim = m_wipe_tower_brim_width_real; return BoundingBoxf(Vec2d(-brim, -brim), Vec2d(double(m_wipe_tower_width) + brim, double(m_wipe_tower_depth) + brim)); } - // WT2 doesn't currently compute a rib-origin compensation like WipeTower (m_rib_offset), - // so expose a zero offset for consistency purposes (to maintain API parity). - Vec2f get_rib_offset() const { return Vec2f::Zero(); } + // Tower-local shift that puts the rib wall's first-layer min corner at the configured + // tower position, like WipeTower::get_rib_offset(). Zero unless the rib wall is used. + Vec2f get_rib_offset() const { return m_rib_offset; } float get_rib_width() const { return m_rib_width; } float get_rib_length() const { return m_rib_length; } @@ -149,6 +165,7 @@ public: struct FilamentParameters { std::string material = "PLA"; bool is_soluble = false; + bool is_support = false; int temperature = 0; int first_layer_temperature = 0; int interface_print_temperature = 0; @@ -220,9 +237,9 @@ private: float m_perimeter_speed = 0.f; float m_first_layer_speed = 0.f; size_t m_first_layer_idx = size_t(-1); - bool m_flat_ironing = false; bool m_enable_tower_interface_features = false; bool m_enable_tower_interface_cooldown_during_tower = false; + bool m_wait_for_temp_on_wipe_tower = false; bool m_prev_layer_had_interface = false; bool m_current_layer_has_interface = false; @@ -231,6 +248,12 @@ private: float m_rib_width = 10; float m_extra_rib_length = 0; float m_rib_length = 0; + Vec2f m_rib_offset = Vec2f::Zero(); + bool m_use_gap_wall = false; + // Per plan layer, each toolchange's entry position (tower-local, un-shifted frame): + // where the wall is cut open so the entry travel does not cross the printed wall. + // Filled by compute_wall_skip_points() once the plan is final. + std::vector> m_wall_skip_points; bool m_enable_arc_fitting = false; @@ -253,6 +276,7 @@ private: } m_bed_shape; float m_bed_width; // width of the bed bounding box Vec2f m_bed_bottom_left; // bottom-left corner coordinates (for rectangular beds) + Polygon m_bed_polygon; // printable_area contour (scaled) float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill. float m_extrusion_flow = 0.038f; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter. @@ -278,6 +302,37 @@ private: bool is_first_layer() const { return size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; } + // Purge row lattice of toolchange_Wipe(): row pitch and extrusion width. + float wipe_row_spacing(bool first_layer) const { return (first_layer ? m_extra_flow : m_extra_spacing_wipe) * m_perimeter_width; } + float wipe_line_width() const { return m_perimeter_width * m_extra_flow; } + + // Whether toolchange_Unload() rams this (old) tool out. + bool tool_ramming_enabled(size_t tool) const { return (m_semm && m_enable_filament_ramming) || m_filpar[tool].multitool_ramming; } + // Whether the wipe restarts at the box boundary on a fresh row below the quantized + // ram band after ramming this (old) tool out (multi-tool gap wall; SEMM keeps the + // stock continue-from-ram-end behavior). + bool boundary_wipe_start_enabled(size_t tool) const { return tool_ramming_enabled(tool) && !m_semm && m_use_gap_wall; } + + // With a boundary wipe start the wipe begins on a fresh row below the quantized ram + // band. Y offset from the box start to that first wipe row. + float wipe_start_offset_after_ram(float ramming_depth, bool first_layer) const + { + return ramming_depth + wipe_row_spacing(first_layer) - (m_perimeter_width + wipe_line_width()) / 2.f; + } + + // Tower-local entry position of a toolchange whose box starts depth_traversed into + // the layer: the box corner, moved down to the first wipe row when the plan gives + // it a boundary wipe start (ramming_depth > 0 iff the unload rams). tool_change() + // enters here and compute_wall_skip_points() cuts the wall gap here, so the routed + // entry, the gap and the wipe scrub all share one opening. + Vec2f toolchange_entry_pos(float depth_traversed, float ramming_depth, bool first_layer) const + { + Vec2f pos(m_perimeter_width / 2.f, m_perimeter_width / 2.f + depth_traversed); + if (!m_semm && m_use_gap_wall && ramming_depth > 0.f) + pos.y() += wipe_start_offset_after_ram(ramming_depth, first_layer); + return pos; + } + // Calculates extrusion flow needed to produce required line width for given layer height float extrusion_flow(float layer_height = -1.f) const // negative layer_height - return current m_extrusion_flow { @@ -328,9 +383,10 @@ private: std::vector m_used_filament_length; std::vector>> m_used_filament_length_until_layer; - // Return index of first toolchange that switches to non-soluble extruder - // ot -1 if there is no such toolchange. - int first_toolchange_to_nonsoluble( + // Return the index of the toolchange whose new filament should print the layer's + // finish extrusions (sparse infill + wall + brim), or -1 to print them with the + // layer's incoming filament before any toolchange happens. + int first_toolchange_to_nonsoluble_nonsupport( const std::vector& tool_changes) const; void toolchange_Unload( @@ -343,7 +399,9 @@ private: void toolchange_Change( WipeTowerWriter2 &writer, const size_t new_tool, - const std::string& new_material); + const std::string& new_material, + const int wait_for_temp, + const bool wait_beside_tower); void toolchange_Load( WipeTowerWriter2 &writer, @@ -353,7 +411,9 @@ private: WipeTowerWriter2 &writer, const WipeTower::box_coordinates &cleaning_box, float wipe_volume, - bool interface_layer); + bool interface_layer, + bool priming = false, + bool fill_box = false); Polygon generate_support_rib_wall(WipeTowerWriter2& writer, @@ -361,8 +421,7 @@ private: double feedrate, bool first_layer, bool rib_wall, - bool extrude_perimeter, - bool skip_points); + bool extrude_perimeter); Polygon generate_support_cone_wall( WipeTowerWriter2& writer, @@ -372,6 +431,12 @@ private: float spacing); Polygon generate_rib_polygon(const WipeTower::box_coordinates& wt_box); + + void compute_wall_skip_points(); + + // Computes the depth reserved for a toolchange (shared by plan_toolchange() and the + // rib-wall square-tower replanning in generate()). + WipeTowerInfo::ToolChange set_toolchange(size_t old_tool, size_t new_tool, float layer_height, float wipe_volume, bool first_layer_plan); }; diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index e3d1c30362..0e80cc1fb7 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -3,6 +3,7 @@ #include "I18N.hpp" #include "PrintConfig.hpp" #include "ClipperUtils.hpp" +#include "Geometry/ArcWelder.hpp" #include "Line.hpp" #include #include @@ -1018,45 +1019,48 @@ std::string GCodeWriter::_spiral_travel_to_z(double z, const Vec2d &ij_offset, c } if (!this->config.enable_arc_fitting) { // Orca: if arc fitting is disabled, approximate the arc with small linear segments - std::ostringstream oss; const double z_start = m_pos(2); // starting Z height - // -------------------------------------------------------------------- - // Determine number of segments based on Resolution - // -------------------------------------------------------------------- - const double ref_resolution = 0.01; // reference resolution in mm - const double ref_segments = 8.0; // reference number of segments at reference resolution - - // number of linear segments to use for approximating the arc, clamp between 4 and 16 - const int segments = std::clamp(int(std::round(ref_segments * (ref_resolution / m_resolution))), 4, 16); - // -------------------------------------------------------------------- - const double px = m_pos(0) - m_x_offset; // take plate offset into consideration const double py = m_pos(1) - m_y_offset; // take plate offset into consideration const double cx = px + ij_offset(0); // center x const double cy = py + ij_offset(1); // center y const double radius = ij_offset.norm(); // radius + + // Number of linear segments approximating the circle, chosen so that a chord never deviates + // from the true arc by more than the slicing resolution. A resolution of 0 means "no + // simplification", which has no finite segment count, so it takes the upper bound. + constexpr size_t min_segments = 8; // keep a small spiral visibly round + constexpr size_t max_segments = 128; // bound the emitted G-code + const int segments = int(m_resolution > 0. ? + std::clamp(Geometry::ArcWelder::arc_discretization_steps(radius, 2. * M_PI, m_resolution), min_segments, max_segments) : + max_segments); + const double a0 = std::atan2(py - cy, px - cx); // start angle - const double delta = 2.0 * M_PI; // CCW full circle - if (full_gcode_comment) - oss << ";" << comment << "\n"; + auto emit_point = [&output](const Vec3d &point) { + GCodeG1Formatter w; + w.emit_xyz(point); + output += w.string(); + }; - oss << "G1 F" << (speed * 60.0) << "\n"; // set feedrate + output.reserve(size_t(segments) * 40); // ~40 characters per emitted G1 line + + GCodeG1Formatter w; // set feedrate + w.emit_f(speed * 60.0); + w.emit_comment(GCodeWriter::full_gcode_comment, comment); + output += w.string(); // approximate the arc with small linear segments (without the last point which is added later to ensure exactness) for (int i = 1; i < segments; ++i) { - double t = double(i) / segments; // parametric position along arc - double a = a0 + delta * t; // CCW arc param - double x = cx + radius * std::cos(a); // point on circle - double y = cy + radius * std::sin(a); // point on circle - double zz = z_start + (z - z_start) * t; // interpolated Z height - - oss << "G1 X" << x << " Y" << y << " Z" << zz << "\n"; + const double t = double(i) / segments; // parametric position along arc + const double a = a0 + 2. * M_PI * t; // CCW arc param, full circle + emit_point(Vec3d(cx + radius * std::cos(a), // point on circle + cy + radius * std::sin(a), + z_start + (z - z_start) * t)); // interpolated Z height } - oss << "G1 X" << px << " Y" << py << " Z" << z << "\n"; // final point to ensure exactness - output = oss.str(); + emit_point(Vec3d(px, py, z)); // final point to ensure exactness } else { // Orca: if arc fitting is enabled emit a G2/G3 command for the spiral lift output = std::string("G17") + (full_gcode_comment ? " ; XY plane for arc\n" : "\n"); diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 614b443131..2f378f5778 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -94,7 +94,7 @@ public: void* volume{nullptr}; std::vector* plane_indices{nullptr}; - Transform3d world_tran; + Transform3d world_tran = Transform3d::Identity(); std::shared_ptr> world_plane_features{nullptr}; std::shared_ptr origin_surface_feature{nullptr}; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 1177a5227d..c689c7ce78 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -3243,9 +3243,9 @@ double Model::findMaxSpeed(const ModelObject* object) { if (objectKey == "outer_wall_speed") externalPerimeterSpeedObj = object->config.get().opt_float_nullable(objectKey, 0); if (objectKey == "small_perimeter_speed") - smallPerimeterSpeedObj = object->config.get().opt_float_nullable(objectKey, 0); + smallPerimeterSpeedObj = object->config.get().opt_float_or_percent_nullable(objectKey, 0).get_abs_value(externalPerimeterSpeedObj); if (objectKey == "small_support_perimeter_speed") - smallSupportPerimeterSpeedObj = object->config.get().opt_float_nullable(objectKey, 0); + smallSupportPerimeterSpeedObj = object->config.get().opt_float_or_percent_nullable(objectKey, 0).get_abs_value(supportSpeedObj); } objMaxSpeed = std::max(perimeterSpeedObj, std::max(externalPerimeterSpeedObj, std::max(infillSpeedObj, std::max(solidInfillSpeedObj, std::max(topSolidInfillSpeedObj, std::max(supportSpeedObj, std::max(smallPerimeterSpeedObj, std::max(smallSupportPerimeterSpeedObj, objMaxSpeed)))))))); if (objMaxSpeed <= 0) objMaxSpeed = 250.; diff --git a/src/libslic3r/Orient.hpp b/src/libslic3r/Orient.hpp index 30dbdd3a20..370f23d4fb 100644 --- a/src/libslic3r/Orient.hpp +++ b/src/libslic3r/Orient.hpp @@ -48,100 +48,50 @@ struct OrientMesh { }; -// params for minimizing support area -struct OrientParamsArea { - float TAR_A = 0.015f; - float TAR_B = 0.177f; - float RELATIVE_F = 20; - float CONTOUR_F = 0.5f; - float BOTTOM_F = 2.5f; - float BOTTOM_HULL_F = 0.1f; - float TAR_C = 0.1f; - float TAR_D = 1; - float TAR_E = 0.0115f; - float FIRST_LAY_H = 0.2f;//0.0475; - float VECTOR_TOL = -0.00083f; - float NEGL_FACE_SIZE = 0.01f; - float ASCENT = -0.5f; - float PLAFOND_ADV = 0.0599f; - float CONTOUR_AMOUNT = 0.0182427f; - float OV_H = 2.574f; - float height_offset = 2.3728f; - float height_log = 0.041375f; - float height_log_k = 1.9325457f; - float LAF_MAX = 0.999f; // cos(1.4\degree) for low angle face 0.9997f - float LAF_MIN = 0.97f; // cos(14\degree) 0.9703f - float TAR_LAF = 0.001f; //0.01f - float TAR_PROJ_AREA = 0.1f; - float BOTTOM_MIN = 0.1f; // min bottom area. If lower than it the object may be unstable - float BOTTOM_MAX = 2000; // max bottom area. If get to it the object is stable enough (further increase bottom area won't do more help) - float height_to_bottom_hull_ratio_MIN = 1; - float BOTTOM_HULL_MAX = 2000;// max bottom hull area - float APPERANCE_FACE_SUPP=3; // penalty of generating supports on appearance face - - float overhang_angle = 60.f; - bool use_low_angle_face = true; - bool min_volume = false; - Eigen::Vector3f fun_dir; - - /// Allow parallel execution. - bool parallel = true; - - /// Progress indicator callback called when an object gets packed. - /// The unsigned argument is the number of items remaining to pack. - std::function progressind = {}; - - /// A predicate returning true if abort is needed. - std::function stopcondition = {}; - - OrientParamsArea() = default; -}; - struct OrientParams { - float TAR_A = 0.01f;//0.128f; - float TAR_B = 0.177f; - float RELATIVE_F= 6.610621027964314f; - float CONTOUR_F = 0.23228623269775997f; - float BOTTOM_F = 1.167152017941474f; - float BOTTOM_HULL_F = 0.1f; - float TAR_C = 0.24308070476924726f; - float TAR_D = 0.6284515508160871f; - float TAR_E = 0;//0.032157292647062234; - float FIRST_LAY_H = 0.2f;//0.029; - float VECTOR_TOL = -0.0011163303070972383f; - float NEGL_FACE_SIZE = 0.1f; - float ASCENT= -0.5f; - float PLAFOND_ADV = 0.04079208948120519f; - float CONTOUR_AMOUNT = 0.0101472219892684f; - float OV_H = 1.0370178217794535f; - float height_offset = 2.7417608343142073f; - float height_log = 0.06442030687034085f; - float height_log_k = 0.3933594673063997f; - float LAF_MAX = 0.999f; // cos(1.4\degree) for low angle face //0.9997f; - float LAF_MIN= 0.9703f; // cos(14\degree) 0.9703f; - float TAR_LAF = 0.01f; //0.1f - float TAR_PROJ_AREA = 0.1f; - float BOTTOM_MIN = 0.1f; // min bottom area. If lower than it the objects may be unstable - float BOTTOM_MAX = 2000; //400 - float height_to_bottom_hull_ratio_MIN = 1; - float BOTTOM_HULL_MAX = 2000;// max bottom hull area to clip //600 - float APPERANCE_FACE_SUPP=3; // penalty of generating supports on appearance face - - float overhang_angle = 60.f; - bool use_low_angle_face = true; - bool min_volume = false; - Eigen::Vector3f fun_dir; + float TAR_A { 0.01f }; // 0.128f; + float TAR_B { 0.177f }; + float RELATIVE_F { 6.610621027964314f }; + float CONTOUR_F { 0.23228623269775997f }; + float BOTTOM_F { 1.167152017941474f }; + float BOTTOM_HULL_F { 0.1f }; + float TAR_C { 0.24308070476924726f }; + float TAR_D { 0.6284515508160871f }; + float TAR_E { 0}; // 0.032157292647062234; + float FIRST_LAY_H { 0.2f}; // 0.029; + float VECTOR_TOL { -0.0011163303070972383f }; + float NEGL_FACE_SIZE { 0.1f }; + float ASCENT { -0.5f }; + float PLAFOND_ADV { 0.04079208948120519f }; + float CONTOUR_AMOUNT { 0.0101472219892684f }; + float OV_H { 1.0370178217794535f }; + float height_offset { 2.7417608343142073f }; + float height_log { 0.06442030687034085f }; + float height_log_k { 0.3933594673063997f }; + float LAF_MAX { 0.999f }; // cos(1.4\degree) for low angle face //0.9997f; + float LAF_MIN { 0.9703f }; // cos(14\degree) 0.9703f; + float TAR_LAF { 0.01f }; // 0.1f + float TAR_PROJ_AREA { 0.1f }; + float BOTTOM_MIN { 0.1f }; // min bottom area. If lower than it the objects may be unstable + float BOTTOM_MAX { 2000 }; // 400 + float height_to_bottom_hull_ratio_MIN { 1 }; + float BOTTOM_HULL_MAX { 2000 }; // max bottom hull area to clip //600 + float APPERANCE_FACE_SUPP { 3 }; // penalty of generating supports on appearance face + float overhang_angle { 60.f }; + bool use_low_angle_face { true }; + bool min_volume { false }; + Eigen::Vector3f fun_dir {}; /// Allow parallel execution. - bool parallel = false; + bool parallel { false }; /// Progress indicator callback called when an object gets packed. /// The unsigned argument is the number of items remaining to pack. - std::function progressind = {}; + std::function progressind {}; /// A predicate returning true if abort is needed. - std::function stopcondition = {}; + std::function stopcondition {}; OrientParams() = default; }; diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 1c785c3184..2d6c993d78 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -360,6 +360,14 @@ static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path& subject, con return clipped_paths; } +static double clipper_z_path_length(const ClipperLib_Z::Path &path) +{ + double len = 0.; + for (size_t i = 1; i < path.size(); ++ i) + len += (Vec2d(double(path[i].x()), double(path[i].y())) - Vec2d(double(path[i - 1].x()), double(path[i - 1].y()))).norm(); + return len; +} + struct PerimeterGeneratorArachneExtrusion { Arachne::ExtrusionLine* extrusion = nullptr; @@ -571,17 +579,156 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p return extrusion_coll; } -// ORCA: only_one_wall_top detects the top as "slice − upper", so a feature rising from the middle of a -// top surface becomes an enclosed hole that gets ringed with extra inner walls. Fill those holes back -// into the top. Only holes that are both covered by the upper layer (excludes bridges) and backed by -// solid material (excludes voids) are filled. -static ExPolygons fill_enclosed_top_feature_holes(const ExPolygons &top, const Polygons &covered_by_upper, const ExPolygons &solid) +// ORCA: only_one_wall_top acts on top surfaces, so without a top shell there is nothing for it to act on: zero top +// shell layers retype the top surfaces as internal, see LayerRegion::prepare_fill_surfaces(). A 0% top surface +// density does leave a top surface - just an unfilled one - so it does not disable the feature. +// ConfigManipulation::toggle_print_fff_options() hides the option under the same condition, so a profile that left +// it enabled does not act behind a hidden checkbox. +static bool has_top_shell_layers(const PrintRegionConfig &config) { - ExPolygons filled = top; - for (ExPolygon &ex : filled) - ex.holes.clear(); - const ExPolygons feature_holes = intersection_ex(intersection_ex(diff_ex(filled, top), covered_by_upper), solid); - return feature_holes.empty() ? top : union_ex(top, feature_holes); + return config.top_shell_layers.value > 0; +} + +// ORCA: only_one_wall_first_layer thins the first layer to a single wall, the bottom counterpart of the above and +// gated the same way: zero bottom shell layers retype the bottom surfaces as internal, so that wall would ring +// sparse infill on the bed. The bottom surface density plays no part - an unfilled bottom surface is still a bottom +// surface, exactly as for the top - and it cannot reach zero anyway, being capped at a 10% minimum. +static bool has_bottom_shell_layers(const PrintRegionConfig &config) +{ + return config.bottom_shell_layers.value > 0; +} + +// ORCA: the inner walls are only given up when a top fill takes their space, and it has to actually reach it - +// a 0% top surface density leaves no fill at all, and without top_surface_expansion the fill never grows over +// them. Either way the original generation is kept (re-onion the not-top region), which is what users of +// only_one_wall_top alone have always got. +static bool top_fill_replaces_inner_walls(const PrintRegionConfig &config) +{ + return has_top_shell_layers(config) && config.top_surface_density.value > 0 && config.top_surface_expansion.value > 0; +} + +// ORCA: only_one_wall_top - cheap per-vertex classification of a wall against the top surface. Only Partial +// needs the geometry clipped or measured; a segment crossing the top with no vertex inside is rare enough to ignore. +enum class TopOverlap { None, Partial, Full }; + +static bool point_over_top(const Point &p, const ExPolygons &top_region, const BoundingBox &top_region_bbox) +{ + if (! top_region_bbox.contains(p)) + return false; + for (const ExPolygon &ex : top_region) + if (ex.contains(p, false)) + return true; + return false; +} + +static TopOverlap classify_over_top(const Points &pts, const ExPolygons &top_region, const BoundingBox &top_region_bbox) +{ + size_t inside = 0; + for (const Point &p : pts) + if (point_over_top(p, top_region, top_region_bbox)) + ++ inside; + return inside == 0 ? TopOverlap::None : inside == pts.size() ? TopOverlap::Full : TopOverlap::Partial; +} + +static TopOverlap classify_over_top(const Arachne::ExtrusionLine &el, const ExPolygons &top_region, const BoundingBox &top_region_bbox) +{ + size_t inside = 0; + for (const Arachne::ExtrusionJunction &j : el.junctions) + if (point_over_top(j.p, top_region, top_region_bbox)) + ++ inside; + return inside == 0 ? TopOverlap::None : inside == el.junctions.size() ? TopOverlap::Full : TopOverlap::Partial; +} + +// ORCA: only_one_wall_top for Arachne - cut out of the already generated inner walls the parts running over the top +// surface, so geometry that continues upward keeps its walls. A wall too short over the top to be worth slitting open +// is left whole, its footprint reported in kept_over_top for the caller to withhold from the top fill. +static void clip_inner_walls_over_top(std::vector &inner_perimeters, const ExPolygons &top_region, coord_t perimeter_width, Polygons &kept_over_top) +{ + const BoundingBox top_region_bbox = get_extents(top_region).inflated(SCALED_EPSILON); + auto covered_by = [](const Arachne::ExtrusionLine &el) { + Polyline centerline; + centerline.points.reserve(el.junctions.size()); + coord_t width = 0; + for (const Arachne::ExtrusionJunction &j : el.junctions) { + centerline.points.emplace_back(j.p); + width = std::max(width, j.w); + } + return offset(centerline, float(width) / 2.f); + }; + // Pull the cut back by half a wall width: the clip severs the centerline, but the bead's rounded end + // extends half a width past its endpoint and would otherwise overlap the top fill. + ClipperLib_Z::Paths top_paths_z; + for (const Polygon &poly : to_polygons(offset_ex(top_region, float(perimeter_width) / 2.f))) { + top_paths_z.emplace_back(); + ClipperLib_Z::Path &out = top_paths_z.back(); + out.reserve(poly.points.size()); + for (const Point &pt : poly.points) + out.emplace_back(pt.x(), pt.y(), 0); + } + for (Arachne::VariableWidthLines &inner_perimeter : inner_perimeters) { + Arachne::VariableWidthLines kept; + kept.reserve(inner_perimeter.size()); + for (Arachne::ExtrusionLine &el : inner_perimeter) { + if (el.empty()) + continue; + const TopOverlap overlap = classify_over_top(el, top_region, top_region_bbox); + if (overlap == TopOverlap::None) { + kept.emplace_back(std::move(el)); + continue; + } + if (overlap == TopOverlap::Full) + continue; // the clip below would return nothing anyway + ClipperLib_Z::Path subject; + subject.reserve(el.size()); + for (const Arachne::ExtrusionJunction &j : el.junctions) + subject.emplace_back(j.p.x(), j.p.y(), j.w); + ClipperLib_Z::Paths pieces = clip_extrusion(subject, top_paths_z, ClipperLib_Z::ctDifference); + + // Clipper treats the subject as an open polyline, so it also cuts a closed loop at its (arbitrary) + // start vertex and may reverse pieces. Stitch pieces sharing an endpoint back together. + auto same_pt = [](const ClipperLib_Z::IntPoint &p, const ClipperLib_Z::IntPoint &q) { + return std::abs(p.x() - q.x()) <= SCALED_EPSILON && std::abs(p.y() - q.y()) <= SCALED_EPSILON; + }; + for (size_t i = 0; i < pieces.size(); ++ i) { + for (size_t j = i + 1; j < pieces.size();) { + ClipperLib_Z::Path &a = pieces[i]; + ClipperLib_Z::Path &b = pieces[j]; + if (same_pt(a.front(), b.front()) || same_pt(a.front(), b.back())) + std::reverse(a.begin(), a.end()); + if (same_pt(a.back(), b.back())) + std::reverse(b.begin(), b.end()); + if (same_pt(a.back(), b.front())) { + a.insert(a.end(), b.begin() + 1, b.end()); + pieces.erase(pieces.begin() + j); + j = i + 1; // the merged path has new endpoints, restart the scan + } else + ++ j; + } + } + + // If the clip removed next to nothing, keep the loop untouched instead of slitting it open. The + // half-width pull-back above already costs about one width per crossing, hence two widths. + double kept_length = 0.; + for (const ClipperLib_Z::Path &path : pieces) + kept_length += clipper_z_path_length(path); + if (clipper_z_path_length(subject) - kept_length < 2. * double(perimeter_width)) { + append(kept_over_top, covered_by(el)); + kept.emplace_back(std::move(el)); + continue; + } + + for (const ClipperLib_Z::Path &path : pieces) { + Arachne::ExtrusionLine clipped(el.inset_idx, el.is_odd); + clipped.junctions.reserve(path.size()); + for (const ClipperLib_Z::IntPoint &pt : path) + clipped.junctions.emplace_back(Point(pt.x(), pt.y()), coord_t(pt.z()), el.inset_idx); + // Discard tiny leftovers that would print as zits. + if (clipped.size() >= 2 && clipped.getLength() >= perimeter_width) + kept.emplace_back(std::move(clipped)); + } + } + inner_perimeter = std::move(kept); + } } void PerimeterGenerator::split_top_surfaces(const ExPolygons &orig_polygons, ExPolygons &top_fills, @@ -649,7 +796,6 @@ void PerimeterGenerator::split_top_surfaces(const ExPolygons &orig_polygons, ExP ExPolygons delete_bridge = diff_ex(orig_polygons, bridge_checker, ApplySafetyOffset::Yes); ExPolygons top_polygons = diff_ex(delete_bridge, upper_polygons_series_clipped, ApplySafetyOffset::Yes); - top_polygons = fill_enclosed_top_feature_holes(top_polygons, upper_polygons_series_clipped, orig_polygons); // get the not-top surface, from the "real top" but enlarged by external_infill_margin (and the // min_width_top_surface we removed a bit before) @@ -1234,6 +1380,11 @@ void PerimeterGenerator::process_classic() for (const Surface &surface : all_surfaces) surface_exp.push_back(surface.expolygon); std::vector surface_order = chain_expolygons(surface_exp); + // ORCA: neither one-wall option has a surface to act on without the shell behind it, see + // has_top_shell_layers() / has_bottom_shell_layers(). Gated here so every use below - including the + // topmost and first layers - sees the same answer. + const bool only_one_wall_top = this->config->only_one_wall_top && has_top_shell_layers(*this->config); + const bool only_one_wall_first_layer = this->config->only_one_wall_first_layer && has_bottom_shell_layers(*this->config); for (size_t order_idx = 0; order_idx < surface_order.size(); order_idx++) { const Surface &surface = all_surfaces[surface_order[order_idx]]; // detect how many perimeters must be generated for this island @@ -1241,16 +1392,23 @@ void PerimeterGenerator::process_classic() int sparse_infill_density = this->config->sparse_infill_density.value; if (this->config->alternate_extra_wall && this->layer_id % 2 == 1 && !m_spiral_vase && sparse_infill_density > 0) // add alternating extra wall loop_number++; - if (this->layer_id == object_config->raft_layers && this->config->only_one_wall_first_layer) + if (this->layer_id == object_config->raft_layers && only_one_wall_first_layer) loop_number = 0; // Set the topmost layer to be one wall - if (loop_number > 0 && config->only_one_wall_top && this->upper_slices == nullptr) + if (loop_number > 0 && only_one_wall_top && this->upper_slices == nullptr) loop_number = 0; ExPolygons last = union_ex(surface.expolygon.simplify_p(surface_simplify_resolution)); ExPolygons gaps; ExPolygons top_fills; ExPolygons fill_clip; + // ORCA: only_one_wall_top, all empty unless this island has a top surface on this layer. See the + // post-onion reduction below: the region to keep clear of inner walls, the space freed by the dropped + // walls (goes to infill, not left as a void) and the space held by the kept ones (withheld from the fill). + ExPolygons one_wall_top_region; + ExPolygons one_wall_top_reclaimed; + Polygons one_wall_top_kept_bands; + bool apply_one_wall_top = false; if (loop_number >= 0) { // In case no perimeters are to be generated, loop_number will equal to -1. std::vector contours(loop_number+1); // depth => loops @@ -1389,8 +1547,19 @@ void PerimeterGenerator::process_classic() //BBS: refer to superslicer //store surface for top infill if only_one_wall_top - if (i == 0 && i!=loop_number && config->only_one_wall_top && !surface.is_bridge() && this->upper_slices != NULL) { - this->split_top_surfaces(last, top_fills, last, fill_clip); + if (i == 0 && i!=loop_number && only_one_wall_top && !surface.is_bridge() && this->upper_slices != NULL) { + if (top_fill_replaces_inner_walls(*this->config)) { + // ORCA: take the top fill and the keep-out region but leave `last` as the real geometry, + // so the onion follows it and the walls over the top are reduced in one step below. + ExPolygons non_top_polygons; + this->split_top_surfaces(last, top_fills, non_top_polygons, fill_clip); + apply_one_wall_top = !top_fills.empty(); + if (apply_one_wall_top) + one_wall_top_region = diff_ex(last, non_top_polygons); + } else { + // Onion the not-top region only, so the remaining walls stop at the top boundary. + this->split_top_surfaces(last, top_fills, last, fill_clip); + } } if (i == loop_number && (! has_gap_fill || this->config->sparse_infill_density.value == 0)) { @@ -1400,6 +1569,46 @@ void PerimeterGenerator::process_classic() } } + // ORCA: only_one_wall_top reduction - drop the inner walls (depth > 0) running over the top surface and + // take that space back from the gaps, leaving the top with the outer wall and the top infill. Classic + // perimeters are closed loops, so a wall can only be kept or dropped whole; one that merely grazes the + // top (same tolerance as the Arachne clip) is kept and withheld from the top fill instead. + if (apply_one_wall_top) { + const BoundingBox top_region_bbox = get_extents(one_wall_top_region).inflated(SCALED_EPSILON); + const double grazing_tolerance = 2. * double(perimeter_width); + // The band a wall covers, taken around its centerline so the orientation of holes does not matter. + auto wall_band = [perimeter_spacing](const Polygon &poly) { + Polygon centerline = poly; + centerline.make_counter_clockwise(); + return diff(offset(centerline, float(perimeter_spacing) / 2.f), + offset(centerline, -float(perimeter_spacing) / 2.f)); + }; + Polygons dropped_wall_bands; + auto reduce_over_top = [&](PerimeterGeneratorLoops &loops) { + loops.erase(std::remove_if(loops.begin(), loops.end(), [&](const PerimeterGeneratorLoop &loop) { + const TopOverlap overlap = classify_over_top(loop.polygon.points, one_wall_top_region, top_region_bbox); + if (overlap == TopOverlap::None) + return false; + // Only a wall straddling the boundary is worth measuring; a wall wholly over the top goes. + if (overlap == TopOverlap::Partial && + total_length(intersection_pl(Polylines{ loop.polygon.split_at_first_point() }, one_wall_top_region)) < grazing_tolerance) { + append(one_wall_top_kept_bands, wall_band(loop.polygon)); + return false; + } + append(dropped_wall_bands, wall_band(loop.polygon)); + return true; + }), loops.end()); + }; + for (int d = 1; d <= loop_number; ++ d) { + reduce_over_top(contours[d]); + reduce_over_top(holes[d]); + } + if (! gaps.empty()) + gaps = diff_ex(gaps, one_wall_top_region); + if (! dropped_wall_bands.empty()) + one_wall_top_reclaimed = diff_ex(dropped_wall_bands, one_wall_top_region); + } + // nest loops: holes first for (int d = 0; d <= loop_number; ++ d) { PerimeterGeneratorLoops &holes_d = holes[d]; @@ -1634,7 +1843,10 @@ void PerimeterGenerator::process_classic() and use zigzag). */ //FIXME Vojtech: This grows by a rounded extrusion width, not by line spacing, // therefore it may cover the area, but no the volume. - last = diff_ex(last, gap_fill.polygons_covered_by_width(10.f)); + Polygons gap_fill_covered = gap_fill.polygons_covered_by_width(10.f); + last = diff_ex(last, gap_fill_covered); + if (! one_wall_top_reclaimed.empty()) + one_wall_top_reclaimed = diff_ex(one_wall_top_reclaimed, gap_fill_covered); this->gap_fill->append(std::move(gap_fill.entities)); } @@ -1679,9 +1891,15 @@ void PerimeterGenerator::process_classic() // append infill areas to fill_surfaces //if any top_fills, grow them by ext_perimeter_spacing/2 to have the real un-anchored fill ExPolygons top_infill_exp = intersection_ex(fill_clip, offset_ex(top_fills, double(ext_perimeter_spacing / 2))); + // ORCA: only_one_wall_top - route the top fill around the walls kept despite grazing the top. + if (!one_wall_top_kept_bands.empty()) + top_infill_exp = diff_ex(top_infill_exp, one_wall_top_kept_bands); if (!top_fills.empty()) { infill_exp = union_ex(infill_exp, offset_ex(top_infill_exp, double(top_infill_peri_overlap))); } + // ORCA: only_one_wall_top - what the top fill does not cover of the dropped walls goes to infill. + if (!one_wall_top_reclaimed.empty()) + infill_exp = union_ex(infill_exp, one_wall_top_reclaimed); this->fill_surfaces->append(infill_exp, stInternal); apply_extra_perimeters(infill_exp); @@ -1700,6 +1918,8 @@ void PerimeterGenerator::process_classic() double(-inset - infill_peri_overlap)); if (!top_fills.empty()) polyWithoutOverlap = union_ex(polyWithoutOverlap, top_infill_exp); + if (!one_wall_top_reclaimed.empty()) + polyWithoutOverlap = union_ex(polyWithoutOverlap, one_wall_top_reclaimed); this->fill_no_overlap->insert(this->fill_no_overlap->end(), polyWithoutOverlap.begin(), polyWithoutOverlap.end()); } @@ -1757,7 +1977,7 @@ void PerimeterGenerator::process_no_bridge(Surfaces& all_surfaces, coord_t perim ExPolygons unsupported = diff_ex(last, *this->lower_slices, ApplySafetyOffset::Yes); if (!unsupported.empty()) { //remove small overhangs - ExPolygons unsupported_filtered = offset2_ex(unsupported, double(-perimeter_spacing), double(perimeter_spacing)); + ExPolygons unsupported_filtered = opening_ex(unsupported, perimeter_spacing); if (!unsupported_filtered.empty()) { //to_draw.insert(to_draw.end(), last.begin(), last.end()); @@ -1870,35 +2090,40 @@ void PerimeterGenerator::process_no_bridge(Surfaces& all_surfaces, coord_t perim //TODO: add other polys as holes inside this one (-margin) } else { // if(this->config->counterbore_hole_bridging.value == chbBridges) // Orca: Partial counterbore bridging is mask-based. Preserve the supported - // remainder (`last`) and use simplified BridgeDetector coverage to derive the + // remainder and use simplified BridgeDetector coverage to derive the // bridgeable counterbore span. The span is grown from supported material, - // shrunk back, stripped from `last`, and expanded back. It is then prevented - // from intruding deeper into `last` than the explicit anchor overlap. - // Finally, add the allowed anchor band from `last` then remove the + // shrunk back, stripped from the remaining normal surface, and expanded back. + // It is then prevented from intruding deeper into it than the explicit anchor overlap. + // Finally, add the allowed anchor band from it then remove the // narrow hole-side wall contact, which must remain unbridgeable. - last = diff_ex(last, unsupported_filtered, ApplySafetyOffset::Yes); + const ExPolygons remaining = diff_ex(last, unsupported_filtered, ApplySafetyOffset::Yes); ExPolygons bridgeable_filtered; + for (ExPolygon& poly : bridgeable) { poly.simplify(perimeter_spacing, &bridgeable_filtered); } bridgeable_filtered = opening_ex(bridgeable_filtered, ext_perimeter_width); // Get rid of coarseness of the resulted bridgeable area by using the original supported area as reference. - // This is to avoid keeping tiny bridgeable areas that are far from the supported area, or protrude into it. - bridgeable_filtered = union_ex(offset_ex(last, perimeter_spacing), bridgeable_filtered); + // This is to avoid keeping tiny bridgeable areas that are far from the supported area, or protrude into it. + bridgeable_filtered = union_ex(offset_ex(remaining, perimeter_spacing), bridgeable_filtered); bridgeable_filtered = offset_ex(bridgeable_filtered, -perimeter_spacing); - bridgeable_filtered = diff_ex(bridgeable_filtered, last, ApplySafetyOffset::Yes); + bridgeable_filtered = diff_ex(bridgeable_filtered, remaining, ApplySafetyOffset::Yes); bridgeable_filtered = opening_ex(bridgeable_filtered, perimeter_spacing); // filter noise from the diff_ex bridgeable_filtered = offset_ex(bridgeable_filtered, perimeter_spacing); // restore the size to the original bridgeable area // Safety measure: Keep the bridge mask from intruding deeper into the - // supported anchor region (`last`) than the explicit anchor overlap. - bridgeable_filtered = diff_ex(bridgeable_filtered, offset_ex(last, -bridge_anchor_offset)); + // supported anchor region than the explicit anchor overlap. + bridgeable_filtered = diff_ex(bridgeable_filtered, offset_ex(remaining, -bridge_anchor_offset)); - ExPolygons bridge_anchor_areas = intersection_ex(last, offset_ex(unsupported_filtered, bridge_anchor_offset)); + ExPolygons bridge_anchor_areas = intersection_ex(remaining, offset_ex(unsupported_filtered, bridge_anchor_offset)); unsupported_filtered = union_ex(bridgeable_filtered, bridge_anchor_areas); // add bridge anchor unsupported_filtered = opening_ex(unsupported_filtered, bridge_anchor_offset); // remove anchor area from hole-side walls, it must remain unbridgeable + + // update 'last' only if we have a valid bridgeable area, otherwise we will lose the original unsupported area + if (!unsupported_filtered.empty()) + last = remaining; // TODO: Fix the case with thin outer walls around the bridge (1~2 walls) where classic wall // might generate two walls in a tiny space or non at all if "Detect thin walls" is not activated } @@ -2138,6 +2363,11 @@ void PerimeterGenerator::process_arachne() process_no_bridge(all_surfaces, perimeter_spacing, ext_perimeter_width); // BBS: don't simplify too much which influence arc fitting when export gcode if arc_fitting is enabled double surface_simplify_resolution = (print_config->enable_arc_fitting && !this->has_fuzzy_skin) ? 0.2 * m_scaled_resolution : m_scaled_resolution; + // ORCA: neither one-wall option has a surface to act on without the shell behind it, see + // has_top_shell_layers() / has_bottom_shell_layers(). Gated here so every use below - including the + // topmost and first layers - sees the same answer. + const bool only_one_wall_top = this->config->only_one_wall_top && has_top_shell_layers(*this->config); + const bool only_one_wall_first_layer = this->config->only_one_wall_first_layer && has_bottom_shell_layers(*this->config); // we need to process each island separately because we might have different // extra perimeters for each one for (const Surface& surface : all_surfaces) { @@ -2150,12 +2380,12 @@ void PerimeterGenerator::process_arachne() // Set the bottommost layer to be one wall const bool is_bottom_layer = (this->layer_id == object_config->raft_layers) ? true : false; - if (is_bottom_layer && this->config->only_one_wall_first_layer) + if (is_bottom_layer && only_one_wall_first_layer) loop_number = 0; // Orca: set the topmost layer to be one wall according to the config const bool is_topmost_layer = (this->upper_slices == nullptr) ? true : false; - if (is_topmost_layer && loop_number > 0 && config->only_one_wall_top) + if (is_topmost_layer && loop_number > 0 && only_one_wall_top) loop_number = 0; auto apply_precise_outer_wall = config->precise_outer_wall && config->wall_sequence == WallSequence::InnerOuter; @@ -2175,10 +2405,10 @@ void PerimeterGenerator::process_arachne() //PS: One wall top surface for Arachne ExPolygons top_expolygons; // Calculate how many inner loops remain when TopSurfaces is selected. - const int inner_loop_number = (config->only_one_wall_top && upper_slices != nullptr) ? loop_number - 1 : -1; + const int inner_loop_number = (only_one_wall_top && upper_slices != nullptr) ? loop_number - 1 : -1; // Set one perimeter when TopSurfaces is selected. - if (config->only_one_wall_top && loop_number > 0) + if (only_one_wall_top && loop_number > 0) loop_number = 0; Arachne::WallToolPathsParams input_params_tmp = input_params; @@ -2209,7 +2439,6 @@ void PerimeterGenerator::process_arachne() upper_slices_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*upper_slices, infill_contour_bbox); top_expolygons = diff_ex(infill_contour, upper_slices_clipped); - top_expolygons = fill_enclosed_top_feature_holes(top_expolygons, upper_slices_clipped, infill_contour); if (!top_expolygons.empty()) { if (lower_slices != nullptr) { @@ -2230,25 +2459,33 @@ void PerimeterGenerator::process_arachne() // due to thin lines being generated top_expolygons = offset2_ex(top_expolygons, -top_surface_min_width, top_surface_min_width + float(perimeter_width * 0.85)); - // Get the not-top ExPolygons (including bridges) from current slices and expanded real top ExPolygons (without bridges). - const ExPolygons not_top_expolygons = diff_ex(infill_contour, top_expolygons); - - // Get final top ExPolygons. + // Get final top ExPolygons (bridges were excluded above, so they stay walled). top_expolygons = intersection_ex(top_expolygons, infill_contour); - const Polygons not_top_polygons = to_polygons(offset_ex(not_top_expolygons,wall_0_inset)); - Arachne::WallToolPaths inner_wall_tool_paths(not_top_polygons, perimeter_spacing, perimeter_spacing, coord_t(inner_loop_number + 1), 0, layer_height, input_params_tmp); + // ORCA: onion the real region (inside the outer wall) so the remaining walls follow the actual + // geometry, then cut away the parts over the top surface. Re-onioning the non-top complement + // instead - the fallback when there is no top fill - walls the top/non-top interface and rings + // top-surface islands with inner walls that don't exist when the feature is disabled. + const bool clip_walls_over_top = top_fill_replaces_inner_walls(*this->config); + const Polygons inner_region = to_polygons(offset_ex(clip_walls_over_top ? infill_contour + : diff_ex(infill_contour, top_expolygons), + wall_0_inset)); + Arachne::WallToolPaths inner_wall_tool_paths(inner_region, perimeter_spacing, perimeter_spacing, coord_t(inner_loop_number + 1), 0, layer_height, input_params_tmp); std::vector inner_perimeters = inner_wall_tool_paths.getToolPaths(); - // Recalculate indexes of inner perimeters before merging them. - if (!perimeters.empty()) { - for (Arachne::VariableWidthLines &inner_perimeter : inner_perimeters) { - if (inner_perimeter.empty()) - continue; + if (clip_walls_over_top) { + Polygons kept_over_top; + clip_inner_walls_over_top(inner_perimeters, top_expolygons, perimeter_width, kept_over_top); + // Route the top fill around the walls kept despite grazing the top. + if (! kept_over_top.empty()) + top_expolygons = diff_ex(top_expolygons, kept_over_top); + } + + // Recalculate indexes of inner perimeters before merging them: they come after the single outer wall. + if (!perimeters.empty()) + for (Arachne::VariableWidthLines &inner_perimeter : inner_perimeters) for (Arachne::ExtrusionLine &el : inner_perimeter) ++el.inset_idx; - } - } perimeters.insert(perimeters.end(), inner_perimeters.begin(), inner_perimeters.end()); infill_contour = union_ex(top_expolygons, inner_wall_tool_paths.getInnerContour()); diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index e3a4037590..3e29e0c172 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -1791,6 +1791,8 @@ namespace client // from UTF8 to UTF16 don't bail out. msg += boost::nowide::narrow(boost::nowide::widen(error_line)); msg += '\n'; + // The error dialog (MsgDialog.cpp) renders this excerpt monospaced. It recognizes a source + // line directly above a caret line of spaces and a single '^'. for (size_t i = 0; i < error_pos; ++ i) msg += ' '; msg += "^\n"; diff --git a/src/libslic3r/Polyline.hpp b/src/libslic3r/Polyline.hpp index 88671391db..f52c3c9bbd 100644 --- a/src/libslic3r/Polyline.hpp +++ b/src/libslic3r/Polyline.hpp @@ -129,13 +129,13 @@ public: std::vector fitting_result; //BBS: simplify points by arc fitting void simplify_by_fitting_arc(double tolerance); - //BBS: + void reset_to_linear_move(); + //BBS: Polylines equally_spaced_lines(double distance) const; private: void append_fitting_result_after_append_points(); void append_fitting_result_after_append_polyline(const Polyline& src); - void reset_to_linear_move(); bool split_fitting_result_before_index(const size_t index, Point &new_endpoint, std::vector& data) const; bool split_fitting_result_after_index(const size_t index, Point &new_startpoint, std::vector& data) const; }; diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 775c31b563..9ae8b86fd8 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1037,6 +1037,7 @@ static std::vector s_Preset_print_options{ "fill_multiline", "gyroid_optimized", "sparse_infill_pattern", + "sparse_infill_smooth_factor", "lateral_lattice_angle_1", "lateral_lattice_angle_2", "infill_overhang_angle", @@ -1090,7 +1091,7 @@ static std::vector s_Preset_print_options{ "top_surface_speed", "support_speed", "support_object_xy_distance", "support_object_first_layer_gap", "support_interface_speed", "bridge_speed", "internal_bridge_speed", "gap_infill_speed", "travel_speed", "travel_speed_z", "initial_layer_speed", "outer_wall_acceleration", "initial_layer_acceleration", "top_surface_acceleration", "default_acceleration", "skirt_type", "skirt_loops", "skirt_speed","min_skirt_length", "skirt_distance", "skirt_start_angle", "skirt_height","single_loop_draft_shield", "draft_shield", - "brim_width", "brim_object_gap", "brim_flow_ratio", "brim_use_efc_outline", "combine_brims", "brim_type", "brim_ears_max_angle", "brim_ears_detection_length", "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap","enforce_support_layers", + "brim_width", "brim_object_gap", "brim_flow_ratio", "brim_use_efc_outline", "combine_brims", "brim_type", "brim_ears_max_angle", "brim_ears_detection_length", "brim_ears_outer_only", "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap","enforce_support_layers", "raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion", "support_base_pattern", "support_base_pattern_spacing", "support_expansion", "support_style", // BBS @@ -1350,6 +1351,8 @@ static std::vector s_Preset_filament_options {/*"filament_colour", "filament_retraction_length", "filament_retraction_minimum_travel", "filament_retraction_speed", + "filament_retract_length_toolchange", + "filament_retract_restart_extra_toolchange", "filament_wipe", "filament_z_hop", "filament_z_hop_types", @@ -1403,7 +1406,7 @@ static std::vector s_Preset_machine_limits_options { static std::vector s_Preset_printer_options { "printer_technology", "printable_area", "extruder_printable_area", "support_parallel_printheads", "parallel_printheads_count", "parallel_printheads_bed_exclude_areas", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "gcode_flavor", - "fan_kickstart", "part_cooling_fan_min_pwm", "fan_speedup_time", "fan_speedup_overhangs", + "gcode_skip_config_block", "fan_kickstart", "part_cooling_fan_min_pwm", "fan_speedup_time", "fan_speedup_overhangs", "single_extruder_multi_material", "manual_filament_change", "file_start_gcode", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "printing_by_object_gcode", "layer_change_gcode", "time_lapse_gcode", "wrapping_detection_gcode", "change_filament_gcode", "change_extrusion_role_gcode", "printer_model", "printer_variant", "printer_extruder_id", "printer_extruder_variant", "extruder_variant_list", "default_nozzle_volume_type", "printable_height", "extruder_printable_height", "extruder_clearance_radius", "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod", @@ -1420,7 +1423,7 @@ static std::vector s_Preset_printer_options { "use_relative_e_distances", "extruder_type", "use_firmware_retraction", "printer_notes", "grab_length", "support_object_skip_flush", "physical_extruder_map", "cooling_tube_retraction", - "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "wipe_tower_type", "purge_in_prime_tower", "enable_filament_ramming", "tool_change_on_wipe_tower", + "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "wipe_tower_type", "purge_in_prime_tower", "enable_filament_ramming", "tool_change_on_wipe_tower", "wait_for_temp_on_wipe_tower", "z_offset", "disable_m73", "preferred_orientation", "emit_machine_limits_to_gcode", "pellet_modded_printer", "support_multi_bed_types", "use_3mf", "default_bed_type", "bed_mesh_min","bed_mesh_max","bed_mesh_probe_distance", "adaptive_bed_mesh_margin", "enable_long_retraction_when_cut","long_retractions_when_cut","retraction_distances_when_cut", "bed_temperature_formula", "nozzle_flush_dataset", @@ -3783,12 +3786,14 @@ void PresetCollection::update_library_profile_excluded_from() } // Check all presets that has the same alias as the filament presets with empty compatible_printers in Orca Filament Library. + // A printer specific profile supersedes the generic one, no matter whether it lives in a vendor bundle or in the + // library itself. for (const Preset& preset : m_presets) { - if (preset.vendor == nullptr || preset.vendor->name == PresetBundle::ORCA_FILAMENT_LIBRARY) + if (preset.vendor == nullptr) continue; const auto* compatible_printers = dynamic_cast(preset.config.option("compatible_printers")); - // All profiles in concrete vendor profile shouldn't have empty compatible_printers, but here we check it for safety. + // Profiles with empty compatible_printers are the generic ones, they never supersede anything. if (compatible_printers == nullptr || compatible_printers->values.empty()) continue; auto itr = excluded_froms.find(preset.alias); diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index 01cbc43bc2..5557d36891 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -5378,7 +5378,7 @@ void PresetBundle::update_multi_material_filament_presets(size_t to_delete_filam f_multiplier.resize(nozzle_nums, 1.f); } - if ( (num_filaments * num_filaments) != size_t(old_matrix.size() / old_nozzle_nums) ) { + if (old_matrix.size() != num_filaments * num_filaments * nozzle_nums) { // First verify if purging volumes presets for each extruder matches number of extruders std::vector& filaments = this->project_config.option("flush_volumes_vector")->values; while (filaments.size() < 2* num_filaments) { diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 334bda84e9..1af28255ee 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -282,6 +282,14 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "wipe_tower_x" || opt_key == "wipe_tower_y" || opt_key == "wipe_tower_rotation_angle") { + // The tower gcode itself is position-independent (position and rotation are applied + // at export), except that the wait_for_temp_on_wipe_tower park bakes a bed-relative + // side choice into it (WipeTower2::toolchange_Change) — regenerate it when the tower + // moves. Gating on the old config is safe: both inputs of wait_for_temp_enabled + // invalidate psWipeTower themselves when they are part of the same diff. + if ((opt_key == "wipe_tower_x" || opt_key == "wipe_tower_y" || opt_key == "wipe_tower_rotation_angle") + && WipeTower2::wait_for_temp_enabled(m_config)) + steps.emplace_back(psWipeTower); steps.emplace_back(psSkirtBrim); } else if ( opt_key == "slicing_pipeline_plugin" @@ -382,6 +390,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "wiping_volumes_extruders" || opt_key == "enable_filament_ramming" || opt_key == "tool_change_on_wipe_tower" + || opt_key == "wait_for_temp_on_wipe_tower" || opt_key == "purge_in_prime_tower" || opt_key == "z_offset" || opt_key == "support_multi_bed_types" @@ -1039,13 +1048,14 @@ static StringObjectException layered_print_cleareance_valid(const Print &print, wipe_tower_convex_hull.points.emplace_back(scale_(x + width), scale_(y)); wipe_tower_convex_hull.points.emplace_back(scale_(x + width), scale_(y + depth)); wipe_tower_convex_hull.points.emplace_back(scale_(x), scale_(y + depth)); - wipe_tower_convex_hull.rotate(a); + wipe_tower_convex_hull.rotate(Geometry::deg2rad(a), Point(scale_(x), scale_(y))); convex_hulls_temp.push_back(wipe_tower_convex_hull); } else { //here, wipe_tower_polygon is not always convex. Polygon wipe_tower_polygon; if (print.wipe_tower_data().wipe_tower_mesh_data) wipe_tower_polygon = print.wipe_tower_data().wipe_tower_mesh_data->bottom; + wipe_tower_polygon.rotate(Geometry::deg2rad(a)); wipe_tower_polygon.translate(Point(scale_(x), scale_(y))); convex_hulls_temp.push_back(wipe_tower_polygon); } @@ -1064,6 +1074,22 @@ static StringObjectException layered_print_cleareance_valid(const Print &print, if (print_config.enable_wrapping_detection.value && !intersection({wrapping_poly}, convex_hulls_temp).empty()) { return {L("Prime Tower") + L(" is too close to clumping detection area, and collisions will be caused.\n")}; } + // Skip the containment check for towers that will never be printed (single-filament + // prints without smooth timelapse keep the config's tower position but emit nothing). + // Pre-generation only the body square is tested — the auto-brim estimate can overshoot + // the generated brim by several mm and must not hard-fail a print that physically fits. + // Post-generation the mesh bottom already includes the real brim, so the exact + // footprint is tested. + if (filaments_count > 1 || print.enable_timelapse_print()) { + // The shared printable polygon is plate-local, while the tower polygons above are + // already shifted by the plate origin. + Polygons printable_polys = print.get_extruder_shared_printable_polygon(); + const Point plate_shift(scale_(plate_origin.x()), scale_(plate_origin.y())); + for (Polygon &p : printable_polys) + p.translate(plate_shift); + if (!diff(convex_hulls_temp, printable_polys).empty()) + return {L("Prime Tower") + L(" is partially outside the printable area, and it cannot be printed.\n")}; + } return {}; } @@ -3409,7 +3435,11 @@ void Print::update_filament_maps_to_config(std::vector f_maps, std::vector< } else if ((extruder_volume_type_count > extruder_count) && (m_config.filament_volume_map.values.size() > index)) nozzle_volume_type = (NozzleVolumeType)(m_config.filament_volume_map.values[index]); - m_config.filament_map_2.values[index] = m_ori_full_print_config.get_index_for_extruder(f_maps[index], "print_extruder_id", extruder_type, nozzle_volume_type, "print_extruder_variant"); + // Orca: when the process variant columns cannot be matched (degenerate + // print_extruder_id), key the override by plain extruder index like the seeding + // above instead of poisoning the map with -1. + int slot_index = m_ori_full_print_config.get_index_for_extruder(f_maps[index], "print_extruder_id", extruder_type, nozzle_volume_type, "print_extruder_variant"); + m_config.filament_map_2.values[index] = slot_index >= 0 ? slot_index : f_maps[index] - 1; } m_full_print_config = m_ori_full_print_config; @@ -3914,6 +3944,12 @@ const WipeTowerData &Print::wipe_tower_data(size_t filaments_cnt) const double volume = wipe_volume * filament_depth_count; if (m_config.nozzle_diameter.values.size() == 2) volume += filament_change_volume * (int) (filaments_cnt / 2); + // Sizing should take into account currently set wiping volumes. + // For a long time, the initial preview would just use 900/width per toolchange (15mm on a 60mm wide tower) + // and it worked well enough. Let's try to do slightly better by accounting for the purging volumes. + const bool semm_flush = m_config.purge_in_prime_tower && m_config.single_extruder_multi_material; + if (semm_flush) volume = WipeTower2::estimate_semm_flush_volume(m_config, filaments_cnt); + if (m_config.wipe_tower_wall_type.value == WipeTowerWallType::wtwRib) { double depth = std::sqrt(volume / layer_height * extra_spacing); if (need_wipe_tower || filaments_cnt > 1) { @@ -3925,30 +3961,16 @@ const WipeTowerData &Print::wipe_tower_data(size_t filaments_cnt) const } } else { - double width = m_config.prime_tower_width; - if (m_config.purge_in_prime_tower && m_config.single_extruder_multi_material) { - // Calculating depth should take into account currently set wiping volumes. - // For a long time, the initial preview would just use 900/width per toolchange (15mm on a 60mm wide tower) - // and it worked well enough. Let's try to do slightly better by accounting for the purging volumes. - std::vector> wipe_volumes = WipeTower2::extract_wipe_volumes(m_config); - std::vector max_wipe_volumes; - for (const std::vector &v : wipe_volumes) - max_wipe_volumes.emplace_back(*std::max_element(v.begin(), v.end())); - float maximum = std::accumulate(max_wipe_volumes.begin(), max_wipe_volumes.end(), 0.f); - maximum = maximum * filaments_cnt / max_wipe_volumes.size(); - - // Orca: it's overshooting a bit, so let's reduce it a bit - maximum *= 0.6; - const_cast(this)->m_wipe_tower_data.depth = maximum / (layer_height * width); - } else { - double depth = volume / (layer_height * width) * extra_spacing; - if (need_wipe_tower || m_wipe_tower_data.depth > EPSILON) { + double width = m_config.prime_tower_width; + double depth = volume / (layer_height * width); + // The flush volumes already hold the spacing between wipes. + if (!semm_flush) depth *= extra_spacing; + if (need_wipe_tower || depth > EPSILON) { float min_wipe_tower_depth = WipeTower::get_limit_depth_by_height(max_height); depth = std::max((double) min_wipe_tower_depth, depth); } const_cast(this)->m_wipe_tower_data.depth = depth; - } - const_cast(this)->m_wipe_tower_data.brim_width = m_config.prime_tower_brim_width; + const_cast(this)->m_wipe_tower_data.brim_width = m_config.prime_tower_brim_width; } if (m_config.prime_tower_brim_width < 0) const_cast(this)->m_wipe_tower_data.brim_width = WipeTower::get_auto_brim_by_height(max_height); } @@ -4017,10 +4039,33 @@ void Print::_make_wipe_tower() // in BBL machine, wipe tower is only use to prime extruder. So just use a global wipe volume. WipeTower wipe_tower(m_config, m_plate_index, m_origin, m_wipe_tower_data.tool_ordering.first_extruder(), m_wipe_tower_data.tool_ordering.empty() ? 0.f : m_wipe_tower_data.tool_ordering.back().print_z, m_wipe_tower_data.tool_ordering.all_extruders()); + // Orca: the tower's first-layer flow follows the user's first-layer flow ratio (BBS reads + // its initial_layer_flow_ratio here — STUDIO-14254; first_layer_flow_ratio is Orca's analog, + // default 1.0 in both). Honor the set_other_flow_ratios gate that governs the option + // everywhere else. + wipe_tower.set_first_layer_flow_ratio(m_default_object_config.set_other_flow_ratios + ? float(m_default_region_config.first_layer_flow_ratio) + : 1.f); wipe_tower.set_has_tpu_filament(this->has_tpu_filament()); - wipe_tower.set_filament_map(this->get_filament_maps()); - // Vortek H2C: pass nozzle-level map for carousel rotation detection in tool_change_new() - wipe_tower.set_filament_nozzle_map(this->get_filament_nozzle_maps()); + // Per-layer filament->nozzle grouping. sort_and_build_data() above publishes it on the Print + // for by-layer prints; by-object prints publish only later (psSkirtBrim), so fall back to the + // ToolOrdering's own copy there. set_extruder() below dereferences it, so it must be set first. + auto print_group_result = get_layered_nozzle_group_result(); + const MultiNozzleUtils::LayeredNozzleGroupResult &nozzle_group_result = + print_group_result ? *print_group_result : m_wipe_tower_data.tool_ordering.get_layered_nozzle_group_result(); + wipe_tower.set_nozzle_group_result(nozzle_group_result); + { + // Orca: acceleration options are object-scope (PrintConfig members in BBS), so resolve + // the per-variant columns here; initial_layer_travel_acceleration is FloatOrPercent + // over travel_acceleration and needs the full config to resolve. + std::vector first_layer_travel_accels; + for (size_t i = 0; i < m_config.initial_layer_travel_acceleration.values.size(); ++i) + first_layer_travel_accels.emplace_back(m_full_print_config.get_abs_value_at("initial_layer_travel_acceleration", i)); + wipe_tower.set_accelerations(m_default_object_config.default_acceleration.values, + m_default_object_config.initial_layer_acceleration.values, + m_default_object_config.travel_acceleration.values, + first_layer_travel_accels); + } // Feed the has_filament_switcher device flag (develop-only dynamic key, read defensively from // the full config — no shipping profile sets it) and the shared printable bed used by the PETG // pre-extrusion offset clamp. Both are inert unless has_filament_switcher is set. @@ -4056,27 +4101,19 @@ void Print::_make_wipe_tower() multi_extruder_flush.emplace_back(wipe_volumes); } - // Use NozzleStatusRecorder for per-carousel-slot tracking (BBS pattern). - // The original Orca code tracked per-extruder (2 slots), which collapsed all - // carousel filaments into one slot and caused massive redundant AMS flushing. - auto group_result = get_layered_nozzle_group_result(); + // Per-carousel-slot purge tracking via NozzleStatusRecorder (BBS pattern); the layered + // group result set on the tower above resolves each filament to its nozzle slot per layer. MultiNozzleUtils::NozzleStatusRecorder nozzle_recorder; - // Fallback (group_result == null) per-physical-nozzle tracking, matching the original - // pre-port behavior: remembers the last filament loaded in each physical nozzle slot. - std::vector nozzle_cur_filament_ids(nozzle_nums, (unsigned int) -1); std::vectorfilament_maps = get_filament_maps(); int layer_idx = -1; unsigned int current_filament_id = m_wipe_tower_data.tool_ordering.first_extruder(); // Initialize NozzleStatusRecorder with the first filament's carousel slot - if (group_result) { - auto nozzle = group_result->get_nozzle_for_filament(current_filament_id, layer_idx); + { + auto nozzle = nozzle_group_result.get_nozzle_for_filament(current_filament_id, layer_idx); if (nozzle) nozzle_recorder.set_nozzle_status(nozzle->group_id, current_filament_id, nozzle->extruder_id); - } else { - size_t cur_nozzle_id = filament_maps[current_filament_id] - 1; - nozzle_cur_filament_ids[cur_nozzle_id] = current_filament_id; } for (auto& layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers @@ -4095,8 +4132,8 @@ void Print::_make_wipe_tower() float volume_to_purge = 0; // Per-carousel-slot purge tracking via NozzleStatusRecorder - if (group_result) { - auto nozzle_info = group_result->get_nozzle_for_filament(filament_id, layer_idx); + { + auto nozzle_info = nozzle_group_result.get_nozzle_for_filament(filament_id, layer_idx); if (nozzle_info) { int extruder_id = nozzle_info->extruder_id; int nozzle_id = nozzle_info->group_id; @@ -4115,22 +4152,6 @@ void Print::_make_wipe_tower() } nozzle_recorder.set_nozzle_status(nozzle_id, filament_id, extruder_id); } - } else { - // Fallback: original Orca per-physical-nozzle path (non-carousel printers). - // Flush source is the last filament that occupied THIS nozzle, guarded so the - // first use of a nozzle incurs no flush. - int nozzle_id = filament_maps[filament_id] - 1; - unsigned int pre_filament_id = nozzle_cur_filament_ids[nozzle_id]; - if (pre_filament_id != (unsigned int) -1 && pre_filament_id != filament_id) { - volume_to_purge = multi_extruder_flush[nozzle_id][pre_filament_id][filament_id]; - float flush_multiplier = (m_config.prime_volume_mode == PrimeVolumeMode::pvmFast) - ? m_config.flush_multiplier_fast.get_at(nozzle_id) - : m_config.flush_multiplier.get_at(nozzle_id); - volume_to_purge *= flush_multiplier; - volume_to_purge = layer_tools.wiping_extrusions().mark_wiping_extrusions( - *this, current_filament_id, filament_id, volume_to_purge); - } - nozzle_cur_filament_ids[nozzle_id] = filament_id; } //During the filament change, the extruder will extrude an extra length of grab_length for the corresponding detection, so the purge can reduce this length. @@ -4138,29 +4159,21 @@ void Print::_make_wipe_tower() float grab_purge_volume = m_config.grab_length.get_at(grab_extruder_id) * 2.4; //(diameter/2)^2*PI=2.4 volume_to_purge = std::max(0.f, volume_to_purge - grab_purge_volume); - // Select prime volume per-filament: nozzle change (carousel rotation) uses - // filament_prime_volume_nc, filament change (same nozzle slot) uses filament_prime_volume. + // Prime volume per-filament: the tower now picks extruder-change vs nozzle-change + // (carousel) internally per plan layer, so pass both candidates (BBS pattern). float wipe_volume_ec = filament_id < m_config.filament_prime_volume.values.size() ? m_config.filament_prime_volume.values[filament_id] : (float) m_config.prime_volume; float wipe_volume_nc = filament_id < m_config.filament_prime_volume_nc.values.size() ? m_config.filament_prime_volume_nc.values[filament_id] : (float) m_config.prime_volume; - - float prime_volume = wipe_volume_ec; - if (group_result) { - bool is_nozzle_change = group_result->are_filaments_same_extruder(current_filament_id, filament_id, layer_idx) && - !group_result->are_filaments_same_nozzle(current_filament_id, filament_id, layer_idx); - if (is_nozzle_change) { - prime_volume = wipe_volume_nc; - } - } if (m_config.prime_volume_mode == PrimeVolumeMode::pvmSaving) { - prime_volume = 15.f; + wipe_volume_ec = 15.f; + wipe_volume_nc = 15.f; } wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_filament_id, filament_id, - prime_volume, volume_to_purge); + wipe_volume_ec, wipe_volume_nc, volume_to_purge); current_filament_id = filament_id; } layer_tools.wiping_extrusions().ensure_perimeters_infills_order(*this); @@ -4338,7 +4351,12 @@ void Print::_make_wipe_tower() wipe_tower.get_rib_width(), wipe_tower.get_rib_length(), config().wipe_tower_fillet_wall.value); const Vec3d origin = Vec3d::Zero(); - m_fake_wipe_tower.set_fake_extrusion_data(wipe_tower.position(), wipe_tower.width(), wipe_tower.get_wipe_tower_height(), + // FakeWipeTower::pos is a bed-frame translation applied after rotation + // (getFakeExtrusionPathsFromWipeTower2 rotates about the local origin), so the + // tower-local rib offset must be rotated into the bed frame first. + m_fake_wipe_tower.rib_offset = Eigen::Rotation2Df(Geometry::deg2rad((float)config().wipe_tower_rotation_angle.value)) * + wipe_tower.get_rib_offset(); + m_fake_wipe_tower.set_fake_extrusion_data(wipe_tower.position() + m_fake_wipe_tower.rib_offset, wipe_tower.width(), wipe_tower.get_wipe_tower_height(), config().initial_layer_print_height, m_wipe_tower_data.depth, m_wipe_tower_data.z_and_depth_pairs, m_wipe_tower_data.brim_width, config().wipe_tower_rotation_angle, config().wipe_tower_cone_angle, diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index 0956cfe154..6d5dbb05f5 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -559,9 +559,11 @@ static inline bool model_volume_solid_or_modifier(const ModelVolume &mv) static inline Transform3f trafo_for_bbox(const Transform3d &object_trafo, const Transform3d &volume_trafo) { - Transform3d m = object_trafo * volume_trafo; - m.translation().x() = 0.; - m.translation().y() = 0.; + // Orca: Keep the volume's local XY offset for multipart overlap checks, but remove the object's bed placement. + Transform3d object_trafo_local = object_trafo; + object_trafo_local.translation().x() = 0.; + object_trafo_local.translation().y() = 0.; + Transform3d m = object_trafo_local * volume_trafo; return m.cast(); } @@ -1355,7 +1357,11 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ if ((extruder_volume_type_count > extruder_count) && opt_filament_volume_maps && opt_filament_volume_maps->values.size() == filament_maps.size()) nozzle_volume_type = (NozzleVolumeType)(opt_filament_volume_maps->values[index]); - m_config.filament_map_2.values[index] = new_full_config.get_index_for_extruder(filament_maps[index], "print_extruder_id", extruder_type, nozzle_volume_type, "print_extruder_variant"); + // Orca: when the process variant columns cannot be matched (degenerate + // print_extruder_id), key the override by plain extruder index like the seeding + // above instead of poisoning the map with -1. + int slot_index = new_full_config.get_index_for_extruder(filament_maps[index], "print_extruder_id", extruder_type, nozzle_volume_type, "print_extruder_variant"); + m_config.filament_map_2.values[index] = slot_index >= 0 ? slot_index : filament_maps[index] - 1; } // Do not use the ApplyStatus as we will use the max function when updating apply_status. @@ -1411,6 +1417,16 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ num_extruders_changed = true; } } + else if (! print_diff.empty()) { + // Orca: m_config can diverge from an unchanged full config (e.g. the in-slice retract + // override recompute writing different values than the apply-time computation). The + // invalidation above already fired for print_diff, so repair m_config here as well; + // otherwise the divergence is never corrected and every subsequent apply of the same + // config invalidates the result again, forever. + m_placeholder_parser.apply_config(filament_overrides); + m_config.apply_only(new_full_config, print_diff, true); + m_config.apply(filament_overrides); + } ModelObjectStatusDB model_object_status_db; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 7510fcf17a..f9d895332a 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -72,6 +72,8 @@ const std::vector filament_extruder_override_keys = { "filament_deretraction_speed", "filament_retract_restart_extra", //not in filament_options_with_variant, added on 20250816 "filament_retraction_minimum_travel", + "filament_retract_length_toolchange", + "filament_retract_restart_extra_toolchange", // BBS: floats "filament_wipe_distance", // bools @@ -1937,6 +1939,13 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(1)); + def = this->add("brim_ears_outer_only", coBool); + def->label = L("Brim ears outer only"); + def->category = L("Support"); + def->tooltip = L("Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("compatible_printers", coStrings); def->label = L("Select printers"); def->mode = comAdvanced; @@ -3457,6 +3466,18 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Octagram Spiral")); def->set_default_value(new ConfigOptionEnum(ipCrossHatch)); + def = this->add("sparse_infill_smooth_factor", coPercent); + def->label = L("Sparse infill smooth factor"); + def->category = L("Strength"); + def->tooltip = L("Controls how strongly sparse infill corners are rounded. 0% keeps the original right-angle path, " + "while 100% produces the largest possible curves between adjacent infill lines. " + "Currently applies only to the Hilbert Curve."); + def->sidetext = "%"; + def->min = 0; + def->max = 100; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionPercent(0)); + def = this->add("top_surface_acceleration", coFloats); def->label = L("Top surface"); def->category = L("Speed"); @@ -4240,6 +4261,15 @@ void PrintConfigDef::init_fff_params() def->readonly = false; def->set_default_value(new ConfigOptionEnum(gcfMarlinLegacy)); + def = this->add("gcode_skip_config_block", coBool); + def->label = L("Skip G-code config block"); + def->tooltip = L("Do not write the CONFIG_BLOCK (slicer configuration key/value pairs) into the G-code file. " + "This can help with printers whose firmware crashes when parsing these comment lines " + "(e.g. Anycubic go-klipper). Note: the G-code file will no longer contain slicer settings, " + "so importing it back into OrcaSlicer will not restore the configuration."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("pellet_modded_printer", coBool); def->label = L("Pellet Modded Printer"); def->tooltip = L("Enable this option if your printer uses pellets instead of filaments."); @@ -4273,7 +4303,7 @@ void PrintConfigDef::init_fff_params() "slow down."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(0)); - + //BBS def = this->add("infill_combination", coBool); def->label = L("Infill combination"); @@ -5706,12 +5736,10 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionFloatsNullable{10}); def = this->add("retract_length_toolchange", coFloats); - def->label = L("Length"); - //def->full_label = L("Retraction Length (Toolchange)"); - def->full_label = "Retraction Length (Toolchange)"; - //def->tooltip = L("When retraction is triggered before changing tool, filament is pulled back " - // "by the specified amount (the length is measured on raw filament, before it enters " - // "the extruder)."); + def->label = L("Retraction Length (Toolchange)"); + def->tooltip = L("When retraction is triggered before changing tool, filament is pulled back " + "by the specified amount (the length is measured on raw filament, before it enters " + "the extruder)."); def->sidetext = L("mm"); // millimeters, CIS languages need translation def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloats { 10. }); @@ -5965,7 +5993,7 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionFloats { 0. }); def = this->add("retract_restart_extra_toolchange", coFloats); - def->label = L("Extra length on restart"); + def->label = L("Extra length on restart (Toolchange)"); def->tooltip = L("When the retraction is compensated after changing tool, the extruder will push " "this additional amount of filament."); def->sidetext = L("mm"); // millimeters, CIS languages need translation @@ -6542,6 +6570,17 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(false)); + def = this->add("wait_for_temp_on_wipe_tower", coBool); + def->label = L("Wait for temperature on wipe tower"); + def->tooltip = L("Pick up the new tool without waiting for it to reach printing temperature, travel to the wipe " + "tower, and wait for the temperature there, right before purging. Ooze from the heat-up lands on " + "the tower instead of the model, and the travel overlaps with the heating. " + "Only relevant for multi-extruder (multi-toolhead) printers using a Type 2 wipe tower. " + "The firmware or tool change macro must not wait for the temperature itself. " + "When disabled, the temperature wait is issued right after the tool change command."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("wipe_tower_no_sparse_layers", coBool); def->label = L("No sparse layers (beta)"); @@ -8135,10 +8174,12 @@ void PrintConfigDef::init_extruder_option_keys() "long_retractions_when_cut", "retract_after_wipe", "retract_before_wipe", + "retract_length_toolchange", "retract_lift_above", "retract_lift_below", "retract_lift_enforce", "retract_restart_extra", + "retract_restart_extra_toolchange", "retract_when_changing_layer", "retraction_distances_when_cut", "retraction_length", @@ -9226,6 +9267,8 @@ std::set filament_options_with_variant = { "filament_retract_lift_below", "filament_retract_lift_enforce", "filament_retract_restart_extra", + "filament_retract_length_toolchange", + "filament_retract_restart_extra_toolchange", "filament_retraction_speed", "filament_deretraction_speed", "filament_retraction_minimum_travel", @@ -10383,6 +10426,16 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector &variant_index, int stride) +{ + // A single-value object or region override applies to every nozzle variant. + std::vector indices = variant_index; + if (source.size() == 1 && !source.is_nil(0)) + std::fill(indices.begin(), indices.end(), 0); + target.set_to_index(&source, indices, stride); +} + //used for object/region config //use the smallest of multiple to single @@ -10516,6 +10569,44 @@ int DynamicPrintConfig::get_extruder_nozzle_volume_count(int extruder_count, std return count; } +// Orca: BBL system profiles ship full-width print_extruder_id/print_extruder_variant columns, but +// custom multi-extruder printers only ever get the machine-scope columns synthesized for them (see +// extend_extruder_variant); the process scope keeps the length-1 defaults, both in presets and in +// 3mf project configs. Expanding with that degenerate map makes every per-extruder lookup fail, and +// because both keys are themselves in print_options_with_variant, the expansion then latches a +// full-width-but-wrong [1,1,...] map that also defeats the generated_extruder_id fallback in +// get_index_for_extruder. Synthesize the process columns from the printer's extruder_variant_list +// (same token walk as extend_extruder_variant) before expanding. +static void ensure_process_variant_columns(DynamicPrintConfig &config, const DynamicPrintConfig &printer_config) +{ + auto id_opt = dynamic_cast(config.option("print_extruder_id")); + auto variant_opt = dynamic_cast(config.option("print_extruder_variant")); + auto list_opt = dynamic_cast(printer_config.option("extruder_variant_list")); + if (!id_opt || !variant_opt || !list_opt) + return; + if (id_opt->values.size() != 1 || variant_opt->values.size() != 1) + return; + + std::vector ids; + std::vector variants; + for (int i = 0; i < int(list_opt->values.size()); ++i) { + std::vector tokens; + boost::split(tokens, list_opt->get_at(i), boost::is_any_of(","), boost::token_compress_on); + for (std::string &token : tokens) { + boost::trim(token); + if (token.empty()) + continue; + ids.push_back(i + 1); + variants.push_back(token); + } + } + // A single column is the legitimate single-extruder layout, not a degenerate one. + if (ids.size() <= 1) + return; + id_opt->values = std::move(ids); + variant_opt->values = std::move(variants); +} + std::vector DynamicPrintConfig::update_values_to_printer_extruders(DynamicPrintConfig& printer_config, int extruder_count, int extruder_nozzle_volume_count, std::vector>& nv_types, std::set& key_set, std::string id_name, std::string variant_name, unsigned int stride, unsigned int extruder_id, NozzleVolumeType filament_nvt) { @@ -10557,6 +10648,8 @@ std::vector DynamicPrintConfig::update_values_to_printer_extruders(DynamicP variant_count = 1; } else { + if (id_name == "print_extruder_id") + ensure_process_variant_columns(*this, printer_config); // Orca: emit the slots first, then size variant_count from what was actually // emitted. extruder_nozzle_volume_count only equals the emitted total when every // extruder carries per-type stats; an extruder with an empty stats entry combined @@ -11420,7 +11513,7 @@ void update_static_print_config_from_dynamic(ConfigBase& config, const DynamicPr else { ConfigOptionVectorBase* opt_vec_src = static_cast(opt_src); const ConfigOptionVectorBase* opt_vec_dest = static_cast(opt_dest); - opt_vec_src->set_to_index(opt_vec_dest, variant_index, stride); + set_variant_override(*opt_vec_src, *opt_vec_dest, variant_index, stride); } } } diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 67841c6404..f51c1c6411 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -842,6 +842,9 @@ extern std::set printer_options_with_variant_1; extern std::set printer_options_with_variant_2; extern std::set empty_options; +void set_variant_override(ConfigOptionVectorBase &target, const ConfigOptionVectorBase &source, + const std::vector &variant_index, int stride = 1); + extern std::set filament_dev_options; extern void update_static_print_config_from_dynamic(ConfigBase& config, const DynamicPrintConfig& dest_config, std::vector variant_index, std::set& key_set1, int stride = 1); @@ -1082,6 +1085,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, brim_width)) ((ConfigOptionFloat, brim_ears_detection_length)) ((ConfigOptionFloat, brim_ears_max_angle)) + ((ConfigOptionBool, brim_ears_outer_only)) ((ConfigOptionFloat, skirt_start_angle)) ((ConfigOptionBool, bridge_no_support)) ((ConfigOptionFloat, elefant_foot_compensation)) @@ -1264,6 +1268,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionString, sparse_infill_rotate_template)) ((ConfigOptionPercent, sparse_infill_density)) ((ConfigOptionEnum, sparse_infill_pattern)) + ((ConfigOptionPercent, sparse_infill_smooth_factor)) ((ConfigOptionFloat, lateral_lattice_angle_1)) ((ConfigOptionFloat, lateral_lattice_angle_2)) ((ConfigOptionFloat, infill_overhang_angle)) @@ -1545,7 +1550,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, gcode_add_line_number)) ((ConfigOptionBool, bbl_bed_temperature_gcode)) ((ConfigOptionEnum, gcode_flavor)) - + ((ConfigOptionBool, gcode_skip_config_block)) ((ConfigOptionFloat, time_cost)) ((ConfigOptionString, layer_change_gcode)) ((ConfigOptionString, time_lapse_gcode)) @@ -1658,6 +1663,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, purge_in_prime_tower)) ((ConfigOptionBool, enable_filament_ramming)) ((ConfigOptionBool, tool_change_on_wipe_tower)) + ((ConfigOptionBool, wait_for_temp_on_wipe_tower)) ((ConfigOptionBool, support_multi_bed_types)) ((ConfigOptionBool, use_3mf)) @@ -2391,6 +2397,55 @@ static void set_flush_volumes_matrix(std::vector &out_matrix, const std::vect } } +template +static bool has_zero_flush_volume_for_used_filaments(const std::vector &fv_matrix, + const std::vector &flush_multipliers, + const std::vector &used_filaments) +{ + if (used_filaments.size() < 2 || flush_multipliers.empty()) + return false; + + if (fv_matrix.size() % flush_multipliers.size() != 0) + return false; + + const size_t matrix_len = fv_matrix.size() / flush_multipliers.size(); + const size_t row_len = size_t(std::sqrt(double(matrix_len))); + if (row_len < 2 || row_len * row_len != matrix_len) + return false; + + std::vector filtered_filaments; + filtered_filaments.reserve(used_filaments.size()); + for (int filament_id : used_filaments) { + if (filament_id <= 0 || filament_id > int(row_len)) + continue; + if (std::find(filtered_filaments.begin(), filtered_filaments.end(), filament_id) == filtered_filaments.end()) + filtered_filaments.push_back(filament_id); + } + if (filtered_filaments.size() < 2) + return false; + + for (T multiplier : flush_multipliers) { + if (multiplier == 0) + return true; + } + + for (size_t nozzle_idx = 0; nozzle_idx < flush_multipliers.size(); nozzle_idx++) { + const size_t block_offset = nozzle_idx * matrix_len; + for (int from_id : filtered_filaments) { + for (int to_id : filtered_filaments) { + if (from_id == to_id) + continue; + + const size_t matrix_idx = block_offset + size_t(from_id - 1) * row_len + size_t(to_id - 1); + if (matrix_idx < fv_matrix.size() && fv_matrix[matrix_idx] == 0) + return true; + } + } + } + + return false; +} + size_t get_extruder_index(const GCodeConfig& config, unsigned int filament_id); } // namespace Slic3r diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 0d31f6c04c..8368de1a4f 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1175,6 +1175,7 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "brim_type" || opt_key == "brim_ears_max_angle" || opt_key == "brim_ears_detection_length" + || opt_key == "brim_ears_outer_only" // BBS: brim generation depends on printing speed || opt_key == "outer_wall_speed" || opt_key == "small_perimeter_speed" @@ -1364,7 +1365,6 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "infill_combination_max_layer_height" || opt_key == "bottom_shell_thickness" || opt_key == "top_shell_thickness" - || opt_key == "top_surface_expansion" || opt_key == "top_surface_expansion_margin" || opt_key == "top_surface_expansion_direction" || opt_key == "minimum_sparse_infill_area" @@ -1400,7 +1400,6 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "infill_anchor" || opt_key == "infill_anchor_max" || opt_key == "top_surface_line_width" - || opt_key == "top_surface_density" || opt_key == "bottom_surface_density" || opt_key == "center_of_surface_pattern" || opt_key == "separated_infills" @@ -1411,6 +1410,7 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "infill_overhang_angle") { steps.emplace_back(posInfill); } else if (opt_key == "sparse_infill_pattern" + || opt_key == "sparse_infill_smooth_factor" || opt_key == "symmetric_infill_y_axis" || opt_key == "infill_shift_step" || opt_key == "sparse_infill_rotate_template" @@ -1434,6 +1434,24 @@ bool PrintObject::invalidate_state_by_config_options( is_approx(new_density->value, 0.) || is_approx(new_density->value, 100.)) steps.emplace_back(posPerimeters); steps.emplace_back(posPrepareInfill); + } else if (opt_key == "top_surface_density") { + // ORCA: 0% means no top solid fill, which switches off both the top surface expansion and the wall + // removal over top surfaces. Only crossing zero matters; posPerimeters cascades to posPrepareInfill. + const auto *old_density = old_config.option(opt_key); + const auto *new_density = new_config.option(opt_key); + assert(old_density && new_density); + if (is_approx(old_density->value, 0.) || is_approx(new_density->value, 0.)) + steps.emplace_back(posPerimeters); + steps.emplace_back(posInfill); + } else if (opt_key == "top_surface_expansion") { + // ORCA: without the expansion the top fill never reaches the space freed by only_one_wall_top, so the + // walls over top surfaces are kept. Only crossing zero matters; posPerimeters cascades to posPrepareInfill. + const auto *old_expansion = old_config.option(opt_key); + const auto *new_expansion = new_config.option(opt_key); + assert(old_expansion && new_expansion); + if (old_expansion->value <= 0. || new_expansion->value <= 0.) + steps.emplace_back(posPerimeters); + steps.emplace_back(posPrepareInfill); } else if (opt_key == "internal_solid_infill_line_width") { // This value is used for calculating perimeter - infill overlap, thus perimeters need to be recalculated. steps.emplace_back(posPerimeters); @@ -1760,51 +1778,50 @@ void PrintObject::detect_surfaces_type() } } - // ORCA: Expand the top surfaces outward by top_surface_expansion in every direction. This - // enlarges the top solid infill and, in particular, grows it over the covered material left - // by features rising from the middle of a top surface (filling holes and joining tops so the - // features rest on it). The expansion stays inside the section it belongs to: each connected - // solid island has its own outer wall, so the top is grown within each island separately and - // clipped to it - growing one island's top across the gap into another island (which may have - // no top surface, leaving a partially filled layer) is never allowed. The top infill sits - // inside the perimeters, so the margin is measured from the walls: the island is inset by the - // band the walls consume (outer wall + inner walls) plus the configured margin, making that - // value the real clearance between the expanded top and the walls (avoiding a hull line). The - // original top is unioned back in, so where it already sits within that band it is kept as-is. - // Never claims a bottom surface. - const double top_expansion = layerm->region().config().top_surface_expansion.value; - if (top_expansion > 0. && ! top.empty()) { - const double d = scale_(top_expansion); - const auto jt = Clipper2Lib::JoinType::Miter; - const ExPolygons T = union_ex(to_expolygons(top)); - const int wall_loops = layerm->region().config().wall_loops.value; + // ORCA: Grow the top surfaces by top_surface_expansion, so the top solid infill also covers the + // material left by features rising from the middle of a top surface (filling the holes and + // joining the tops, so the features rest on solid infill). Each connected island is grown and + // clipped separately: growing one island's top across a gap into another - which may have no top + // surface at all, leaving a partially filled layer - is never allowed. The original top is + // unioned back in and bottom surfaces are never claimed, so this can only add area. + const PrintRegionConfig ®ion_config = layerm->region().config(); + const double top_expansion = region_config.top_surface_expansion.value; + // Nothing to expand without a top fill: a 0% top surface density leaves the top layer with + // walls only, and zero top shell layers retypes it as internal in prepare_fill_surfaces(). + if (top_expansion > 0. && region_config.top_shell_layers.value > 0 && + region_config.top_surface_density.value > 0. && ! top.empty()) { + const double d = scale_(top_expansion); + const ExPolygons T = union_ex(to_expolygons(top)); + // Walls are laid out on spacing, not width; and only_one_wall_top leaves a single wall over + // a top surface, which is exactly the situation handled here. + const int wall_loops = region_config.only_one_wall_top.value ? std::min(region_config.wall_loops.value, 1) + : region_config.wall_loops.value; const double wall_band = wall_loops <= 0 ? 0. : double(layerm->flow(frExternalPerimeter).scaled_width()) + - double(layerm->flow(frPerimeter).scaled_width()) * double(wall_loops - 1); - const double margin = scale_(layerm->region().config().top_surface_expansion_margin.value); + double(layerm->flow(frPerimeter).scaled_spacing()) * double(wall_loops - 1); + const double margin = scale_(region_config.top_surface_expansion_margin.value); // minimum real top to act on: ignore anything thinner than ~2 top-infill lines const float min_top = float(layerm->flow(frTopSolidInfill).scaled_width()); - const auto direction = layerm->region().config().top_surface_expansion_direction.value; + const auto direction = region_config.top_surface_expansion_direction.value; ExPolygons grown; for (const ExPolygon &island : union_ex(layerm_slices_surfaces)) { // The top infill only exists inside the perimeters, so seed and measure from the infill - // region (the island minus the wall band), not the raw slice. A section whose only - // exposed top lies in the wall band - i.e. a layer where the top is just the walls - // themselves - has no infill here and is skipped, instead of being flooded inward by - // the expansion. Thin slivers inside the infill region are dropped by the opening too. + // region (the island minus the wall band), not the raw slice: a section whose exposed top + // is just the walls themselves is then skipped instead of being flooded inward. Clip the + // layer's tops to the island first, to keep the boolean ops proportional to the island. const ExPolygons infill_region = wall_band > 0. ? offset_ex(island, -float(wall_band)) : ExPolygons{ island }; - const ExPolygons island_top = intersection_ex(T, infill_region); + const ExPolygons island_top = intersection_ex( + ClipperUtils::clip_clipper_polygons_with_subject_bbox(T, get_extents(island).inflated(SCALED_EPSILON)), + infill_region); if (opening_ex(island_top, min_top).empty()) continue; // no real top infill in this section - never expand into it - // grow by d, then keep only the part allowed by the configured direction: inward fills - // the holes/gaps left by features (clip the growth back to the top's own filled outline, - // which leaves the outer edge fixed), outward grows the outer edge toward the walls (drop - // the growth that fell into the original holes), and inward+outward keeps both. - ExPolygons expanded = offset_ex_2(island_top, d, jt); + // Grow, then keep only what the configured direction allows, using the top's own filled + // outline (same outer edge, holes closed) to tell the two apart. + ExPolygons expanded = offset_ex_2(island_top, d, Clipper2Lib::JoinType::Miter); if (direction != TopSurfaceExpansionDirection::InwardAndOutward) { - ExPolygons outline; // the top with its holes filled (same outer edge) + ExPolygons outline; outline.reserve(island_top.size()); for (const ExPolygon &ex : island_top) outline.emplace_back(ex.contour); @@ -3795,7 +3812,7 @@ static void apply_to_print_region_config(PrintRegionConfig &out, const DynamicPr else { ConfigOptionVectorBase* opt_vec_src = static_cast(my_opt); const ConfigOptionVectorBase* opt_vec_dest = static_cast(it->second.get()); - opt_vec_src->set_to_index(opt_vec_dest, variant_index, 1); + set_variant_override(*opt_vec_src, *opt_vec_dest, variant_index); } } } diff --git a/src/libslic3r/SLA/IndexedMesh.cpp b/src/libslic3r/SLA/IndexedMesh.cpp index b879e3f48b..65d9d90b34 100644 --- a/src/libslic3r/SLA/IndexedMesh.cpp +++ b/src/libslic3r/SLA/IndexedMesh.cpp @@ -56,12 +56,12 @@ public: int & i, Eigen::Matrix &closest) { - size_t idx_unsigned = 0; - Vec3d closest_vec3d(closest); - double dist = + size_t idx_unsigned { 0 }; + Vec3d closest_vec3d { Vec3d::Zero() }; + const double dist { AABBTreeIndirect::squared_distance_to_indexed_triangle_set( its.vertices, its.indices, m_tree, point, idx_unsigned, - closest_vec3d); + closest_vec3d) }; i = int(idx_unsigned); closest = closest_vec3d; return dist; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 2dee4bc780..06ebbbf41d 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -51,9 +51,4 @@ // Enable extension of tool position imgui dialog to show actual speed profile #define ENABLE_ACTUAL_SPEED_DEBUG 1 -// Disable layout inspector for public release -#if BBL_RELEASE_TO_PUBLIC -#define WXINSPECTOR_DISABLE -#endif - #endif // _prusaslicer_technologies_h_ diff --git a/src/libvgcode/include/Viewer.hpp b/src/libvgcode/include/Viewer.hpp index 7c0a0c295a..5141245d96 100644 --- a/src/libvgcode/include/Viewer.hpp +++ b/src/libvgcode/include/Viewer.hpp @@ -91,12 +91,15 @@ public: // void toggle_top_layer_only_view_range(); // - // Dim previous layers (ORCA, ported from preFlight) - // Whether the layers below the current top layer are rendered darkened while - // scrubbing below the full print, so only the current layer is shown at full brightness. + // Dim previous layers (ORCA) + // Whether the layers the layer slider is not scrubbed to are rendered darkened while + // showing less than the full print, so only the inspected layer(s) are at full brightness. + // How bright those darkened layers are rendered, 1.0 = unchanged, 0.0 = black. // bool is_dim_previous_layers() const; void set_dim_previous_layers(bool value); + float get_dim_previous_layers_brightness() const; + void set_dim_previous_layers_brightness(float value); // // Returns true if the given option is visible. // diff --git a/src/libvgcode/src/Settings.hpp b/src/libvgcode/src/Settings.hpp index 89cb9771b4..b3aa371c4a 100644 --- a/src/libvgcode/src/Settings.hpp +++ b/src/libvgcode/src/Settings.hpp @@ -19,9 +19,11 @@ struct Settings EViewType view_type{ EViewType::FeatureType }; ETimeMode time_mode{ ETimeMode::Normal }; bool top_layer_only_view_range{ false }; - // ORCA: when enabled, all layers below the current top layer are rendered - // darkened (keeping their color) while scrubbing below the full print (ported from preFlight) + // ORCA: when enabled, every layer the layer slider is not scrubbed to is rendered + // darkened (keeping its color) while showing less than the full print bool dim_previous_layers{ false }; + // ORCA: how bright those darkened layers are rendered, 1.0 = unchanged, 0.0 = black + float dim_previous_layers_brightness{ 0.4f }; bool spiral_vase_mode{ false }; // // Required update flags diff --git a/src/libvgcode/src/Viewer.cpp b/src/libvgcode/src/Viewer.cpp index a36cf011ce..eb606598e9 100644 --- a/src/libvgcode/src/Viewer.cpp +++ b/src/libvgcode/src/Viewer.cpp @@ -82,6 +82,16 @@ void Viewer::set_dim_previous_layers(bool value) m_impl->set_dim_previous_layers(value); } +float Viewer::get_dim_previous_layers_brightness() const +{ + return m_impl->get_dim_previous_layers_brightness(); +} + +void Viewer::set_dim_previous_layers_brightness(float value) +{ + m_impl->set_dim_previous_layers_brightness(value); +} + bool Viewer::is_option_visible(EOptionType type) const { return m_impl->is_option_visible(type); diff --git a/src/libvgcode/src/ViewerImpl.cpp b/src/libvgcode/src/ViewerImpl.cpp index 9804e12b9e..da1a601149 100644 --- a/src/libvgcode/src/ViewerImpl.cpp +++ b/src/libvgcode/src/ViewerImpl.cpp @@ -1223,16 +1223,12 @@ static float encode_color(const Color& color) { return static_cast(i_color); } -// ORCA: how much the layers below the current top layer are darkened when -// Settings::dim_previous_layers is enabled (ported from preFlight). 0.0 = no change, 1.0 = black. -static constexpr float PREVIOUS_LAYER_DARKEN_FACTOR = 0.60f; - -// ORCA: returns the encoded color scaled towards black by 'factor', preserving its hue -static float encode_color_darkened(const Color& color, float factor) { - const float keep = 1.0f - factor; - const int r = static_cast(color[0] * keep); - const int g = static_cast(color[1] * keep); - const int b = static_cast(color[2] * keep); +// ORCA: returns the encoded color scaled towards black by 'brightness', preserving its hue. +// 1.0 = no change, 0.0 = black. +static float encode_color_dimmed(const Color& color, float brightness) { + const int r = static_cast(color[0] * brightness); + const int g = static_cast(color[1] * brightness); + const int b = static_cast(color[2] * brightness); const int i_color = r << 16 | g << 8 | b; return static_cast(i_color); } @@ -1248,15 +1244,20 @@ void ViewerImpl::update_colors_texture() const size_t top_layer_id = m_settings.top_layer_only_view_range ? m_layers.get_view_range()[1] : 0; const bool color_top_layer_only = m_view_range.get_full()[1] != m_view_range.get_visible()[1]; - // ORCA: when dim_previous_layers is enabled, darken every layer below the current top layer - // (keeping its color) whenever we are not rendering the whole print, so that only the layer - // being scrubbed to is shown at full brightness (ported from preFlight). This shares - // top_layer_id with the greying path, so it only applies while in top-layer-only mode - that - // way the moves slider still animates normally across all layers when that mode is disabled. - const bool dim_previous_layers = m_settings.dim_previous_layers && !m_layers.empty(); - const bool full_render = (m_layers.get_view_range()[0] == 0) && - (m_layers.get_view_range()[1] >= static_cast(m_layers.count()) - 1) && - (m_view_range.get_visible()[1] == m_view_range.get_full()[1]); + // ORCA: when dim_previous_layers is enabled, darken every layer (keeping its color) except the + // one(s) the layer slider is being scrubbed to, so that only those are shown at full brightness. + // A slider thumb marks a layer as inspected only once it is moved away from + // its end of the print: the upper one while it is below the last layer (or while the moves + // slider is not at the end of the layer), the lower one while it is above the first layer, so + // trimming the print from the bottom lights up the lowest visible layer and using the slider as + // a range lights up both ends. When neither thumb is moved the whole print is rendered normally. + // Gated on top-layer-only mode, which the greying path below also keys off of, so that the moves + // slider still animates normally across all layers when that mode is disabled. + const Interval& layers_range = m_layers.get_view_range(); + const bool inspecting_top_layer = layers_range[1] + 1 < m_layers.count() || color_top_layer_only; + const bool inspecting_bottom_layer = layers_range[0] > 0; + const bool dim_previous_layers = m_settings.dim_previous_layers && m_settings.top_layer_only_view_range && + !m_layers.empty() && (inspecting_top_layer || inspecting_bottom_layer); // Based on current settings and slider position, we might want to render some // vertices as dark grey (or darkened, see above). Use either that or the normal color (from the cache). @@ -1265,9 +1266,13 @@ void ViewerImpl::update_colors_texture() for (size_t i=0; i ViewerImpl::get_time_modes() const { std::vector ret; diff --git a/src/libvgcode/src/ViewerImpl.hpp b/src/libvgcode/src/ViewerImpl.hpp index 8a91d5524f..4da312fc0e 100644 --- a/src/libvgcode/src/ViewerImpl.hpp +++ b/src/libvgcode/src/ViewerImpl.hpp @@ -85,9 +85,14 @@ public: bool is_top_layer_only_view_range() const { return m_settings.top_layer_only_view_range; } void toggle_top_layer_only_view_range(); - // ORCA: darken layers below the current top layer while scrubbing (ported from preFlight) + // ORCA: darken every layer the layer slider is not scrubbed to, so that only the inspected + // one(s) - the top thumb's layer, the bottom thumb's layer, or both - stay at full + // brightness. dim_previous_layers_brightness sets how dark the rest go, 1.0 = unchanged, + // 0.0 = black bool is_dim_previous_layers() const { return m_settings.dim_previous_layers; } void set_dim_previous_layers(bool value); + float get_dim_previous_layers_brightness() const { return m_settings.dim_previous_layers_brightness; } + void set_dim_previous_layers_brightness(float value); bool is_spiral_vase_mode() const { return m_settings.spiral_vase_mode; } diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index b52a520200..bf5d1f2421 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -70,6 +70,9 @@ float FullTransparentModdifiedToFixAlpha = 0.3f; // value like 0.18f could not because in C++ (int)(0.18f * 255) == 45 however in OpenGL it renders this as 46 // which breaks the `SelectMachineDialog::record_edge_pixels_data()` function! float FULL_BLACK_THRESHOLD = 0.2f; +// Keep depth_tex away from texture unit 0 to avoid sampler-type aliasing with +// shadow/environment samplers when realistic view is disabled. +static constexpr int OUTLINE_DEPTH_TEX_UNIT = 5; Slic3r::ColorRGBA adjust_color_for_rendering(const Slic3r::ColorRGBA &colors) { @@ -518,6 +521,37 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size) glsafe(::glStencilMask(0xFF)); glsafe(::glDisable(GL_STENCIL_TEST)); // render the outline using depth buffer and discard the pixels that are not on the outline + // The silhouette is resolved per sample in the shader (see DetectSilho in gouraud.fs/phong.fs). + // That needs the GL 3.2 entry points and a shader that declares depth_tex as sampler2DMS, which + // only the 140 ones do and only under GL_ARB_texture_multisample - so ask the compiled program + // rather than the GL version, or a sampler2D ends up bound to a multisample texture. + // Only the Arb branch below allocates a multisample texture, so keep the target consistent with it. + const bool use_msaa_outline = framebuffers_type == GUI::OpenGLManager::EFramebufferType::Arb && + GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 2) && + shader->get_uniform_location("msaa_samples") >= 0; + const GLenum depth_tex_target = use_msaa_outline ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; + // Keep the depth texture off image unit 0. The object shaders leave shadow_map (and + // environment_tex) at the default sampler value 0 whenever the shadow pass is skipped - which is + // the case with realistic view off - and GL forbids two sampler types referring to the same image + // unit. A sampler2DMS on unit 0 then makes every draw fail with INVALID_OPERATION on drivers that + // enforce it (Mesa), i.e. the model disappears entirely. Unit 5 is unused (shadow_map takes 4). + const int depth_tex_unit = OUTLINE_DEPTH_TEX_UNIT; + int aa_samples = 1; + if (use_msaa_outline) { + if (const AppConfig* app_config = GUI::wxGetApp().app_config; app_config != nullptr) { + const std::string value = app_config->get(SETTING_OPENGL_AA_SAMPLES); + if (value == "2" || value == "4" || value == "8" || value == "16") + aa_samples = ::atoi(value.c_str()); + } + // Never request more samples than the driver supports for depth textures (a 1-sample texture + // is used when MSAA is disabled, keeping a single code path for the sampler2DMS shader). + GLint max_samples = 1; + glsafe(::glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &max_samples)); + if (aa_samples > max_samples) + aa_samples = max_samples < 1 ? 1 : max_samples; + if (aa_samples < 1) + aa_samples = 1; + } // 1st. render pass, render the model into a separate render target that has only depth buffer GLuint depth_fbo = 0; GLuint depth_tex = 0; @@ -525,21 +559,26 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size) glsafe(::glGenFramebuffers(1, &depth_fbo)); glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, depth_fbo)); - glActiveTexture(GL_TEXTURE0); + glsafe(::glActiveTexture(GL_TEXTURE0 + depth_tex_unit)); glsafe(::glGenTextures(1, &depth_tex)); - glsafe(::glBindTexture(GL_TEXTURE_2D, depth_tex)); - glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, cnv_size.get_width(), cnv_size.get_height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr)); + glsafe(::glBindTexture(depth_tex_target, depth_tex)); + if (use_msaa_outline) { + // Multisample textures do not take filter/wrap parameters. + glsafe(::glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, aa_samples, GL_DEPTH_COMPONENT32F, cnv_size.get_width(), cnv_size.get_height(), GL_TRUE)); + } else { + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, cnv_size.get_width(), cnv_size.get_height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr)); + } - glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_tex, 0)); + glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_tex_target, depth_tex, 0)); } else { glsafe(::glGenFramebuffersEXT(1, &depth_fbo)); glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, depth_fbo)); - glActiveTexture(GL_TEXTURE0); + glsafe(::glActiveTexture(GL_TEXTURE0 + depth_tex_unit)); glsafe(::glGenTextures(1, &depth_tex)); glsafe(::glBindTexture(GL_TEXTURE_2D, depth_tex)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); @@ -550,12 +589,15 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size) glsafe(::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depth_tex, 0)); } + // Unbind before drawing: the texture is this framebuffer's depth attachment, so leaving it bound + // to a sampled unit would be a feedback loop. + glsafe(::glBindTexture(depth_tex_target, 0)); + glsafe(::glActiveTexture(GL_TEXTURE0)); glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); if (tverts_range == std::make_pair(0, -1)) model.render(shader); else model.render(this->tverts_range, shader); - glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); // 2nd. render pass, just a normal render with the depth buffer passed as a texture if (framebuffers_type == GUI::OpenGLManager::EFramebufferType::Arb) { @@ -565,13 +607,17 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size) } shader->set_uniform("is_outline", true); shader->set_uniform("screen_size", Vec2f{cnv_size.get_width(), cnv_size.get_height()}); - glActiveTexture(GL_TEXTURE0); - glsafe(::glBindTexture(GL_TEXTURE_2D, depth_tex)); - shader->set_uniform("depth_tex", 0); + shader->set_uniform("msaa_samples", aa_samples); + glsafe(::glActiveTexture(GL_TEXTURE0 + depth_tex_unit)); + glsafe(::glBindTexture(depth_tex_target, depth_tex)); + glsafe(::glActiveTexture(GL_TEXTURE0)); + shader->set_uniform("depth_tex", depth_tex_unit); simple_render(shader, model_objects, colors); // Some clean up to do - glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); + glsafe(::glActiveTexture(GL_TEXTURE0 + depth_tex_unit)); + glsafe(::glBindTexture(depth_tex_target, 0)); + glsafe(::glActiveTexture(GL_TEXTURE0)); shader->set_uniform("is_outline", false); if (framebuffers_type == GUI::OpenGLManager::EFramebufferType::Arb) { glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0)); @@ -1075,6 +1121,10 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, const float support_normal_z = get_selection_support_normal_z(); + // Prime depth_tex on every frame so non-outline draws do not keep the + // default sampler unit 0, which can conflict with other sampler types. + shader->set_uniform("depth_tex", OUTLINE_DEPTH_TEX_UNIT); + for (GLVolumeWithIdAndZ& volume : to_render) { #if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT if (type == ERenderType::Transparent) { diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 74165c20fe..2e436e8462 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -4,6 +4,7 @@ #include "GUI_App.hpp" #include "libslic3r/Preset.hpp" #include "I18N.hpp" +#include #include #include #include @@ -1075,54 +1076,105 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi // Sort the filaments { - static std::unordered_map sorted_names - { {"Bambu PLA Basic", 0}, - {"Bambu PLA Matte", 1}, - {"Bambu PETG HF", 2}, - {"Bambu ABS", 3}, - {"Bambu PLA Silk", 4}, - {"Bambu PLA-CF" , 5}, - {"Bambu PLA Galaxy", 6}, - {"Bambu PLA Metal", 7}, - {"Bambu PLA Marble", 8}, - {"Bambu PETG-CF", 9}, - {"Bambu PETG Translucent", 10}, - {"Bambu ABS-GF", 11} + std::unordered_map selected_filament_ranks; + + // Helper lambda to find a filament Preset by name. We can call this multiple times to walk the inheritance chain and find the base filament. + auto find_filament_by_name = [](const std::string& wanted, const PresetCollection& filaments) -> const Preset* { + for (auto it = filaments.begin(); it != filaments.end(); ++it) { + if (it->name == wanted) { + return &(*it); + } + } + return nullptr; }; - static std::vector sorted_vendors { "Bambu Lab", "Generic" }; - static std::vector sorted_types { "PLA", "PETG", "ABS", "TPU" }; - auto _filament_sorter = [&query_filament_vendors, &query_filament_types](const wxString& left, const wxString& right) -> bool - { - { // Compare name order - const auto& iter1 = sorted_names.find(left); - int name_order1 = (iter1 != sorted_names.end()) ? iter1->second : INT_MAX; + // For each active filament preset, find its base filament alias and promote it in extruder order. + auto bundle = wxGetApp().preset_bundle; + const auto& preset_names = bundle->filament_presets; + for (size_t i = preset_names.size(); i-- > 0; ) { + std::string wanted = preset_names[i]; + const int sort_rank = -static_cast(preset_names.size() - i); + + const Preset* match = nullptr; - const auto& iter2 = sorted_names.find(right); - int name_order2 = (iter2 != sorted_names.end()) ? iter2->second : INT_MAX; - if (name_order1 != name_order2) + do { + auto find_result = find_filament_by_name(wanted, bundle->filaments); + if (!find_result) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " No available filament name matches " << wanted; + break; + } + + match = find_result; + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Found available filament matching current preset name " << wanted + << " - Name: " << match->name << " - Alias: " << match->alias + << " - Inherits: " << match->inherits(); + + if (match->inherits().length() == 0) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " No more inherits so we reached the base filament"; + break; + } + + wanted = match->inherits(); + } while (1); // Or loop while (match->alias.length() == 0) because existence of alias and inherits on a Preset seem to be exclusive + + if (!match) { + continue; + } + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Update filament rank to " + std::to_string(sort_rank) + " for preset Name: " + << match->name << " - Alias: " << match->alias; + selected_filament_ranks.insert_or_assign(match->alias, sort_rank); + } + + static const std::vector sorted_vendors { "Generic" }; + static const std::vector sorted_types { "PLA", "PETG", "ABS", "TPU" }; + auto priority_rank = [](const std::vector& priorities, const wxString& value) { + const auto iter = std::find_if(priorities.begin(), priorities.end(), [&value](const wxString& priority) { + return priority.CmpNoCase(value) == 0; + }); + return iter - priorities.begin(); + }; + auto _filament_sorter = [&query_filament_vendors, &query_filament_types, &selected_filament_ranks, &priority_rank](const wxString& left, const wxString& right) -> bool + { + { // Compare selected filament order + const auto& iter1 = selected_filament_ranks.find(left); + int selected_order1 = (iter1 != selected_filament_ranks.end()) ? iter1->second : INT_MAX; + + const auto& iter2 = selected_filament_ranks.find(right); + int selected_order2 = (iter2 != selected_filament_ranks.end()) ? iter2->second : INT_MAX; + if (selected_order1 != selected_order2) { - return name_order1 < name_order2; + return selected_order1 < selected_order2; } } { // Compare vendor - auto iter1 = std::find(sorted_vendors.begin(), sorted_vendors.end(), query_filament_vendors[left]); - auto iter2 = std::find(sorted_vendors.begin(), sorted_vendors.end(), query_filament_vendors[right]); - if (iter1 != iter2) - { - return iter1 < iter2; - }; + const wxString& vendor1 = query_filament_vendors.at(left); + const wxString& vendor2 = query_filament_vendors.at(right); + const auto rank1 = priority_rank(sorted_vendors, vendor1); + const auto rank2 = priority_rank(sorted_vendors, vendor2); + if (rank1 != rank2) + return rank1 < rank2; + + const int vendor_compare = vendor1.CmpNoCase(vendor2); + if (vendor_compare != 0) + return vendor_compare < 0; } { // Compare type - auto iter1 = std::find(sorted_types.begin(), sorted_types.end(), query_filament_types[left]); - auto iter2 = std::find(sorted_types.begin(), sorted_types.end(), query_filament_types[right]); - if (iter1 != iter2) - { - return iter1 < iter2; - } + const wxString& type1 = query_filament_types.at(left); + const wxString& type2 = query_filament_types.at(right); + const auto rank1 = priority_rank(sorted_types, type1); + const auto rank2 = priority_rank(sorted_types, type2); + if (rank1 != rank2) + return rank1 < rank2; + + const int type_compare = type1.CmpNoCase(type2); + if (type_compare != 0) + return type_compare < 0; } - return left < right; + const int name_compare = left.CmpNoCase(right); + return name_compare != 0 ? name_compare < 0 : left < right; }; std::sort(filament_items.begin(), filament_items.end(), _filament_sorter); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 57f25eba24..3885a391b8 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -12,6 +12,7 @@ #include "libslic3r/GCode/AdaptivePAProcessor.hpp" #include "Plater.hpp" +#include #include #include @@ -70,6 +71,12 @@ void ConfigManipulation::toggle_line(const std::string& opt_key, const bool togg cb_toggle_line(opt_key, toggle, opt_index); } +void ConfigManipulation::set_option_label(const std::string& opt_key, const wxString& label, int opt_index) +{ + if (cb_set_option_label) + cb_set_option_label(opt_key, label, opt_index); +} + void ConfigManipulation::check_nozzle_recommended_temperature_range(DynamicPrintConfig *config) { if (is_msg_dlg_already_exist) return; @@ -244,6 +251,59 @@ void ConfigManipulation::check_chamber_minimal_temperature(DynamicPrintConfig* c } } +void ConfigManipulation::layer_height_limits(double& min_layer_height, double& max_layer_height) const +{ + const DynamicPrintConfig& printer_config = GUI::wxGetApp().preset_bundle->printers.get_edited_preset().config; + const std::vector& min_limits = printer_config.option("min_layer_height")->values; + const std::vector& max_limits = printer_config.option("max_layer_height")->values; + min_layer_height = *std::min_element(min_limits.begin(), min_limits.end()); + max_layer_height = *std::max_element(max_limits.begin(), max_limits.end()); +} + +bool ConfigManipulation::check_layer_height(DynamicPrintConfig* config) +{ + double min_layer_height = 0., max_layer_height = 0.; + layer_height_limits(min_layer_height, max_layer_height); + const double layer_height = config->opt_float("layer_height"); + + if (min_layer_height > EPSILON && layer_height < EPSILON) { + const wxString msg_text = wxString::Format(_L("Layer height is too small. It will be set to the minimum (%g mm)."), min_layer_height); + MessageDialog dialog(wxGetApp().plater(), msg_text, "", wxICON_WARNING | wxOK); + dialog.SetButtonLabel(wxID_OK, _L("OK")); + is_msg_dlg_already_exist = true; + dialog.ShowModal(); + is_msg_dlg_already_exist = false; + DynamicPrintConfig new_conf = *config; + new_conf.set_key_value("layer_height", new ConfigOptionFloat(min_layer_height)); + apply(config, &new_conf); + return true; + } + if (max_layer_height > EPSILON && layer_height > max_layer_height + EPSILON) + return layer_height_out_of_range_dialog(config, max_layer_height); + if (min_layer_height > EPSILON && layer_height < min_layer_height - EPSILON) + return layer_height_out_of_range_dialog(config, min_layer_height); + return false; +} + +bool ConfigManipulation::layer_height_out_of_range_dialog(DynamicPrintConfig* config, double clamp_to) +{ + wxString msg_text = _(L("Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, " + "this may cause printing quality issues.")); + msg_text += "\n\n" + wxString::Format(_L("Adjust it to the limit (%g mm) automatically?"), clamp_to); + MessageDialog dialog(wxGetApp().plater(), msg_text, "", wxICON_WARNING | wxYES | wxNO); + dialog.SetButtonLabel(wxID_YES, _L("Adjust")); + dialog.SetButtonLabel(wxID_NO, _L("Ignore")); + is_msg_dlg_already_exist = true; + const bool adjust = dialog.ShowModal() == wxID_YES; + if (adjust) { + DynamicPrintConfig new_conf = *config; + new_conf.set_key_value("layer_height", new ConfigOptionFloat(clamp_to)); + apply(config, &new_conf); + } + is_msg_dlg_already_exist = false; + return adjust; +} + void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config, const bool is_plate_config) { // #ys_FIXME_to_delete @@ -258,7 +318,6 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con // layer_height shouldn't be equal to zero auto layer_height = config->opt_float("layer_height"); - auto gpreset = GUI::wxGetApp().preset_bundle->printers.get_edited_preset(); if (layer_height < EPSILON) { const wxString msg_text = _(L("Layer height too small\nIt has been reset to 0.2")); @@ -271,20 +330,6 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con is_msg_dlg_already_exist = false; } - //BBS: limite the max layer_herght - auto max_lh = gpreset.config.opt_float("max_layer_height",0); - if (max_lh > 0.2 && layer_height > max_lh+ EPSILON) - { - const wxString msg_text = wxString::Format(L"Too large layer height.\nReset to %0.3f.", max_lh); - MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK); - DynamicPrintConfig new_conf = *config; - is_msg_dlg_already_exist = true; - dialog.ShowModal(); - new_conf.set_key_value("layer_height", new ConfigOptionFloat(max_lh)); - apply(config, &new_conf); - is_msg_dlg_already_exist = false; - } - //BBS: ironing_spacing shouldn't be too small or equal to zero if (config->opt_float("ironing_spacing") < 0.05) { @@ -703,12 +748,14 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in toggle_line("spiral_mode_max_xy_smoothing", has_spiral_vase && config->opt_bool("spiral_mode_smooth")); toggle_line("spiral_starting_flow_ratio", has_spiral_vase); toggle_line("spiral_finishing_flow_ratio", has_spiral_vase); - bool has_top_shell = config->opt_int("top_shell_layers") > 0 || (has_spiral_vase && config->opt_int("bottom_shell_layers") > 1); + bool has_top_shell_layers = config->opt_int("top_shell_layers") > 0 || (has_spiral_vase && config->opt_int("bottom_shell_layers") > 1); + bool has_top_shell = has_top_shell_layers && config->option("top_surface_density")->value > 0; bool has_bottom_shell = config->opt_int("bottom_shell_layers") > 0; - bool has_solid_infill = has_top_shell || has_bottom_shell; + bool has_solid_infill = has_top_shell_layers || has_bottom_shell; + toggle_line("sparse_infill_smooth_factor", pattern == ipHilbertCurve); toggle_field("top_surface_pattern", has_top_shell); toggle_field("bottom_surface_pattern", has_bottom_shell); - toggle_field("top_surface_density", has_top_shell); + toggle_field("top_surface_density", has_top_shell_layers); toggle_field("bottom_surface_density", has_bottom_shell); toggle_field("top_layer_direction", has_top_shell); toggle_field("bottom_layer_direction", has_bottom_shell); @@ -751,7 +798,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in for (auto el : { "sparse_infill_speed", "bridge_speed", "internal_bridge_speed"}) toggle_field(el, have_infill || has_solid_infill, variant_index); - toggle_field("top_shell_thickness", ! has_spiral_vase && has_top_shell); + toggle_field("top_shell_thickness", ! has_spiral_vase && has_top_shell_layers); toggle_field("bottom_shell_thickness", ! has_spiral_vase && has_bottom_shell); // Gap fill is newly allowed in between perimeter lines even for empty infill (see GH #1476). @@ -806,14 +853,19 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in toggle_field("outer_wall_filament_id", have_perimeters || have_brim); toggle_field("inner_wall_filament_id", have_perimeters || have_brim); - bool have_brim_ear = (config->opt_enum("brim_type") == btEar); + const BrimType brim_type = config->opt_enum("brim_type"); + const bool have_auto_brim_ear = brim_type == btEar; + const bool have_painted_brim_ear = brim_type == btPainted; + set_option_label("brim_width", have_auto_brim_ear ? _L("Brim ear radius") : _L("Brim width")); const auto brim_width = config->opt_float("brim_width"); - // disable brim_ears_max_angle and brim_ears_detection_length if brim_width is 0 + // Automatic brim ear settings require a non-zero brim width. toggle_field("brim_ears_max_angle", brim_width > 0.0f); toggle_field("brim_ears_detection_length", brim_width > 0.0f); - // hide brim_ears_max_angle and brim_ears_detection_length if brim_ear is not selected - toggle_line("brim_ears_max_angle", have_brim_ear); - toggle_line("brim_ears_detection_length", have_brim_ear); + // Painted ears carry their own radius and do not depend on brim_width. + toggle_field("brim_ears_outer_only", have_painted_brim_ear || brim_width > 0.0f); + toggle_line("brim_ears_max_angle", have_auto_brim_ear); + toggle_line("brim_ears_detection_length", have_auto_brim_ear); + toggle_line("brim_ears_outer_only", have_auto_brim_ear || have_painted_brim_ear); // Hide Elephant foot compensation layers if elefant_foot_compensation is not enabled toggle_line("elefant_foot_compensation_layers", config->opt_float("elefant_foot_compensation") > 0 || config->option("elefant_foot_layers_density")->get_abs_value(1.0f) < 1.0f); @@ -1008,7 +1060,11 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in toggle_line("make_overhang_printable_angle", have_make_overhang_printable); toggle_line("make_overhang_printable_hole_size", have_make_overhang_printable); - toggle_line("min_width_top_surface", config->opt_bool("only_one_wall_top") || ((config->opt_float("min_length_factor") > 0.5f) && have_arachne)); // 0.5 is default value + // Orca: the one-wall options act on top/bottom surfaces, which exist only with a shell. An unfilled surface + // (0% surface density) is still a surface, so these are gated on the layer counts alone. + toggle_line("only_one_wall_first_layer", has_bottom_shell); + toggle_line("only_one_wall_top", has_top_shell_layers); + toggle_line("min_width_top_surface", (has_top_shell_layers && config->opt_bool("only_one_wall_top")) || ((config->opt_float("min_length_factor") > 0.5f) && have_arachne)); // 0.5 is default value for (auto el : { "hole_to_polyhole_threshold", "hole_to_polyhole_twisted", "hole_to_polyhole_max_edges" }) toggle_line(el, config->opt_bool("hole_to_polyhole")); diff --git a/src/slic3r/GUI/ConfigManipulation.hpp b/src/slic3r/GUI/ConfigManipulation.hpp index 0ad1fb0b7c..ac53ffb4bb 100644 --- a/src/slic3r/GUI/ConfigManipulation.hpp +++ b/src/slic3r/GUI/ConfigManipulation.hpp @@ -29,6 +29,7 @@ class ConfigManipulation std::function load_config = nullptr; std::function cb_toggle_field = nullptr; std::function cb_toggle_line = nullptr; + std::function cb_set_option_label = nullptr; // callback to propagation of changed value, if needed std::function cb_value_change = nullptr; //BBS: change local config to const DynamicPrintConfig @@ -45,10 +46,12 @@ public: std::function cb_value_change, //BBS: change local config to DynamicPrintConfig const DynamicPrintConfig* local_config = nullptr, - wxWindow* msg_dlg_parent = nullptr) : + wxWindow* msg_dlg_parent = nullptr, + std::function cb_set_option_label = nullptr) : load_config(load_config), cb_toggle_field(cb_toggle_field), cb_toggle_line(cb_toggle_line), + cb_set_option_label(cb_set_option_label), cb_value_change(cb_value_change), m_msg_dlg_parent(msg_dlg_parent), local_config(local_config) {} @@ -58,6 +61,7 @@ public: load_config = nullptr; cb_toggle_field = nullptr; cb_toggle_line = nullptr; + cb_set_option_label = nullptr; cb_value_change = nullptr; } @@ -67,6 +71,7 @@ public: t_config_option_keys const &applying_keys() const; void toggle_field(const std::string& field_key, const bool toggle, int opt_index = -1); void toggle_line(const std::string& field_key, const bool toggle, int opt_index = -1); + void set_option_label(const std::string& field_key, const wxString& label, int opt_index = -1); // FFF print void update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config = false, const bool is_plate_config = false); @@ -81,6 +86,9 @@ public: void check_filament_max_volumetric_speed(DynamicPrintConfig *config); void check_chamber_temperature(DynamicPrintConfig* config); void check_chamber_minimal_temperature(DynamicPrintConfig* config); + bool check_layer_height(DynamicPrintConfig* config); + bool layer_height_out_of_range_dialog(DynamicPrintConfig* config, double clamp_to); + void layer_height_limits(double& min_layer_height, double& max_layer_height) const; void set_is_BBL_Printer(bool is_bbl_printer) { is_BBL_Printer = is_bbl_printer; }; bool get_is_BBL_Printer() { return is_BBL_Printer; }; // SLA print diff --git a/src/slic3r/GUI/ConnectPrinter.cpp b/src/slic3r/GUI/ConnectPrinter.cpp index b4cd7f4f2f..3e78e7fe5c 100644 --- a/src/slic3r/GUI/ConnectPrinter.cpp +++ b/src/slic3r/GUI/ConnectPrinter.cpp @@ -156,6 +156,8 @@ void ConnectPrinterDialog::on_input_enter(wxCommandEvent& evt) void ConnectPrinterDialog::on_button_confirm(wxCommandEvent &event) { wxString code = m_textCtrl_code->GetTextCtrl()->GetValue(); + if (code.empty()) + code = "88888888"; for (char c : code) { if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))) { show_error(this, _L("Invalid input")); @@ -163,7 +165,7 @@ void ConnectPrinterDialog::on_button_confirm(wxCommandEvent &event) } } if (m_obj) { - m_obj->set_user_access_code(code.ToStdString()); + m_obj->set_access_code(code.ToStdString()); } EndModal(wxID_OK); } diff --git a/src/slic3r/GUI/DeviceCore/DevManager.cpp b/src/slic3r/GUI/DeviceCore/DevManager.cpp index 2d54b5c85f..edc958ec53 100644 --- a/src/slic3r/GUI/DeviceCore/DevManager.cpp +++ b/src/slic3r/GUI/DeviceCore/DevManager.cpp @@ -15,6 +15,18 @@ using namespace nlohmann; +namespace { + // Orca: access_code and user_access_code used to be separate AppConfig keys before the two + // fields were merged; fall back to the legacy key so existing users' saved codes aren't lost. + std::string get_access_code_with_legacy_fallback(Slic3r::AppConfig* config, const std::string& dev_id) + { + std::string code = config->get("access_code", dev_id); + if (code.empty()) + code = config->get("user_access_code", dev_id); + return code; + } +} + namespace Slic3r { DeviceManager::DeviceManager(NetworkAgent* agent) @@ -48,8 +60,7 @@ namespace Slic3r obj->bind_sec_link = "secure"; obj->m_is_online = true; obj->last_alive = Slic3r::Utils::get_current_time_utc(); - obj->set_access_code(config->get("access_code", m.dev_id), false); - obj->set_user_access_code(config->get("user_access_code", m.dev_id), false); + obj->set_access_code(get_access_code_with_legacy_fallback(config, m.dev_id), false); if (obj->has_access_right()) { localMachineList.insert(std::make_pair(m.dev_id, obj)); } else { @@ -339,8 +350,7 @@ namespace Slic3r //load access code AppConfig* config = Slic3r::GUI::wxGetApp().app_config; if (config) { - obj->set_access_code(Slic3r::GUI::wxGetApp().app_config->get("access_code", dev_id), false); - obj->set_user_access_code(Slic3r::GUI::wxGetApp().app_config->get("user_access_code", dev_id), false); + obj->set_access_code(get_access_code_with_legacy_fallback(config, dev_id), false); } localMachineList.insert(std::make_pair(dev_id, obj)); @@ -382,7 +392,6 @@ namespace Slic3r obj->m_is_online = true; obj->last_alive = Slic3r::Utils::get_current_time_utc(); obj->set_access_code(access_code, false); - obj->set_user_access_code(access_code, false); update_local_machine(*obj); @@ -496,6 +505,26 @@ namespace Slic3r OnSelectedMachineChanged(previous_selected_machine, selected_machine); } + void DeviceManager::clear_other_devices() + { + // why: on agent swap, keep "My Devices" but drop the transient "Other Devices" + // Those belong to the previous agent's network scan; the new agent's start_discovery re-populates its own. + const auto my = get_my_machine_list(); + for (auto it = localMachineList.begin(); it != localMachineList.end();) + { + if (my.find(it->first) == my.end()) + { + // not a "My Device" -> an "Other Device" + delete it->second; + it = localMachineList.erase(it); + } + else + { + ++it; + } + } + } + bool DeviceManager::set_selected_machine(std::string dev_id) { BOOST_LOG_TRIVIAL(info) << "set_selected_machine=" << dev_id @@ -558,7 +587,6 @@ namespace Slic3r } else { - Slic3r::GUI::wxGetApp().reset_unsigned_plugin_warning(); if (m_agent) { if (it->second->connection_type() != "lan" || it->second->connection_type().empty()) @@ -851,7 +879,9 @@ namespace Slic3r int result = m_agent->get_user_print_info(&http_code, &body, provider); if (result == 0) { - parse_user_print_info(body); + // parse_user_print_info and on_machine_alive (SSDP for discovery) both mutate the same userMachineList map. + // on_machine_alive mutates the map on the UI thread, do the same for parse_user_print_info. + Slic3r::GUI::wxGetApp().CallAfter([this, body]() { parse_user_print_info(body); }); } } @@ -878,17 +908,15 @@ namespace Slic3r void DeviceManager::load_last_machine() { - if (userMachineList.empty()) return; - else if (userMachineList.size() == 1) { - this->set_selected_machine(userMachineList.begin()->second->get_dev_id()); - } else { - const auto& last_monitor_machine = get_user_last_machine(); - if (userMachineList.find(last_monitor_machine) != userMachineList.end()) { - set_selected_machine(last_monitor_machine); - } else { - this->set_selected_machine(userMachineList.begin()->second->get_dev_id()); - } - } + // Only reconnect the remembered cloud machine. Do not select an arbitrary + // first machine: agent swaps intentionally leave the selection empty until + // the new agent explicitly selects its configured printer. + if (userMachineList.empty()) + return; + + const auto& last_monitor_machine = get_user_last_machine(); + if (userMachineList.find(last_monitor_machine) != userMachineList.end()) + set_selected_machine(last_monitor_machine); } void DeviceManager::OnMachineBindStateChanged(MachineObject* obj, const std::string& new_state) diff --git a/src/slic3r/GUI/DeviceCore/DevManager.h b/src/slic3r/GUI/DeviceCore/DevManager.h index 1f7f87b7fb..e3ac0064b9 100644 --- a/src/slic3r/GUI/DeviceCore/DevManager.h +++ b/src/slic3r/GUI/DeviceCore/DevManager.h @@ -48,6 +48,10 @@ public: MachineObject* get_selected_machine(); bool set_selected_machine(std::string dev_id); + // why: clears stale sidebar sync-status / AMS visuals. Public so the printer-agent + // swap path can reuse it instead of duplicating the two sidebar calls. + void OnSelectedMachineLost(); + void record_user_last_machine(const std::string& dev_id); std::string get_user_last_machine() const; @@ -70,6 +74,8 @@ public: void erase_user_machine(std::string dev_id) { userMachineList.erase(dev_id); } void clean_user_info(bool keep_local_selection = false); + void clear_other_devices(); + void load_last_machine(); void update_user_machine_list_info(const std::string& provider); void parse_user_print_info(std::string body); @@ -110,7 +116,6 @@ private: void check_pushing(); void OnMachineBindStateChanged(MachineObject* obj, const std::string& new_state); - void OnSelectedMachineLost(); void OnSelectedMachineChanged(const std::string& pre_dev_id, const std::string& new_dev_id); diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 5499694686..f4befe78c1 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -449,9 +449,7 @@ bool MachineObject::HasRecentLanMessage() std::string MachineObject::get_access_code() const { - if (get_user_access_code().empty()) - return access_code; - return get_user_access_code(); + return access_code; } void MachineObject::set_access_code(std::string code, bool only_refresh) @@ -470,37 +468,6 @@ void MachineObject::set_access_code(std::string code, bool only_refresh) } } -void MachineObject::erase_user_access_code() -{ - this->user_access_code = ""; - AppConfig* config = GUI::wxGetApp().app_config; - if (config) { - GUI::wxGetApp().app_config->erase("user_access_code", get_dev_id()); - //GUI::wxGetApp().app_config->save(); - } -} - -void MachineObject::set_user_access_code(std::string code, bool only_refresh) -{ - this->user_access_code = code; - if (only_refresh && !code.empty()) { - AppConfig* config = GUI::wxGetApp().app_config; - if (config && !code.empty()) { - GUI::wxGetApp().app_config->set_str("user_access_code", get_dev_id(), code); - DeviceManager::update_local_machine(*this); - } - } -} - -std::string MachineObject::get_user_access_code() const -{ - AppConfig* config = GUI::wxGetApp().app_config; - if (config) { - return GUI::wxGetApp().app_config->get("user_access_code", get_dev_id()); - } - return ""; -} - std::string MachineObject::get_show_printer_type() const { std::string printer_type = this->printer_type; @@ -2907,7 +2874,6 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_ std::string access_code = j_pre["system"]["access_code"].get(); if (!access_code.empty()) { set_access_code(access_code); - set_user_access_code(access_code); } } } @@ -4647,6 +4613,40 @@ void MachineObject::set_ctt_dlg( wxString text){ } } +void MachineObject::show_unsupported_dlg(int code) +{ + // why: a dead control invites repeat clicks, and the frame is modeless - without the guard + // every click stacks another one. Same shape as set_ctt_dlg above, including the reset on + // both hide and close so a dismissed dialog can reappear on the next attempt. + if (m_unsupported_dlg_shown) { + return; + } + m_unsupported_dlg_shown = true; + + // why: two codes so the user learns which kind of dead end this is - the slicer having no + // translation for the command, or the printer's own config lacking the hardware to run it. + const wxString text = (code == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE) ? + _L("This printer is not configured with the hardware this control needs.") : + _L("This control is not supported on this printer."); + + // note: constructed directly rather than through CallAfter because every publish_json caller + // is on the UI thread - clicks come from wx handlers, and the agent marshals its own push + // callbacks back to main before parse_json runs. set_ctt_dlg relies on the same property. + auto unsupported_dlg = new GUI::SecondaryCheckDialog(nullptr, wxID_ANY, _L("Warning"), + GUI::SecondaryCheckDialog::VisibleButtons::ONLY_CONFIRM); + unsupported_dlg->update_text(text); + unsupported_dlg->Bind(wxEVT_SHOW, [this](auto& e) { + if (!e.IsShown()) { + m_unsupported_dlg_shown = false; + } + }); + unsupported_dlg->Bind(wxEVT_CLOSE_WINDOW, [this](auto& e) { + e.Skip(); + m_unsupported_dlg_shown = false; + }); + unsupported_dlg->on_show(); +} + int MachineObject::publish_gcode(std::string gcode_str) { json j; diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 456901cf84..33635fbe6e 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -113,7 +113,6 @@ private: std::string dev_name; std::string dev_ip; std::string access_code; - std::string user_access_code; // type, time stamp, delay std::vector> message_delay; @@ -228,11 +227,6 @@ public: std::string get_access_code() const; void set_access_code(std::string code, bool only_refresh = true); - /*user access code*/ - void set_user_access_code(std::string code, bool only_refresh = true); - void erase_user_access_code(); - std::string get_user_access_code() const; - //PRINTER_TYPE printer_type = PRINTER_3DPrinter_UKNOWN; std::string printer_type; /* model_id */ std::string get_show_printer_type() const; @@ -272,9 +266,11 @@ public: bool m_is_online; bool m_lan_mode_connection_state{false}; bool m_set_ctt_dlg{ false }; + bool m_unsupported_dlg_shown{ false }; void set_lan_mode_connection_state(bool state) {m_lan_mode_connection_state = state;}; bool get_lan_mode_connection_state() {return m_lan_mode_connection_state;}; void set_ctt_dlg( wxString text); + void show_unsupported_dlg(int code); int parse_msg_count = 0; int keep_alive_count = 0; std::chrono::system_clock::time_point last_update_time; /* last received print data from machine */ diff --git a/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp index 33e9cdf518..259506612d 100644 --- a/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp +++ b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp @@ -1,9 +1,9 @@ -//**********************************************************/ -/* File: uiAmsHumidityPopup.cpp +/********************************************************** +* File: uiAmsHumidityPopup.cpp * Description: The popup with DevAms Humidity * * \n class uiAmsHumidityPopup -//**********************************************************/ +**********************************************************/ #include "uiAmsHumidityPopup.h" @@ -191,4 +191,4 @@ void uiAmsPercentHumidityDryPopup::msw_rescale() } // namespace GUI -} // namespace Slic3r \ No newline at end of file +} // namespace Slic3r diff --git a/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h index 0f22c6b662..a109381c86 100644 --- a/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h +++ b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h @@ -1,9 +1,9 @@ -//**********************************************************/ -/* File: uiAmsHumidityPopup.h +/********************************************************** +* File: uiAmsHumidityPopup.h * Description: The popup with DevAms Humidity * * \n class uiAmsHumidityPopup -//**********************************************************/ +**********************************************************/ #pragma once #include "slic3r/GUI/Widgets/AMSItem.hpp" @@ -68,7 +68,7 @@ private: wxStaticBitmap* m_dry_state_img; Label* m_dry_state; - + Label* m_humidity_header; Label* m_humidity_label; @@ -81,4 +81,4 @@ private: wxSizer* m_sizer; }; -}} // namespace Slic3r::GUI \ No newline at end of file +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp b/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp index 5167f482b8..59fc8809ce 100644 --- a/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp +++ b/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp @@ -1,9 +1,9 @@ -//**********************************************************/ -/* File: uiDeviceUpdateVersion.cpp +/********************************************************** +* File: uiDeviceUpdateVersion.cpp * Description: The panel with firmware info * * \n class uiDeviceUpdateVersion -//**********************************************************/ +**********************************************************/ #include "uiDeviceUpdateVersion.h" @@ -114,4 +114,4 @@ void uiDeviceUpdateVersion::CreateWidgets() Layout(); wxGetApp().UpdateDarkUIWin(this); -} \ No newline at end of file +} diff --git a/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.h b/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.h index 100280db62..342067e374 100644 --- a/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.h +++ b/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.h @@ -1,9 +1,9 @@ -//**********************************************************/ -/* File: uiDeviceUpdateVersion.h +/********************************************************** +* File: uiDeviceUpdateVersion.h * Description: The panel with firmware info * * \n class uiDeviceUpdateVersion -//**********************************************************/ +**********************************************************/ #pragma once #include @@ -44,4 +44,4 @@ private: wxStaticText* m_dev_version; wxStaticBitmap* m_dev_upgrade_indicator; }; -};// end of namespace Slic3r::GUI \ No newline at end of file +};// end of namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index bcbc381eff..8d05de13a4 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -35,6 +35,7 @@ #include "Widgets/TextCtrl.h" #include "../Utils/ColorSpaceConvert.hpp" +#include "../Utils/NetworkAgentFactory.hpp" #ifdef __WXOSX__ #define wxOSX true #else @@ -1334,27 +1335,7 @@ void SpinCtrl::BUILD() { if (!parsed || value < INT_MIN || value > INT_MAX) tmp_value = UNDEF_VALUE; else { - tmp_value = std::min(std::max((int)value, temp->GetMin()), temp->GetMax()); -#ifdef __WXOSX__ -#ifdef UNDEFINED__WXOSX__ // BBS - // Forcibly set the input value for SpinControl, since the value - // inserted from the keyboard or clipboard is not updated under OSX - SpinInput* spin = static_cast(window); - spin->SetValue(tmp_value); - // But in SetValue() is executed m_text_ctrl->SelectAll(), so - // discard this selection and set insertion point to the end of string - // temp->GetText()->SetInsertionPointEnd(); -#endif -#else - // update value for the control only if it was changed in respect to the Min/max values - if (tmp_value != (int)value) { - temp->SetValue(tmp_value); - // But after SetValue() cursor ison the first position - // so put it to the end of string - // int pos = std::to_string(tmp_value).length(); - // temp->SetSelection(pos, pos); - } -#endif + tmp_value = (int)value; } }), temp->GetTextCtrl()->GetId()); @@ -1375,6 +1356,10 @@ void SpinCtrl::propagate_value() on_kill_focus(); } else { auto ctrl = dynamic_cast(window); + tmp_value = std::min(std::max(tmp_value, ctrl->GetMin()), ctrl->GetMax()); + if (ctrl->GetValue() != tmp_value) + ctrl->SetValue(tmp_value); // Clamp now when the user is done typing (kill focus / Enter / spin arrows) + if (m_value.empty() ? !ctrl->GetTextCtrl()->GetLabel().IsEmpty() : ctrl->GetValue() != boost::any_cast(m_value)) @@ -1419,39 +1404,6 @@ using choice_ctrl = ::ComboBox; // BBS static std::map dynamic_lists; -static bool is_plugin_printer_agent_key(const std::string& value) -{ - return value.rfind("plugin:", 0) == 0; -} - -static int printer_agent_item_for_enum_index(const choice_ctrl* field, int enum_index) -{ - if (!field) - return -1; - - const unsigned int count = field->GetCount(); - for (unsigned int idx = 0; idx < count; ++idx) { - if (void* data = field->GetClientData(idx)) { - const int stored = static_cast(reinterpret_cast(data)) - 1; - if (stored == enum_index) - return static_cast(idx); - } - } - - return -1; -} - -static int printer_agent_enum_index_for_item(const choice_ctrl* field, int item_index, int fallback) -{ - if (!field || item_index < 0) - return fallback; - - if (void* data = field->GetClientData(item_index)) - return static_cast(reinterpret_cast(data)) - 1; - - return fallback; -} - void Choice::register_dynamic_list(std::string const &optname, DynamicList *list) { dynamic_lists.emplace(optname, list); } void DynamicList::update() @@ -1534,33 +1486,7 @@ void Choice::BUILD() window = dynamic_cast(temp); if (! m_opt.enum_labels.empty() || ! m_opt.enum_values.empty()) { - if (m_opt_id == "printer_agent") { - const bool has_builtin_agents = std::any_of(m_opt.enum_values.begin(), m_opt.enum_values.end(), - [](const std::string& value) { return !is_plugin_printer_agent_key(value); }); - const bool has_plugin_agents = std::any_of(m_opt.enum_values.begin(), m_opt.enum_values.end(), - [](const std::string& value) { return is_plugin_printer_agent_key(value); }); - - auto append_agent_rows = [this, temp](bool plugins) { - for (size_t i = 0; i < m_opt.enum_values.size(); ++i) { - const bool is_plugin = is_plugin_printer_agent_key(m_opt.enum_values[i]); - if (is_plugin != plugins) - continue; - - const wxString label = i < m_opt.enum_labels.size() ? _(m_opt.enum_labels[i]) : wxString(m_opt.enum_values[i]); - const int item = temp->Append(label); - temp->SetClientData(item, reinterpret_cast(static_cast(i + 1))); - } - }; - - if (has_builtin_agents) { - temp->Append(_L("System agents"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM | DD_ITEM_STYLE_DISABLED); - append_agent_rows(false); - } - if (has_plugin_agents) { - temp->Append(_L("Plugins"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM | DD_ITEM_STYLE_DISABLED); - append_agent_rows(true); - } - } else if (m_opt.enum_labels.empty()) { + if (m_opt.enum_labels.empty()) { // Append non-localized enum_values for (auto el : m_opt.enum_values) temp->Append(el); @@ -1667,7 +1593,7 @@ void Choice::set_selection() switch (m_opt.type) { case coEnum:{ const int val = m_opt.default_value->getInt(); - field->SetSelection(m_opt_id == "printer_agent" ? printer_agent_item_for_enum_index(field, val) : val); + field->SetSelection(val); break; } case coFloat: @@ -1717,12 +1643,7 @@ void Choice::set_value(const std::string& value, bool change_event) //! Redunda } choice_ctrl* field = dynamic_cast(window); - if (m_opt_id == "printer_agent") { - const int enum_index = idx == m_opt.enum_values.size() ? - (m_opt.default_value ? m_opt.default_value->getInt() : 0) : - static_cast(idx); - field->SetSelection(printer_agent_item_for_enum_index(field, enum_index)); - } else if (idx == m_opt.enum_values.size()) + if (idx == m_opt.enum_values.size()) field->SetValue(value); else field->SetSelection(idx); @@ -1788,33 +1709,11 @@ void Choice::set_value(const boost::any& value, bool change_event) case coEnum: // BBS case coEnums: { - auto printer_agent_index_from_key = [this](const std::string& key) { - auto it = std::find(m_opt.enum_values.begin(), m_opt.enum_values.end(), key); - if (it != m_opt.enum_values.end()) - return static_cast(it - m_opt.enum_values.begin()); - return m_opt.default_value ? m_opt.default_value->getInt() : 0; - }; - - int val = 0; - if (m_opt_id == "printer_agent") { - if (const int* int_value = boost::any_cast(&value)) - val = *int_value; - else if (const wxString* wx_value = boost::any_cast(&value)) - val = printer_agent_index_from_key(into_u8(*wx_value)); - else if (const std::string* string_value = boost::any_cast(&value)) - val = printer_agent_index_from_key(*string_value); - else { - m_disable_change_event = false; - return; - } - } else - val = boost::any_cast(value); + int val = boost::any_cast(value); int selection = val; - if (m_opt_id == "printer_agent") { - selection = printer_agent_item_for_enum_index(field, val); - } else if (m_opt_id == "input_shaping_type") { + if (m_opt_id == "input_shaping_type") { if (field != nullptr) { const unsigned int count = field->GetCount(); int match_index = -1; @@ -1936,12 +1835,6 @@ boost::any& Choice::get_value() { if (m_opt.nullable && field->GetSelection() == -1) m_value = ConfigOptionEnumsGenericNullable::nil_value(); - else if (m_opt_id == "printer_agent") - { - const int selection = field->GetSelection(); - const int fallback = m_opt.default_value ? m_opt.default_value->getInt() : 0; - m_value = printer_agent_enum_index_for_item(field, selection, fallback); - } else if (m_opt_id == "input_shaping_type") { int selection = field->GetSelection(); @@ -2083,6 +1976,171 @@ void Choice::msw_rescale() } +// PrinterAgentChoice + +void PrinterAgentChoice::reload_rows() +{ + auto* combo = dynamic_cast(window); // wxWidgets ComboBox + if (!combo) + return; + + // clear ComboBox + combo->Clear(); + + // helpers + const auto agents = NetworkAgentFactory::get_registered_printer_agents(); + const bool has_builtin_agents = std::any_of(agents.begin(), agents.end(), + [](const PrinterAgentInfo& a) { return !a.is_plugin(); }); + const bool has_plugin_agents = std::any_of(agents.begin(), agents.end(), + [](const PrinterAgentInfo& a) { return a.is_plugin(); }); + + auto append_agent_rows = [combo](bool is_plugin) + { + const auto agents = NetworkAgentFactory::get_registered_printer_agents(); + for (size_t i = 0; i < agents.size(); ++i) + { + if (agents[i].is_plugin() != is_plugin) + continue; + const int item = combo->Append(_(agents[i].display_name)); + // why: carry the agent-id string on the row. alias is an owned wxString (auto-freed, never rendered) + combo->SetItemAlias(item, from_u8(agents[i].id)); + } + }; + + // append rows + if (has_builtin_agents) + { + combo->Append(_L("System agents"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM | DD_ITEM_STYLE_DISABLED); + append_agent_rows(false); // append rows for agents that are not plugins + } + if (has_plugin_agents) + { + combo->Append(_L("Plugins"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM | DD_ITEM_STYLE_DISABLED); + append_agent_rows(true); // append rows for agents that are plugins + } +} + +void PrinterAgentChoice::BUILD() +{ + wxSize size(def_width_wider() * m_em_unit, wxDefaultCoord); + if (m_opt.height >= 0) size.SetHeight(m_opt.height * m_em_unit); + if (m_opt.width >= 0) size.SetWidth(m_opt.width * m_em_unit); + + static Builder builder; + choice_ctrl* temp = builder.build(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr, + wxCB_READONLY); + temp->Clear(); + temp->GetDropDown().SetUseContentWidth(true); + if (parent_is_custom_ctrl && m_opt.height < 0) + opt_height = (double)temp->GetTextCtrl()->GetSize().GetHeight() / m_em_unit; + temp->SetTextLabel(_L(m_opt.sidetext)); + m_combine_side_text = true; +#ifdef __WXGTK3__ + wxSize best_sz = temp->GetBestSize(); + if (best_sz.x > size.x) temp->SetSize(best_sz); +#endif + if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT); + + window = dynamic_cast(temp); + + reload_rows(); + + temp->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { on_change_field(); }, temp->GetId()); + temp->SetToolTip(get_tooltip_text(temp->GetValue())); +} + +// Resolve CONFIG id string to a matching row in the live REGISTRY. "" uses the vendor default. +// An unregistered id clears selection and shows " (missing)" as free text. +void PrinterAgentChoice::set_value(const std::string& value, bool change_event) +{ + m_disable_change_event = !change_event; + + auto* field = dynamic_cast(window); + + // check if any row's corresponding id matches the agent id we are attempting to set + const std::string effective_agent_id = wxGetApp().resolve_printer_agent_id(value); + const unsigned int count = field->GetCount(); + int match = wxNOT_FOUND; + for (unsigned int i = 0; i < count; ++i) + { + if (into_u8(field->GetItemAlias(i)) == effective_agent_id) // if alias == id + { + match = static_cast(i); + break; + } + } + + // based on match or not, set selection and value + // - SetSelection and SetValue are UI to manipulate the display of the ComboBox + // - SetSelection automatically calls SetValue for the same value + // - we can also SetValue separately from SetSelection + if (match == wxNOT_FOUND) + { + field->SetSelection(wxNOT_FOUND); // nothing shows as selected in the dropdown + field->SetValue(from_u8(value + " (missing)")); // set a value not in the selection (upper display field) + } + else + { + // display name of agent shows both in upper display field and appears selected in dropdown + field->SetSelection(match); + } + + m_disable_change_event = false; +} + +// Accept boost::any values from callers (usually to OptionsGroup/Field parent classes) and normalize them to an agent id. +// Then use PrinterAgentChoice::set_value(std::string& value, ...) +void PrinterAgentChoice::set_value(const boost::any& value, bool change_event) +{ + m_disable_change_event = !change_event; + + auto* field = dynamic_cast(window); + if (value.empty()) + { + field->SetValue(""); + m_value = value; + m_disable_change_event = false; + return; + } + + std::string id; + if (const std::string* s = boost::any_cast(&value)) + id = *s; + else if (const wxString* w = boost::any_cast(&value)) + id = into_u8(*w); + set_value(id, change_event); +} + +// A real row returns its alias, which is the agent id. Header rows, missing rows, +// and no selection return empty boost::any so the custom writer leaves config unchanged. +boost::any& PrinterAgentChoice::get_value() +{ + auto* field = dynamic_cast(window); + const int sel = field->GetSelection(); + const std::string id = sel < 0 ? std::string{} : into_u8(field->GetItemAlias(sel)); + if (id.empty()) + m_value = boost::any{}; + else + m_value = id; + return m_value; +} + +void PrinterAgentChoice::enable() { dynamic_cast(window)->Enable(); } +void PrinterAgentChoice::disable() { dynamic_cast(window)->Disable(); } + +void PrinterAgentChoice::msw_rescale() +{ + Field::msw_rescale(); + + auto* field = dynamic_cast(window)->GetTextCtrl(); + wxSize size(wxDefaultSize); + size.SetWidth((m_opt.width > 0 ? m_opt.width : def_width_wider()) * m_em_unit); + field->SetMinSize(wxSize(-1, int(1.5f * field->GetFont().GetPixelSize().y + 0.5f))); + field->SetSize(size); + + dynamic_cast(window)->Rescale(); +} + void PluginField::BUILD() { auto* panel = new wxPanel(m_parent, wxID_ANY); diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index 4e9c65da5d..e57a569561 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -469,6 +469,44 @@ public: void suppress_scroll(); }; +// printer_agent is a coString whose choices come from the live agent registry. +// PrinterAgentChoice uses a ComboBox directly because Choice expects static config enums. +// Real rows carry the stored agent id in the row alias (SetItemAlias/GetItemAlias). +class PrinterAgentChoice : public Field +{ + using Field::Field; + +public: + PrinterAgentChoice(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) + { + } + + PrinterAgentChoice(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field( + parent, opt, id) + { + } + + ~PrinterAgentChoice() + { + } + + wxWindow* window{nullptr}; + + void BUILD() override; + // Clear and repopulate rows from the live registry (grouped System agents / Plugins). + // Does not change selection; the caller follows with set_value(stored id). + void reload_rows(); + + void set_value(const std::string& value, bool change_event = false); + void set_value(const boost::any& value, bool change_event = false) override; + boost::any& get_value() override; + + void enable() override; + void disable() override; + void msw_rescale() override; + wxWindow* getWindow() override { return window; } +}; + class PluginField : public Field { using Field::Field; public: diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 20bcb109e1..b882117aae 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -1134,8 +1134,9 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const if (current_top_layer_only != required_top_layer_only) m_viewer.toggle_top_layer_only_view_range(); - // ORCA: darken layers below the current one while scrubbing the preview (ported from preFlight) + // ORCA: darken the layers the preview layer slider is not scrubbed to m_viewer.set_dim_previous_layers(get_app_config()->get_bool("preview_dim_previous_layers")); + m_viewer.set_dim_previous_layers_brightness(0.01f * std::stoi(get_app_config()->get("preview_dim_previous_layers_brightness"))); // avoid processing if called with the same gcode_result if (m_last_result_id == gcode_result.id && wxGetApp().is_editor()) { diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 570c688987..a19f7bb9ae 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -333,9 +333,12 @@ public: libvgcode::EViewType get_view_type() const { return m_viewer.get_view_type(); } - // ORCA: darken layers below the current top layer while scrubbing the preview (ported from preFlight) + // ORCA: darken the layers not scrubbed to while using the preview layer slider void set_dim_previous_layers(bool value) { m_viewer.set_dim_previous_layers(value); } bool is_dim_previous_layers() const { return m_viewer.is_dim_previous_layers(); } + // ORCA: brightness of those darkened layers, 1.0 = unchanged, 0.0 = black + void set_dim_previous_layers_brightness(float value) { m_viewer.set_dim_previous_layers_brightness(value); } + float get_dim_previous_layers_brightness() const { return m_viewer.get_dim_previous_layers_brightness(); } void set_layers_z_range(const std::array& layers_z_range); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f39761f0ec..a51a10296c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1842,6 +1842,10 @@ void GLCanvas3D::enable_separator_toolbar(bool enable) m_separator_toolbar.set_enabled(enable); } +bool GLCanvas3D::has_mouse_capture() const { + return m_canvas != nullptr && m_canvas->HasCapture(); +} + void GLCanvas3D::zoom_to_bed() { BoundingBoxf3 box = m_bed.build_volume().bounding_volume(); @@ -2182,7 +2186,7 @@ void GLCanvas3D::render(bool only_init) // Negative coordinate means out of the window, likely because the window was deactivated. // In that case the tooltip should be hidden. - if (m_mouse.position.x() >= 0. && m_mouse.position.y() >= 0.) { + if (m_mouse.position.x() >= 0. && m_mouse.position.y() >= 0. || has_mouse_capture()) { // ORCA continue to capture mouse pos mid drag if (tooltip.empty()) tooltip = m_layers_editing.get_tooltip(*this); @@ -2867,6 +2871,9 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re } if (wt && (need_wipe_tower || filaments_count > 1) && !wxGetApp().plater()->only_gcode_mode() && !wxGetApp().plater()->is_gcode_3mf()) { + // The tower size estimate reads printer- and filament-scope keys, which the print preset + // does not carry; built once here rather than per plate. + const DynamicPrintConfig full_config = wxGetApp().preset_bundle->full_config(); for (int plate_id = 0; plate_id < n_plates; plate_id++) { // If print ByObject and there is only one object in the plate, the wipe tower is allowed to be generated. PartPlate* part_plate = ppl.get_plate(plate_id); @@ -2891,51 +2898,26 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (part_plate->get_objects_on_this_plate().empty()) continue; float brim_width = print->wipe_tower_data(filaments_count).brim_width; - const DynamicPrintConfig &print_cfg = wxGetApp().preset_bundle->prints.get_edited_preset().config; int nozzle_nums = wxGetApp().preset_bundle->get_printer_extruder_count(); - Vec3d wipe_tower_size = ppl.get_plate(plate_id)->estimate_wipe_tower_size(print_cfg, w, v, nozzle_nums, 0, false, dynamic_cast(dconfig.option("enable_wrapping_detection"))->value); + Vec3d wipe_tower_size = ppl.get_plate(plate_id)->estimate_wipe_tower_size(full_config, w, v, nozzle_nums, 0, false, dynamic_cast(dconfig.option("enable_wrapping_detection"))->value); - { - const float margin = WIPE_TOWER_MARGIN + brim_width; - BoundingBoxf3 plate_bbox = part_plate->get_bounding_box(); - BoundingBoxf plate_bbox_2d(Vec2d(plate_bbox.min(0), plate_bbox.min(1)), Vec2d(plate_bbox.max(0), plate_bbox.max(1))); - const std::vector &extruder_areas = part_plate->get_extruder_areas(); - for (Pointfs points : extruder_areas) { - BoundingBoxf bboxf(points); - plate_bbox_2d.min = plate_bbox_2d.min(0) >= bboxf.min(0) ? plate_bbox_2d.min : bboxf.min; - plate_bbox_2d.max = plate_bbox_2d.max(0) <= bboxf.max(0) ? plate_bbox_2d.max : bboxf.max; - } - - coordf_t plate_bbox_x_min_local_coord = plate_bbox_2d.min(0) - plate_origin(0); - coordf_t plate_bbox_x_max_local_coord = plate_bbox_2d.max(0) - plate_origin(0); - coordf_t plate_bbox_y_max_local_coord = plate_bbox_2d.max(1) - plate_origin(1); - - if (!current_print->is_step_done(psWipeTower) || !current_print->wipe_tower_data().wipe_tower_mesh_data) { - // update for wipe tower position - { - int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(1000 + plate_id, x + plate_origin(0), y + plate_origin(1), - (float) wipe_tower_size(0), (float) wipe_tower_size(1), (float) wipe_tower_size(2), - a, - /*!print->is_step_done(psWipeTower)*/ true, brim_width); - int volume_idx_wipe_tower_old = volume_idxs_wipe_tower_old[plate_id]; - if (volume_idx_wipe_tower_old != -1) map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new; - } - } else { - const float margin = 2.f; - auto tower_bottom = current_print->wipe_tower_data().wipe_tower_mesh_data->bottom; - tower_bottom.translate(scaled(Vec2d{x, y})); - tower_bottom.translate(scaled(Vec2d{plate_origin[0], plate_origin[1]})); - auto tower_bottom_bbox = get_extents(tower_bottom); - BoundingBoxf3 plate_bbox = wxGetApp().plater()->get_partplate_list().get_plate(plate_id)->get_build_volume(true); - BoundingBox plate_bbox2d = BoundingBox(scaled(Vec2f(plate_bbox.min[0], plate_bbox.min[1])), scaled(Vec2f(plate_bbox.max[0], plate_bbox.max[1]))); - Vec2f offset = WipeTower::move_box_inside_box(tower_bottom_bbox, plate_bbox2d, scaled(margin)); - int volume_idx_wipe_tower_new = m_volumes.load_real_wipe_tower_preview(1000 + plate_id, x + plate_origin(0), y + plate_origin(1), - current_print->wipe_tower_data().wipe_tower_mesh_data->real_wipe_tower_mesh, - current_print->wipe_tower_data().wipe_tower_mesh_data->real_brim_mesh, - true,a,/*!print->is_step_done(psWipeTower)*/ true, m_initialized); - int volume_idx_wipe_tower_old = volume_idxs_wipe_tower_old[plate_id]; - if (volume_idx_wipe_tower_old != -1) map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new; - } + // The stored position is already clamped onto the bed, by + // set_default_wipe_tower_pos_for_plate and again on every drag. + if (!current_print->is_step_done(psWipeTower) || !current_print->wipe_tower_data().wipe_tower_mesh_data) { + // update for wipe tower position + int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(1000 + plate_id, x + plate_origin(0), y + plate_origin(1), + (float) wipe_tower_size(0), (float) wipe_tower_size(1), (float) wipe_tower_size(2), + a, + /*!print->is_step_done(psWipeTower)*/ true, brim_width); + int volume_idx_wipe_tower_old = volume_idxs_wipe_tower_old[plate_id]; + if (volume_idx_wipe_tower_old != -1) map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new; + } else { + int volume_idx_wipe_tower_new = m_volumes.load_real_wipe_tower_preview(1000 + plate_id, x + plate_origin(0), y + plate_origin(1), + current_print->wipe_tower_data().wipe_tower_mesh_data->real_wipe_tower_mesh, + current_print->wipe_tower_data().wipe_tower_mesh_data->real_brim_mesh, + true,a,/*!print->is_step_done(psWipeTower)*/ true, m_initialized); + int volume_idx_wipe_tower_old = volume_idxs_wipe_tower_old[plate_id]; + if (volume_idx_wipe_tower_old != -1) map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new; } } } @@ -4170,6 +4152,23 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // BBS: single snapshot Plater::SingleSnapshot single(wxGetApp().plater()); +#ifdef __WXMAC__ + // On macOS, the mouse key state is only present for mouse btn related events such as wxEVT_LEFT_DOWN. + // For other events, all buttons are reported as non-pressed, such as window leaving event. This causes + // imgui stopped responding if cursor moved out of window, such as + // https://github.com/OrcaSlicer/OrcaSlicer/pull/14999#issuecomment-5151344759 + // We solve this by correcting the state of the event from the actual mouse state querying with `wxGetMouseState()` + // so it works like on other platforms. + { + const auto state = wxGetMouseState(); + evt.SetLeftDown(state.LeftIsDown()); + evt.SetMiddleDown(state.MiddleIsDown()); + evt.SetRightDown(state.RightIsDown()); + evt.SetAux1Down(state.Aux1IsDown()); + evt.SetAux2Down(state.Aux2IsDown()); + } +#endif + #if ENABLE_RETINA_GL const float scale = m_retina_helper->get_scale_factor(); evt.SetX(evt.GetX() * scale); @@ -4183,11 +4182,27 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // ignore left up events coming from imgui windows and not processed by them m_mouse.ignore_left_up = true; m_tooltip.set_in_imgui(false); - if (imgui->update_mouse_data(evt)) { + + // while a non-ImGui drag is already in progress (gizmo grabber, object move, rectangle selection, layer editing), + // don't let ImGui/ImGuizmo claim the event just because the cursor is hovering something like the navigator cube + // that incorrectly suppresses the active drag's tooltip and can interrupt its processing. The active drag always takes priority. + const bool other_drag_active = m_gizmos.is_dragging() || m_mouse.dragging || m_rectangle_selection.is_dragging() || m_layers_editing.state == LayersEditing::Editing; + + if (imgui->update_mouse_data(evt) && !other_drag_active) { if ((evt.LeftDown() || (evt.Moving() && (evt.AltDown() || evt.ShiftDown()))) && m_canvas != nullptr) m_canvas->SetFocus(); m_mouse.position = evt.Leaving() ? Vec2d(-1.0, -1.0) : pos.cast(); m_tooltip.set_in_imgui(true); + + // ORCA keep tracking mouse position while drag active and cursor not in window bounds + const bool imgui_dragging_active = (GImGui != nullptr && ImGui::GetIO().MouseDown[0] && GImGui->ActiveId != 0) || m_navigator_dragging; + if (!has_mouse_capture() && imgui_dragging_active) + m_canvas->CaptureMouse(); + + // release capture as soon as the button goes up + if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) + mouse_up_cleanup(); + render(); #ifdef SLIC3R_DEBUG_MOUSE_EVENTS printf((format_mouse_event_debug_message(evt) + " - Consumed by ImGUI\n").c_str()); @@ -4284,6 +4299,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_main_toolbar.on_mouse(evt2, *this); } + // ORCA keep tracking mouse position while drag active and cursor not in window bounds + if (!has_mouse_capture() && evt.LeftIsDown() && m_gizmos.is_dragging()) + m_canvas->CaptureMouse(); + if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) mouse_up_cleanup(); @@ -4389,6 +4408,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // Start editing the layer height. m_layers_editing.state = LayersEditing::Editing; _perform_layer_editing_action(&evt); + + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); } else { @@ -4402,6 +4424,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) && m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation && m_gizmos.get_current_type() != GLGizmosManager::FuzzySkin) { m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect); + + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); + m_dirty = true; } } @@ -4469,6 +4495,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.drag.start_position_3D = m_mouse.scene_position; m_sequential_print_clearance_first_displacement = true; m_moving = true; + + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); } } } @@ -4477,6 +4506,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } else if (evt.Dragging() && evt.LeftIsDown() && m_mouse.drag.move_volume_idx != -1 && m_layers_editing.state == LayersEditing::Unknown) { if (m_canvas_type != ECanvasType::CanvasAssembleView) { + + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); + if (!m_mouse.drag.move_requires_threshold) { m_mouse.dragging = true; Vec3d cur_pos = m_mouse.drag.start_position_3D; @@ -4528,6 +4561,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) else if (evt.Dragging() && evt.LeftIsDown() && m_picking_enabled && m_rectangle_selection.is_dragging()) { //BBS not in assemble view if (m_canvas_type != ECanvasType::CanvasAssembleView) { + + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); + m_rectangle_selection.dragging(pos.cast()); m_dirty = true; } @@ -4537,12 +4574,19 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (m_layers_editing.state != LayersEditing::Unknown && layer_editing_object_idx != -1) { if (m_layers_editing.state == LayersEditing::Editing) { + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); + _perform_layer_editing_action(&evt); m_mouse.position = pos.cast(); } } // do not process the dragging if the left mouse was set down in another canvas else if (is_camera_rotate(evt, button_mappings)) { + + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); + // Orca: Sphere rotation for painting view // if dragging over blank area with left button or other button mapped to rotate, then rotate bool middle_or_right_button_used_as_rotate = (evt.MiddleIsDown() && button_mappings[MouseButton::Middle] == MouseAction::Rotation) || @@ -4622,6 +4666,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.drag.start_position_3D = Vec3d((double)pos(0), (double)pos(1), 0.0); } else if (is_camera_pan(evt, button_mappings)) { + + if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds + m_canvas->CaptureMouse(); + // if dragging with right button or if button functions swapped and dragging with left button over blank area then pan if (m_mouse.is_start_position_2D_defined()) { // get point in model space at Z = 0 @@ -4686,7 +4734,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) deselect_all(); } //BBS Select plate in this 3D canvas. - else if (evt.LeftUp() && !m_mouse.dragging && m_picking_enabled && !m_hover_plate_idxs.empty() && (m_canvas_type == CanvasView3D) && !is_layers_editing_enabled()) + // The left up may come from an ImGui window (e.g. a drag started on the gizmo floating window and released over the bed), + // in which case it must not be treated as a click on the plate, otherwise the gizmo would be closed (see deselect_all below). + else if (evt.LeftUp() && !m_mouse.ignore_left_up && !m_mouse.dragging && m_picking_enabled && !m_hover_plate_idxs.empty() && (m_canvas_type == CanvasView3D) && !is_layers_editing_enabled()) { int hover_idx = m_hover_plate_idxs.front(); wxGetApp().plater()->select_plate_by_hover_id(hover_idx); @@ -6033,9 +6083,18 @@ void GLCanvas3D::_render_3d_navigator() { if (!wxGetApp().show_3d_navigator()) { m_canvas_toolbar_pos[0] = 0; + m_navigator_dragging = false; return; } + // Fix stealing capture event from other drag events + const bool other_drag_active = !m_navigator_dragging && (m_moving || m_rectangle_selection.is_dragging() || m_gizmos.is_dragging() || m_layers_editing.state == LayersEditing::Editing); + + ImGuiIO& io = ImGui::GetIO(); + const bool saved_mouse_down0 = io.MouseDown[0]; + if (other_drag_active) + io.MouseDown[0] = false; + ImGuizmo::BeginFrame(); auto& style = ImGuizmo::GetStyle(); @@ -6060,7 +6119,6 @@ void GLCanvas3D::_render_3d_navigator() sc *= (float) dpi / (float) DPI_DEFAULT; #endif // WIN32 - const ImGuiIO& io = ImGui::GetIO(); const float viewManipulateLeft = 0; const float viewManipulateTop = io.DisplaySize.y; const float camDistance = 8.f; @@ -6084,6 +6142,10 @@ void GLCanvas3D::_render_3d_navigator() camDistance, ImVec2(viewManipulateLeft, viewManipulateTop - size), ImVec2(size, size), 0x00101010); + // Restore the real mouse-down state + if (other_drag_active) + io.MouseDown[0] = saved_mouse_down0; + if (result.changed) { for (unsigned int c = 0; c < 4; ++c) { for (unsigned int r = 0; r < 4; ++r) { @@ -6115,6 +6177,8 @@ void GLCanvas3D::_render_3d_navigator() request_extra_frame(); } + + m_navigator_dragging = result.dragging; } #define ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT 0 @@ -6913,7 +6977,7 @@ void GLCanvas3D::_update_select_plate_toolbar_stats_item(bool force_selected) { else m_sel_plate_toolbar.show_stats_item = false; - if (force_selected && m_sel_plate_toolbar.show_stats_item) + if (force_selected && m_sel_plate_toolbar.show_stats_item && m_sel_plate_toolbar.m_all_plates_stats_item) m_sel_plate_toolbar.m_all_plates_stats_item->selected = true; } @@ -9226,8 +9290,12 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar() //ORCA ImGui::IsWindowHovered() returns false when left_down events on buttons that causes scrollbar disappears for a short time auto win_pos = ImGui::GetWindowPos(); - bool is_win_hovered = ImGui::IsMouseHoveringRect(win_pos, win_pos + ImVec2(window_width + (show_scroll ? scrollbar_size : 0), window_height), !show_scroll); // use non clipped rectangle to reserve clickable area for scrollbar track - m_sel_plate_toolbar.is_display_scrollbar = is_win_hovered; + bool is_win_hovered = ImGui::IsMouseHoveringRect(win_pos, win_pos + ImVec2(window_width + (show_scroll ? scrollbar_size : 0), window_height), !show_scroll); + + // Also show scrollbar visible and continue to capture mouse position + const bool is_scrollbar_active_drag = GImGui != nullptr && ImGui::GetIO().MouseDown[0] && GImGui->ActiveId != 0 && GImGui->ActiveIdWindow == ImGui::GetCurrentWindow(); + + m_sel_plate_toolbar.is_display_scrollbar = is_win_hovered || is_scrollbar_active_drag; imgui.end(); } @@ -10534,9 +10602,8 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) wxString region = L"en"; if (language.find("zh") == 0) region = L"zh"; - // Use the generic dual-nozzle PLA+PETG guide rather than the H2D-specific page - // so the link is relevant for all dual-extrusion printers, not just Bambu H2D. (#12073) - wxGetApp().open_browser_with_warning_dialog(wxString::Format(L"https://wiki.bambulab.com/%s/filament-acc/filament/pla-and-petg-dual-extrusion", region)); + // Although this link looks like it's only for the H2D, its guidance is generic. + wxGetApp().open_browser_with_warning_dialog(wxString::Format(L"https://wiki.bambulab.com/%s/filament-acc/filament/h2d-pla-and-petg-mutual-support", region)); return false; }); } @@ -10670,24 +10737,14 @@ bool GLCanvas3D::is_flushing_matrix_error() { if (!Sidebar::should_show_SEMM_buttons()) return false; + std::vector plate_extruders = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_extruders(true); + if (plate_extruders.size() < 2) + return false; + const auto &project_config = wxGetApp().preset_bundle->project_config; const std::vector &config_matrix = (project_config.option("flush_volumes_matrix"))->values; const std::vector &config_multiplier = (project_config.option("flush_multiplier"))->values; - - for (auto multiplier : config_multiplier) { - if (multiplier == 0) return true; - } - - int matrix_len = config_matrix.size() / config_multiplier.size(); - int row_len = std::sqrt(matrix_len); - for (int i = 0; i < config_matrix.size(); i++) - { - int relative_id = i % matrix_len; - int row_id = relative_id / row_len; - int col_id = relative_id % row_len; - if (row_id != col_id && config_matrix[i] == 0) return true; - } - return false; + return has_zero_flush_volume_for_used_filaments(config_matrix, config_multiplier, plate_extruders); } bool GLCanvas3D::_is_any_volume_outside() const diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 84cf311e57..17497edf16 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -589,6 +589,7 @@ private: bool m_toolpath_outside{ false }; ECursorType m_cursor_type; GLSelectionRectangle m_rectangle_selection; + bool m_navigator_dragging{ false }; //BBS:add plate related logic mutable std::vector m_hover_volume_idxs; @@ -916,6 +917,7 @@ public: void update_volumes_colors_by_extruder(); bool is_dragging() const { return m_gizmos.is_dragging() || m_moving; } + bool has_mouse_capture() const; void render(bool only_init = false); bool is_rendering_enabled() @@ -1117,6 +1119,10 @@ public: void set_mouse_as_dragging() { m_mouse.dragging = true; } bool is_mouse_dragging() const { return m_mouse.dragging; } + // True when the current left up event comes from an ImGui window and was not processed by it + // (e.g. a drag that started on a gizmo floating window and was released over the 3D scene). + // Such a release is the end of an ImGui interaction, not a click on the scene. + bool is_mouse_left_up_ignored() const { return m_mouse.ignore_left_up; } double get_size_proportional_to_max_bed_size(double factor) const; diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 554ecd4a4e..29f8fc9749 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -256,18 +256,18 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt } } -void show_error(wxWindow* parent, const wxString& message, bool monospaced_font) +void show_error(wxWindow* parent, const wxString& message, bool has_code_excerpts) { wxGetApp().CallAfter([=] { - ErrorDialog msg(parent, message, monospaced_font); + ErrorDialog msg(parent, message, has_code_excerpts); msg.ShowModal(); }); } -void show_error(wxWindow* parent, const char* message, bool monospaced_font) +void show_error(wxWindow* parent, const char* message, bool has_code_excerpts) { assert(message); - show_error(parent, wxString::FromUTF8(message), monospaced_font); + show_error(parent, wxString::FromUTF8(message), has_code_excerpts); } void show_error_id(int id, const std::string& message) diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp index 357fd20a97..db882b79cf 100644 --- a/src/slic3r/GUI/GUI.hpp +++ b/src/slic3r/GUI/GUI.hpp @@ -40,11 +40,11 @@ extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_ // Change option value in config void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0); -// If monospaced_font is true, the error message is displayed using html
tags, -// so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser. -void show_error(wxWindow* parent, const wxString& message, bool monospaced_font = false); -void show_error(wxWindow* parent, const char* message, bool monospaced_font = false); -inline void show_error(wxWindow* parent, const std::string& message, bool monospaced_font = false) { show_error(parent, message.c_str(), monospaced_font); } +// If has_code_excerpts is true, code excerpts (a source line and the caret line below it) render +// monospaced so the caret aligns. Used for placeholder-parser errors. +void show_error(wxWindow* parent, const wxString& message, bool has_code_excerpts = false); +void show_error(wxWindow* parent, const char* message, bool has_code_excerpts = false); +inline void show_error(wxWindow* parent, const std::string& message, bool has_code_excerpts = false) { show_error(parent, message.c_str(), has_code_excerpts); } void show_error_id(int id, const std::string& message); // For Perl void show_info(wxWindow* parent, const wxString& message, const wxString& title = wxString()); void show_info(wxWindow* parent, const char* message, const char* title = nullptr); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 07e99348bb..db51bd9d8e 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -307,6 +307,20 @@ public: #endif // !__APPLE__ ) { + // Some desktop environments ignore splash screen typed window properties + // when running the app through Wayland,resulting in the titlebar being shown + // on the splash screen. The code below creates a client-side window decoration + // when running on Wayland and then removes that decoration. This ensures every + // environment correctly targets and removes the titlebar for this screen. + #if defined(__WXGTK__) + if (Slic3r::GUI::is_running_on_wayland()) { + GtkWidget *empty = gtk_fixed_new(); + gtk_widget_set_size_request(empty, 0, 0); + gtk_window_set_titlebar(GTK_WINDOW(GetHandle()), empty); + gtk_window_set_decorated(GTK_WINDOW(GetHandle()), false); + } + #endif + this->SetPosition(pos); this->CenterOnScreen(); @@ -2152,7 +2166,6 @@ void GUI_App::init_networking_callbacks() obj->is_tunnel_mqtt = tunnel; obj->command_request_push_all(true); obj->command_get_version(); - obj->erase_user_access_code(); obj->command_get_access_code(); if (m_agent) m_agent->install_device_cert(obj->get_dev_id(), obj->is_lan_mode_printer()); @@ -2202,7 +2215,6 @@ void GUI_App::init_networking_callbacks() wxString text; if (msg == "5") { obj->set_access_code(""); - obj->erase_user_access_code(); text = wxString::Format(_L("Incorrect password")); wxGetApp().show_dialog(text); } else { @@ -2795,16 +2807,58 @@ void GUI_App::init_plugin_gui_wiring() }); }; + // why: a newly loaded plugin only adds a selectable agent + // refresh the dropdown and leave the live agent alone + auto refresh_printer_agent_dropdown_after_load = [](const std::string&) + { + if (!wxTheApp) + return; + + GUI_App* app = &GUI::wxGetApp(); + if (app->is_closing()) + return; + + app->CallAfter([app] + { + if (!app->is_closing()) + app->refresh_printer_agent_dropdown(); + }); + }; + + // why: the unloaded plugin may have been the provider of the live agent + // re-run selection, where a now-missing agent will be cleared + // refresh dropdown after + auto switch_printer_agent_after_unload = [](const std::string&) + { + if (!wxTheApp) + return; + + GUI_App* app = &GUI::wxGetApp(); + if (app->is_closing()) + return; + + app->CallAfter([app] { + if (app->is_closing()) + return; + + app->switch_printer_agent(); + app->refresh_printer_agent_dropdown(); + }); + }; + plugin_mgr.subscribe_on_unload_callback(PluginHostUi::close_windows_for_plugin); plugin_mgr.subscribe_on_load_callback([refresh_plugins_dialog](const std::string&) { refresh_plugins_dialog(); }); plugin_mgr.subscribe_on_unload_callback([refresh_plugins_dialog](const std::string&) { refresh_plugins_dialog(); }); plugin_mgr.subscribe_on_load_callback(NetworkAgentFactory::register_python_plugin); plugin_mgr.subscribe_on_unload_callback(NetworkAgentFactory::deregister_python_plugin); + plugin_mgr.subscribe_on_load_callback(refresh_printer_agent_dropdown_after_load); + plugin_mgr.subscribe_on_unload_callback(switch_printer_agent_after_unload); plugin_mgr.subscribe_on_capability_load_callback( - [refresh_plugins_dialog](const PluginCapabilityId& capability) { + [refresh_plugins_dialog, refresh_printer_agent_dropdown_after_load](const PluginCapabilityId& capability) { if (capability.type == PluginCapabilityType::PrinterConnection) NetworkAgentFactory::register_python_printer_agent(capability.plugin_key, capability.name); refresh_plugins_dialog(); + refresh_printer_agent_dropdown_after_load(capability.plugin_key); // A newly loaded capability may satisfy a missing-plugin notification; re-validate the // current plate (on the UI thread) so the notification clears once its plugin is available. if (wxTheApp && !wxGetApp().is_closing()) @@ -2814,10 +2868,11 @@ void GUI_App::init_plugin_gui_wiring() }); }); plugin_mgr.subscribe_on_capability_unload_callback( - [refresh_plugins_dialog](const PluginCapabilityId& capability) { + [refresh_plugins_dialog, switch_printer_agent_after_unload](const PluginCapabilityId& capability) { if (capability.type == PluginCapabilityType::PrinterConnection) NetworkAgentFactory::deregister_python_printer_agent(capability.plugin_key, capability.name); refresh_plugins_dialog(); + switch_printer_agent_after_unload(capability.plugin_key); }); } @@ -3859,6 +3914,48 @@ unsigned GUI_App::get_colour_approx_luma(const wxColour &colour) )); } +void GUI_App::refresh_printer_agent_dropdown() +{ + if (Tab* tab = get_tab(Preset::TYPE_PRINTER)) + { + if (auto* printer_tab = dynamic_cast(tab)) + printer_tab->refresh_printer_agent_dropdown(); + } +} + +void GUI_App::set_live_printer_agent(std::shared_ptr agent) +{ + if (!m_agent) + return; + + // why: tearing down the old machine selection is only ever the prefix of setting the live + // agent (to a new one, or to null when the selection is missing) - so it lives here, not as + // a standalone helper. Pass nullptr to clear the selection. + if (DeviceManager* dev = getDeviceManager()) + { + dev->set_selected_machine(""); // why: empty id disconnects and deselects the current machine + m_agent->set_user_selected_machine(""); + // note: belt-and-suspenders (precedent: DeviceManagerRefresher::on_timer) + dev->OnSelectedMachineLost(); // why: clear stale sidebar sync-status / AMS + dev->clear_other_devices(); // why: drop stale LAN discoveries; keep My Devices + } + + m_agent->set_printer_agent(agent); + sidebar().update_all_preset_comboboxes(); +} + +std::string GUI_App::resolve_printer_agent_id(const std::string& stored_id) +{ + if (!stored_id.empty()) + return stored_id; + return (preset_bundle && preset_bundle->is_bbl_vendor()) ? BBL_PRINTER_AGENT_ID : ORCA_PRINTER_AGENT_ID; +} + +std::string GUI_App::canonical_printer_agent_id(const std::string& picked_id) +{ + return picked_id == resolve_printer_agent_id("") ? std::string() : picked_id; +} + void GUI_App::switch_printer_agent() { if (!m_agent) { @@ -3866,24 +3963,17 @@ void GUI_App::switch_printer_agent() return; } - // Read printer_agent from config, falling back to default - std::string effective_agent_id = ORCA_PRINTER_AGENT_ID; - if (preset_bundle->is_bbl_vendor()) - effective_agent_id = BBL_PRINTER_AGENT_ID; - const DynamicPrintConfig& config = preset_bundle->printers.get_edited_preset().config; - if (config.has("printer_agent")) { - const std::string& value = config.option("printer_agent")->value; - if (!value.empty()) - effective_agent_id = value; - } + const std::string effective_agent_id = resolve_printer_agent_id(config.opt_string("printer_agent")); // Check if agent is registered const PrinterAgentInfo* agent_info_ptr = NetworkAgentFactory::get_printer_agent_info(effective_agent_id); if (!agent_info_ptr) { - BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": unregistered agent ID '" << effective_agent_id - << "', keeping current agent"; - // Keep current agent, don't switch + // why: the selected agent's provider is gone (e.g. plugin unloaded); leaving the old + // live agent up would keep talking to a machine the user can no longer select. + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": agent ID '" << effective_agent_id + << "' is unregistered; clearing live printer agent"; + set_live_printer_agent(nullptr); return; } const PrinterAgentInfo agent_info = *agent_info_ptr; @@ -3897,7 +3987,9 @@ void GUI_App::switch_printer_agent() NetworkAgentFactory::create_printer_agent_by_id(effective_agent_id, cloud_agent, log_dir); if (!new_printer_agent) { - BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": failed to create agent '" << effective_agent_id << "', keeping current agent"; + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": failed to create agent '" << effective_agent_id + << "'; clearing live printer agent"; + set_live_printer_agent(nullptr); return; } @@ -3920,9 +4012,9 @@ void GUI_App::switch_printer_agent() return; } - // Swap the agent - m_agent->set_printer_agent(new_printer_agent); - sidebar().update_all_preset_comboboxes(); + // Swap the agent; set_live_printer_agent resets the device selection so the new + // agent starts clean (#124). + set_live_printer_agent(new_printer_agent); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": printer agent switched to " << effective_agent_id; @@ -8192,7 +8284,7 @@ bool GUI_App::show_modal_ip_address_enter_dialog(bool input_sn, wxString title) wxGetApp().app_config->save(); obj->set_dev_ip(ip_address.ToStdString()); - obj->set_user_access_code(access_code.ToStdString()); + obj->set_access_code(access_code.ToStdString()); } } }); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index bda27d40ec..8bf32df64c 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -365,9 +365,14 @@ public: HMSQuery* get_hms_query() { return hms_query; } NetworkAgent* getAgent() { return m_agent; } - // Dynamic printer agent switching + // Reconcile the live printer agent with the stored preset selection. void switch_printer_agent(); + std::string resolve_printer_agent_id(const std::string& stored_id); + // ORCA TODO: in the future, bbl presets should specify "bbl" printer agent id + // then, all resolve and canonical would just be ORCA<->"" + std::string canonical_printer_agent_id(const std::string& picked_id); + FilamentColorCodeQuery* get_filament_color_code_query(); bool is_editor() const { return m_app_mode == EAppMode::Editor; } bool is_gcode_viewer() const { return m_app_mode == EAppMode::GCodeViewer; } @@ -798,6 +803,11 @@ private: void window_pos_center(wxTopLevelWindow *window); bool select_language(); + // Dynamic printer agent selection - internal helpers for switch_printer_agent + // and the plugin load/unload callbacks (init_plugin_gui_wiring). + void refresh_printer_agent_dropdown(); + void set_live_printer_agent(std::shared_ptr agent); // null clears the selection + bool config_wizard_startup(); void check_updates(const bool verbose); diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index a4a60ac4bd..5254492e5d 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -123,6 +123,7 @@ std::map> SettingsFactory::PART_CATE {"sparse_infill_density", "", 1}, {"fill_multiline", "", 1}, {"sparse_infill_pattern", "", 1}, + {"sparse_infill_smooth_factor", "", 1}, {"lateral_lattice_angle_1", "", 1}, {"lateral_lattice_angle_2", "", 1}, {"infill_overhang_angle", "", 1}, diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index b23b554a74..dc89f5f9bb 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -3213,7 +3213,7 @@ void ObjectList::merge(bool to_multipart_object) //changed_object(obj_idx); //remove(); } - /* wxGetApp().plater()->load_model_objects(objects); + // wxGetApp().plater()->load_model_objects(objects); Selection& selection = p->view3D->get_canvas3d()->get_selection(); size_t last_obj_idx = p->model.objects.size() - 1; diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 65cd99a2fa..25e6204a40 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -139,7 +139,7 @@ bool ObjectSettings::update_settings_list() optgroup->sidetext_width = 5; optgroup->m_on_change = [this, config](const t_config_option_key& opt_id, const boost::any& value) { - this->update_config_values(config); + this->update_config_values(config, opt_id); wxGetApp().obj_list()->changed_object(); }; // call back for rescaling of the extracolumn control @@ -325,7 +325,7 @@ bool ObjectSettings::add_missed_options(ModelConfig* config_to, const DynamicPri return is_added; } -void ObjectSettings::update_config_values(ModelConfig* config) +void ObjectSettings::update_config_values(ModelConfig* config, const std::string& changed_opt_key) { const auto objects_model = wxGetApp().obj_list()->GetModel(); const auto item = wxGetApp().obj_list()->GetSelection(); @@ -403,6 +403,10 @@ void ObjectSettings::update_config_values(ModelConfig* config) } main_config.apply(config->get(), true); + + if (printer_technology == ptFFF && changed_opt_key == "layer_height") + config_manipulation.check_layer_height(&main_config); + printer_technology == ptFFF ? config_manipulation.update_print_fff_config(&main_config) : config_manipulation.update_print_sla_config(&main_config) ; diff --git a/src/slic3r/GUI/GUI_ObjectSettings.hpp b/src/slic3r/GUI/GUI_ObjectSettings.hpp index 8903f8748b..21146425cc 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.hpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.hpp @@ -66,7 +66,7 @@ public: * we should add sparse_infill_pattern to avoid endless loop in update */ bool add_missed_options(ModelConfig *config_to, const DynamicPrintConfig &config_from); - void update_config_values(ModelConfig *config); + void update_config_values(ModelConfig *config, const std::string& changed_opt_key = ""); void UpdateAndShow(const bool show); void msw_rescale(); void sys_color_changed(); diff --git a/src/slic3r/GUI/GUI_ObjectTableSettings.cpp b/src/slic3r/GUI/GUI_ObjectTableSettings.cpp index 37ccfb8e41..e72c421a08 100644 --- a/src/slic3r/GUI/GUI_ObjectTableSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectTableSettings.cpp @@ -223,7 +223,7 @@ bool ObjectTableSettings::update_settings_list(bool is_object, bool is_multiple_ std::weak_ptr weak_optgroup(optgroup); optgroup->m_on_change = [this, is_object, object, config, group_category](const t_config_option_key &opt_id, const boost::any &value) { this->m_parent->Freeze(); - this->update_config_values(is_object, object, config, group_category); + this->update_config_values(is_object, object, config, group_category, opt_id); wxGetApp().obj_list()->changed_object(); this->m_parent->Thaw(); //update_extra_column_visible_status(optgroup.get(), cat.second, config); @@ -369,7 +369,7 @@ int ObjectTableSettings::update_extra_column_visible_status(ConfigOptionsGroup* return count; } -void ObjectTableSettings::update_config_values(bool is_object, ModelObject* object, ModelConfig* config, const std::string& category) +void ObjectTableSettings::update_config_values(bool is_object, ModelObject* object, ModelConfig* config, const std::string& category, const std::string& changed_opt_key) { int different_count = 0; const auto printer_technology = wxGetApp().plater()->printer_technology(); @@ -403,6 +403,9 @@ void ObjectTableSettings::update_config_values(bool is_object, ModelObject* obje config_manipulation.set_is_BBL_Printer(wxGetApp().preset_bundle->is_bbl_vendor()); + if (printer_technology == ptFFF && changed_opt_key == "layer_height") + config_manipulation.check_layer_height(&main_config); + printer_technology == ptFFF ? config_manipulation.update_print_fff_config(&main_config) : config_manipulation.update_print_sla_config(&main_config) ; diff --git a/src/slic3r/GUI/GUI_ObjectTableSettings.hpp b/src/slic3r/GUI/GUI_ObjectTableSettings.hpp index 534426f554..39e7e514e2 100644 --- a/src/slic3r/GUI/GUI_ObjectTableSettings.hpp +++ b/src/slic3r/GUI/GUI_ObjectTableSettings.hpp @@ -70,7 +70,7 @@ public: bool add_missed_options(ModelConfig *config_to, const DynamicPrintConfig &config_from); //return visible count int update_extra_column_visible_status(ConfigOptionsGroup* option_group, const std::vector& option_keys, ModelConfig* config); - void update_config_values(bool is_object, ModelObject* object, ModelConfig* config, const std::string& category); + void update_config_values(bool is_object, ModelObject* object, ModelConfig* config, const std::string& category, const std::string& changed_opt_key = ""); void UpdateAndShow(int row, const bool show, bool is_object, bool is_multiple_selection, ModelObject* object, ModelConfig* config, const std::string& category); void ValueChanged(int row, bool is_object, ModelObject* object, ModelConfig* config, const std::string& category, const std::string& key); void resetAllValues(int row, bool is_object, ModelObject* object, ModelConfig* config, const std::string& category); diff --git a/src/slic3r/GUI/GUI_Utils.cpp b/src/slic3r/GUI/GUI_Utils.cpp index 697eefea0b..cb8ba45c6b 100644 --- a/src/slic3r/GUI/GUI_Utils.cpp +++ b/src/slic3r/GUI/GUI_Utils.cpp @@ -548,7 +548,7 @@ void RemoveButtonBorder(wxWindow* win) GtkCssProvider* provider = gtk_css_provider_new(); const char* css = - "button {" + "button, button:hover, button:active, button:focus {" " border: none;" " outline: none;" " box-shadow: none;" @@ -589,6 +589,58 @@ void RemoveButtonBorder(wxWindow* win) ); #endif } + +void RemoveInputBorder(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(); + + // Target 'entry' and its inner subnodes (like text selection areas) + const char* css = + "entry, entry text, entry undershoot {" + " 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 + gtk_css_provider_load_from_data(provider, css, -1); +#else + // GTK3 + 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: Target the x/y thickness of the entry widget + gtk_rc_parse_string( + "style \"no-padding-entry\" {" + " xthickness = 0" + " ythickness = 0" + " GtkEntry::inner-border = { 0, 0, 0, 0 }" + " GtkEntry::focus-line-width = 0" + "}" + "class \"GtkEntry\" style \"no-padding-entry\"" + ); +#endif +} #endif // __WXGTK__ #ifdef __linux__ diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index 427ba9f0ad..c93c40b066 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -113,14 +113,7 @@ public: update_dark_ui(this); #endif - // Linux specific issue : get_dpi_for_window(this) still doesn't responce to the Display's scale in new wxWidgets(3.1.3). - // So, calculate the m_em_unit value from the font size, as before -#if !defined(__WXGTK__) - m_em_unit = std::max(10, 10.0f * m_scale_factor); -#else - // initialize default width_unit according to the width of the one symbol ("m") of the currently active font of this window. - m_em_unit = std::max(10, this->GetTextExtent("m").x - 1); -#endif // __WXGTK__ + update_em_unit(); // recalc_font(); @@ -235,6 +228,19 @@ private: // m_em_unit = metrics.averageWidth; // } + // update em_unit value for new window font + void update_em_unit() + { + // Linux specific issue : get_dpi_for_window(this) still doesn't responce to the Display's scale in new wxWidgets(3.1.3). + // So, calculate the m_em_unit value from the font size, as before +#if !defined(__WXGTK__) + m_em_unit = std::max(10, 10.0f * m_scale_factor); +#else + // initialize default width_unit according to the width of the one symbol ("m") of the currently active font of this window. + m_em_unit = std::max(10, this->GetTextExtent("m").x - 1); +#endif // __WXGTK__ + } + // check if new scale is differ from previous bool is_new_scale_factor() const { return fabs(m_scale_factor - m_prev_scale_factor) > 0.001; } @@ -247,8 +253,7 @@ private: // set normal application font as a current window font m_normal_font = this->GetFont(); - // update em_unit value for new window font - m_em_unit = std::max(10, 10.0f * m_scale_factor); + update_em_unit(); // rescale missed controls sizes and images on_dpi_changed(suggested_rect); @@ -472,8 +477,9 @@ void dataview_remove_insets(wxDataViewCtrl* dv); void staticbox_remove_margin(wxStaticBox* sb); #endif -#ifdef __WXGTK3__ -void RemoveButtonBorder(wxWindow* win); +#ifdef __WXGTK__ +void RemoveButtonBorder(wxWindow* win); // for wxButton/wxBitmapToggleButton based controls (SwitchButton, CheckBox) +void RemoveInputBorder(wxWindow* win); // for TextCtrl based controls (TextInput, ComboBox, SpinInput..) #endif #if defined(__WXOSX__) || defined(__linux__) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 7855ea92cc..1aaac99d40 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -442,7 +442,7 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) { } } else if (m_dragging) { // when mouse cursor leave window than finish actual dragging operation - bool is_leaving = mouse_event.Leaving(); + bool is_leaving = mouse_event.Leaving() && !m_parent.has_mouse_capture(); // ORCA keep tracking mouse position while drag active and cursor not in window bounds if (mouse_event.Dragging()) { Point mouse_coord(mouse_event.GetX(), mouse_event.GetY()); auto ray = m_parent.mouse_ray(mouse_coord); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp index 45aaf37a86..709e7b5b21 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp @@ -15,6 +15,8 @@ static const ColorRGBA DEF_COLOR = {0.7f, 0.7f, 0.7f, 1.f}; static const ColorRGBA SELECTED_COLOR = {0.0f, 0.5f, 0.5f, 1.0f}; static const ColorRGBA ERR_COLOR = {1.0f, 0.3f, 0.3f, 0.5f}; static const ColorRGBA HOVER_COLOR = {0.7f, 0.7f, 0.7f, 0.5f}; +static constexpr float BRIM_EAR_RADIUS_MIN = 0.1f; +static constexpr float BRIM_EAR_RADIUS_MAX = 100.f; static ModelVolume *get_model_volume(const Selection &selection, Model &model) { @@ -41,14 +43,14 @@ GLGizmoBrimEars::GLGizmoBrimEars(GLCanvas3D &parent, const std::string &icon_fil bool GLGizmoBrimEars::on_init() { - m_new_point_head_diameter = get_brim_default_radius(); + m_new_point_head_radius = get_brim_default_radius(); m_shortcut_key = WXK_CONTROL_E; const wxString ctrl = GUI::shortkey_ctrl_prefix(); const wxString alt = GUI::shortkey_alt_prefix(); - m_desc["head_diameter"] = _L("Head diameter"); + m_desc["brim_ear_radius"] = _L("Brim ear radius"); m_desc["max_angle"] = _L("Max angle"); m_desc["detection_radius"] = _L("Detection radius"); m_desc["remove"] = _L("Remove"); @@ -62,7 +64,7 @@ bool GLGizmoBrimEars::on_init() m_shortcuts = { {_L("Left mouse button"), _L("Add or Select")}, {_L("Right mouse button"), _L("Remove")}, - {ctrl + _L("Mouse wheel"), m_desc["head_diameter"]}, + {ctrl + _L("Mouse wheel"), m_desc["brim_ear_radius"]}, {alt + _L("Mouse wheel"), m_desc["section_view"]}, }; @@ -358,7 +360,7 @@ bool GLGizmoBrimEars::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_p Transform3d inverse_trsf = volume->get_instance_transformation().get_matrix_no_offset().inverse(); std::pair pos_and_normal; if (unproject_on_mesh2(mouse_position, pos_and_normal)) { - render_hover_point = CacheEntry(BrimPoint(pos_and_normal.first, m_new_point_head_diameter / 2.f), false, (inverse_trsf * m_world_normal).cast(), true); + render_hover_point = CacheEntry(BrimPoint(pos_and_normal.first, m_new_point_head_radius), false, (inverse_trsf * m_world_normal).cast(), true); } else { render_hover_point.reset(); } @@ -397,7 +399,7 @@ bool GLGizmoBrimEars::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_p Vec3d object_pos = trsf.inverse() * world_pos; // brim ear always face up Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Add brim ear"); - add_point_to_cache(object_pos.cast(), m_new_point_head_diameter / 2.f, false, (inverse_trsf * m_world_normal).cast()); + add_point_to_cache(object_pos.cast(), m_new_point_head_radius, false, (inverse_trsf * m_world_normal).cast()); m_parent.set_as_dirty(); m_wait_for_up_event = true; find_single(); @@ -490,9 +492,9 @@ bool GLGizmoBrimEars::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_p // mouse wheel up if (action == SLAGizmoEventType::MouseWheelUp) { if (control_down) { - float initial_value = m_new_point_head_diameter; + float initial_value = m_new_point_head_radius; begin_radius_change(initial_value); - m_new_point_head_diameter = std::min(20., initial_value + 0.1); + m_new_point_head_radius = std::min(BRIM_EAR_RADIUS_MAX, initial_value + 0.1f); update_cache_radius(); return true; } @@ -502,9 +504,9 @@ bool GLGizmoBrimEars::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_p if (action == SLAGizmoEventType::MouseWheelDown) { if (control_down) { - float initial_value = m_new_point_head_diameter; + float initial_value = m_new_point_head_radius; begin_radius_change(initial_value); - m_new_point_head_diameter = std::max(5., initial_value - 0.1); + m_new_point_head_radius = std::max(BRIM_EAR_RADIUS_MIN, initial_value - 0.1f); update_cache_radius(); return true; } @@ -597,18 +599,18 @@ std::vector GLGizmoBrimEars::get_config_options(const std: void GLGizmoBrimEars::begin_radius_change(float initial_value) { - if (m_old_point_head_diameter == 0.f) - m_old_point_head_diameter = initial_value; + if (m_old_point_head_radius == 0.f) + m_old_point_head_radius = initial_value; } void GLGizmoBrimEars::update_cache_radius() { if (render_hover_point) - render_hover_point->brim_point.head_front_radius = m_new_point_head_diameter / 2.f; + render_hover_point->brim_point.head_front_radius = m_new_point_head_radius; for (auto &cache_entry : m_editing_cache) if (cache_entry.selected) { - cache_entry.brim_point.head_front_radius = m_new_point_head_diameter / 2.f; + cache_entry.brim_point.head_front_radius = m_new_point_head_radius; find_single(); update_model_object(); } @@ -617,18 +619,18 @@ void GLGizmoBrimEars::update_cache_radius() void GLGizmoBrimEars::apply_radius_change() { - if (m_old_point_head_diameter == 0.f) return; + if (m_old_point_head_radius == 0.f) return; // momentarily restore the old value to take snapshot for (auto& cache_entry : m_editing_cache) if (cache_entry.selected) - cache_entry.brim_point.head_front_radius = m_old_point_head_diameter / 2.f; - float backup = m_new_point_head_diameter; - m_new_point_head_diameter = m_old_point_head_diameter; - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Change point head diameter"); - m_new_point_head_diameter = backup; + cache_entry.brim_point.head_front_radius = m_old_point_head_radius; + float backup = m_new_point_head_radius; + m_new_point_head_radius = m_old_point_head_radius; + Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Change brim ear radius"); + m_new_point_head_radius = backup; update_cache_radius(); - m_old_point_head_diameter = 0.f; + m_old_point_head_radius = 0.f; } void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limit) @@ -653,7 +655,7 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar); float space_size = m_imgui->get_style_scaling() * 8; - std::vector text_list = {m_desc["head_diameter"], m_desc["max_angle"], m_desc["detection_radius"], m_desc["clipping_of_view"], + std::vector text_list = {m_desc["brim_ear_radius"], m_desc["max_angle"], m_desc["detection_radius"], m_desc["clipping_of_view"], m_desc["create"], m_desc["remove"]}; float widest_text = m_imgui->find_widest_text(text_list); float caption_size = widest_text + space_size + ImGui::GetStyle().WindowPadding.x; @@ -680,11 +682,11 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi // - keep updating the head radius during sliding so it is continuosly refreshed in 3D scene // - take correct undo/redo snapshot after the user is done with moving the slider ImGui::AlignTextToFramePadding(); - float initial_value = m_new_point_head_diameter; - m_imgui->text(m_desc["head_diameter"]); + float initial_value = m_new_point_head_radius; + m_imgui->text(m_desc["brim_ear_radius"]); ImGui::SameLine(caption_size); ImGui::PushItemWidth(slider_width); - m_imgui->bbl_slider_float_style("##head_diameter", &m_new_point_head_diameter, 5, 20, "%.1f", 1.0f, true); + m_imgui->bbl_slider_float_style("##brim_ear_radius", &m_new_point_head_radius, BRIM_EAR_RADIUS_MIN, BRIM_EAR_RADIUS_MAX, "%.1f", 1.0f, true); if (m_imgui->get_last_slider_status().clicked) { begin_radius_change(initial_value); } @@ -695,7 +697,7 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi } ImGui::SameLine(drag_left_width); ImGui::PushItemWidth(1.5 * slider_icon_width); - ImGui::BBLDragFloat("##head_diameter_input", &m_new_point_head_diameter, 0.05f, 0.0f, 0.0f, "%.1f"); + ImGui::BBLDragFloat("##brim_ear_radius_input", &m_new_point_head_radius, 0.05f, BRIM_EAR_RADIUS_MIN, BRIM_EAR_RADIUS_MAX, "%.1f"); ImGui::Separator(); @@ -910,9 +912,9 @@ void GLGizmoBrimEars::on_stop_dragging() m_point_before_drag = CacheEntry(); } -void GLGizmoBrimEars::on_load(cereal::BinaryInputArchive &ar) { ar(m_new_point_head_diameter, m_editing_cache, m_selection_empty); } +void GLGizmoBrimEars::on_load(cereal::BinaryInputArchive &ar) { ar(m_new_point_head_radius, m_editing_cache, m_selection_empty); } -void GLGizmoBrimEars::on_save(cereal::BinaryOutputArchive &ar) const { ar(m_new_point_head_diameter, m_editing_cache, m_selection_empty); } +void GLGizmoBrimEars::on_save(cereal::BinaryOutputArchive &ar) const { ar(m_new_point_head_radius, m_editing_cache, m_selection_empty); } void GLGizmoBrimEars::select_point(int i) { @@ -920,11 +922,11 @@ void GLGizmoBrimEars::select_point(int i) for (auto &point_and_selection : m_editing_cache) point_and_selection.selected = (i == AllPoints); m_selection_empty = (i == NoPoints); - if (i == AllPoints) m_new_point_head_diameter = m_editing_cache[0].brim_point.head_front_radius * 2.f; + if (i == AllPoints) m_new_point_head_radius = m_editing_cache[0].brim_point.head_front_radius; } else { m_editing_cache[i].selected = true; m_selection_empty = false; - m_new_point_head_diameter = m_editing_cache[i].brim_point.head_front_radius * 2.f; + m_new_point_head_radius = m_editing_cache[i].brim_point.head_front_radius; } } @@ -1011,8 +1013,7 @@ void GLGizmoBrimEars::auto_generate() auto add_point = [this, &trsf, &normal](const Point &p) { Vec3d world_pos = {float(p.x() * SCALING_FACTOR), float(p.y() * SCALING_FACTOR), -0.0001}; Vec3d object_pos = trsf.inverse() * world_pos; - // m_editing_cache.emplace_back(BrimPoint(object_pos.cast(), m_new_point_head_diameter / 2), false, normal); - add_point_to_cache(object_pos.cast(), m_new_point_head_diameter / 2, false, normal); + add_point_to_cache(object_pos.cast(), m_new_point_head_radius, false, normal); }; for (const ExPolygon &ex_poly : m_first_layer) { Polygon out_poly = ex_poly.contour; @@ -1158,8 +1159,11 @@ void GLGizmoBrimEars::reset_all_pick() { std::mapprinters.get_edited_preset().config.option("nozzle_diameter")->get_at(0); - const DynamicPrintConfig &pring_cfg = wxGetApp().preset_bundle->prints.get_edited_preset().config; - return pring_cfg.get_abs_value("initial_layer_line_width", nozzle_diameter) * 16.0f; + const DynamicPrintConfig &print_cfg = wxGetApp().preset_bundle->prints.get_edited_preset().config; + return std::clamp( + float(print_cfg.get_abs_value("initial_layer_line_width", nozzle_diameter) * 8.0), + BRIM_EAR_RADIUS_MIN, + BRIM_EAR_RADIUS_MAX); } ExPolygon GLGizmoBrimEars::make_polygon(BrimPoint point, const Geometry::Transformation &trsf) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.hpp index 8b1ff2ca62..4e531e6acc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.hpp @@ -98,12 +98,12 @@ private: void render_points(const Selection& selection); - float m_new_point_head_diameter; // Size of a new point. + float m_new_point_head_radius; // Radius of a new point. float m_max_angle = 125.f; float m_detection_radius = 1.f; double m_detection_radius_max = .0f; CacheEntry m_point_before_drag; // undo/redo - so we know what state was edited - float m_old_point_head_diameter = 0.; // the same + float m_old_point_head_radius = 0.; // the same mutable std::vector m_editing_cache; // a support point and whether it is currently selectedchanges or undo/redo std::map m_single_brim; ObjectID m_old_mo_id; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index feba37133a..ecf465afe7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -566,8 +566,11 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) void GLGizmoEmboss::on_mouse_change_selection(const wxMouseEvent &mouse_event) { - static bool was_dragging = true; - if ((mouse_event.LeftUp() || mouse_event.RightUp()) && !was_dragging) { + static bool was_dragging = true; + // The left up may be the end of a drag that started on the gizmo floating window (e.g. selecting + // text in the input field). Such a release is not a click on the scene and must not close the gizmo. + // (The flag is only set for left up events, so right up behavior is unchanged.) + if ((mouse_event.LeftUp() || mouse_event.RightUp()) && !was_dragging && !m_parent.is_mouse_left_up_ignored()) { // is hovered volume closest hovered? int hovered_idx = m_parent.get_first_hover_volume_idx(); if (hovered_idx < 0) diff --git a/src/slic3r/GUI/IMSlider.cpp b/src/slic3r/GUI/IMSlider.cpp index 35f4761257..c008963646 100644 --- a/src/slic3r/GUI/IMSlider.cpp +++ b/src/slic3r/GUI/IMSlider.cpp @@ -1733,7 +1733,7 @@ std::string IMSlider::get_label(int tick, LabelType label_type) ::sprintf(layer_height, "%.2f", m_values.empty() ? m_label_koef * value : m_values[value]); if (label_type == ltHeight) return std::string(layer_height); if (label_type == ltHeightWithLayer) { - char buffer[64]; + char buffer[90]; size_t layer_number; layer_number = m_draw_mode == dmSequentialFffPrint ? (m_values.empty() ? value : value + 1) : m_is_wipe_tower ? get_layer_number(value, label_type) + 1 : (m_values.empty() ? value : value + 1); ::sprintf(buffer, "%5s\n%5s", std::to_string(layer_number).c_str(), layer_height); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 8974a169d1..d46e8ed31b 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -2809,12 +2809,26 @@ void ImGuiWrapper::init_font(bool compress) } } + if (m_glyph_ranges == ImGui::GetIO().Fonts->GetGlyphRangesThai()) { + ImFontConfig fallback_cfg = cfg; + fallback_cfg.MergeMode = true; + static constexpr ImWchar celsius_range[] = { 0x2103, 0x2103, 0 }; + io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/HarmonyOS_Sans_SC_Regular.ttf").c_str(), m_font_size, &fallback_cfg, celsius_range); + } + bold_font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/" + font_name_bold).c_str(), m_font_size, &cfg, ranges.Data); if (bold_font == nullptr) { bold_font = io.Fonts->AddFontDefault(); if (bold_font == nullptr) { throw Slic3r::RuntimeError("ImGui: Could not load deafult font"); } } + if (m_glyph_ranges == ImGui::GetIO().Fonts->GetGlyphRangesThai()) { + ImFontConfig fallback_cfg = cfg; + fallback_cfg.MergeMode = true; + static constexpr ImWchar celsius_range[] = { 0x2103, 0x2103, 0 }; + io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/HarmonyOS_Sans_SC_Bold.ttf").c_str(), m_font_size, &fallback_cfg, celsius_range); + } + if (m_glyph_ranges == ImGui::GetIO().Fonts->GetGlyphRangesThai()) { default_font->Scale *= 1.25f; bold_font->Scale *= 1.25f; diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index c3d05c556f..6b74b71af1 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -548,7 +548,7 @@ void ArrangeJob::process(Ctl &ctl) params.stopcondition = [&ctl]() { return ctl.was_canceled(); }; params.progressind = [this, &ctl](unsigned num_finished, std::string str = "") { - ctl.update_status(num_finished * 100 / status_range(), _u8L("Arranging") + str); + ctl.update_status(num_finished * 100 / status_range(), _u8L("Arranging ") + str); }; { diff --git a/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp index f988f622ce..31bd6728b1 100644 --- a/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp +++ b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp @@ -45,24 +45,26 @@ void CreateFontStyleImagesJob::process(Ctl &ctl) for (const ExPolygon &shape : shapes) bounding_box.merge(BoundingBox(shape.contour.points)); for (ExPolygon &shape : shapes) shape.translate(-bounding_box.min); - - // calculate conversion from FontPoint to screen pixels by size of font - double scale = get_text_shape_scale(item.prop, *item.font.font_file) * m_input.ppm; - scales[index] = scale; - //double scale = font_prop.size_in_mm * SCALING_FACTOR; - BoundingBoxf bb2(bounding_box.min.cast(), - bounding_box.max.cast()); + if (bounding_box.size().x() < 1 || bounding_box.size().y() < 1) + continue; // or however the font job's degenerate-box case is handled + + // Normalize to fit max_size, exactly like CreateFontImageJob does against m_input.size. + // Fit by height (matches row height), then clamp width if needed. + constexpr float preview_padding_px = 2.f; // margin for AA sampling, tune to your AA kernel radius + + double scale = m_input.max_size.y() / (double) bounding_box.size().y(); + BoundingBoxf bb2(bounding_box.min.cast(), bounding_box.max.cast()); bb2.scale(scale); - image.tex_size.x = std::ceil(bb2.max.x() - bb2.min.x()); - image.tex_size.y = std::ceil(bb2.max.y() - bb2.min.y()); - // crop image width - if (image.tex_size.x > m_input.max_size.x()) + // crop width only if the (now height-normalized) text is too wide + image.tex_size.x = std::ceil(bb2.max.x() - bb2.min.x()) + 2 * preview_padding_px; + image.tex_size.y = std::ceil(bb2.max.y() - bb2.min.y()) + 2 * preview_padding_px; + + if (image.tex_size.x > m_input.max_size.x()) image.tex_size.x = m_input.max_size.x(); - // crop image height - if (image.tex_size.y > m_input.max_size.y()) - image.tex_size.y = m_input.max_size.y(); + + scales[index] = scale; } // arrange bounding boxes diff --git a/src/slic3r/GUI/Jobs/OrientJob.cpp b/src/slic3r/GUI/Jobs/OrientJob.cpp index 7347bad6a2..ee8ea875c0 100644 --- a/src/slic3r/GUI/Jobs/OrientJob.cpp +++ b/src/slic3r/GUI/Jobs/OrientJob.cpp @@ -149,6 +149,46 @@ void OrientJob::prepare() } } +/// parameters to minimize support area +static void setMinimalSupportAreaPrams(Slic3r::orientation::OrientParams &out) +{ + out.TAR_A = 0.015f; + out.TAR_B = 0.177f; + out.RELATIVE_F = 20; + out.CONTOUR_F = 0.5f; + out.BOTTOM_F = 2.5f; + out.BOTTOM_HULL_F = 0.1f; + out.TAR_C = 0.1f; + out.TAR_D = 1; + out.TAR_E = 0.0115f; + out.FIRST_LAY_H = 0.2f; // 0.0475; + out.VECTOR_TOL = -0.00083f; + out.NEGL_FACE_SIZE = 0.01f; + out.ASCENT = -0.5f; + out.PLAFOND_ADV = 0.0599f; + out.CONTOUR_AMOUNT = 0.0182427f; + out.OV_H = 2.574f; + out.height_offset = 2.3728f; + out.height_log = 0.041375f; + out.height_log_k = 1.9325457f; + out.LAF_MAX = 0.999f; // cos(1.4\degree) for low angle face 0.9997f + out.LAF_MIN = 0.97f; // cos(14\degree) 0.9703f + out.TAR_LAF = 0.001f; // 0.01f + out.TAR_PROJ_AREA = 0.1f; + out.BOTTOM_MIN = 0.1f; // min bottom area. If lower than it the object may be unstable + out.BOTTOM_MAX = 2000; // max bottom area. If get to it the object is stable enough (further increase bottom area won't do more help) + out.height_to_bottom_hull_ratio_MIN = 1, + out.BOTTOM_HULL_MAX = 2000; // max bottom hull area + out.APPERANCE_FACE_SUPP = 3; // penalty of generating supports on appearance face + out.overhang_angle = 60.f; + out.use_low_angle_face = true; + out.min_volume = false; + out.fun_dir = {}; + out.parallel = true; + out.progressind = {}; + out.stopcondition = {}; +} + void OrientJob::process(Ctl &ctl) { static const auto arrangestr = _u8L("Orienting..."); @@ -161,9 +201,8 @@ void OrientJob::process(Ctl &ctl) const GLCanvas3D::OrientSettings& settings = m_plater->canvas3D()->get_orient_settings(); orientation::OrientParams params; - orientation::OrientParamsArea params_area; if (settings.min_area) { - memcpy(¶ms, ¶ms_area, sizeof(params)); + setMinimalSupportAreaPrams(params); params.min_volume = false; } else { diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 7b638e3316..5a0e70b74c 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -708,7 +708,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ m_print_enable = get_enable_print_status(); m_print_btn->Enable(m_print_enable); if (m_print_enable) { - if (wxGetApp().preset_bundle->use_bbl_network()) + if (wxGetApp().preset_bundle->use_bbl_network() || wxGetApp().app_config->get_bool("use_printer_agents")) wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_PRINT_PLATE)); else wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SEND_GCODE)); @@ -1368,9 +1368,88 @@ void MainFrame::init_tabpanel() { } // SoftFever -void MainFrame::show_device(bool bBBLPrinter) { +void MainFrame::show_device(bool should_use_native) { auto idx = -1; - if (bBBLPrinter) { + + const bool use_printer_agents = wxGetApp().app_config->get_bool("use_printer_agents"); + + // The web page is appended when printer agents are enabled. Remove that + // extra page before switching back to the normal native/Web layout. + if (!use_printer_agents) { + if ((idx = m_tabpanel->FindPage(m_printer_view)) != wxNOT_FOUND && idx != tpMonitor) { + m_printer_view->Show(false); + m_tabpanel->RemovePage(idx); + } + } + + if (use_printer_agents) { + if (!m_monitor) { + m_monitor = new MonitorPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); + m_monitor->SetBackgroundColour(*wxWHITE); + } + + if (m_tabpanel->FindPage(m_monitor) == wxNOT_FOUND) { + if ((idx = m_tabpanel->FindPage(m_printer_view)) != wxNOT_FOUND) { + m_printer_view->Show(false); + m_tabpanel->RemovePage(idx); + } + m_monitor->Show(false); + m_tabpanel->InsertPage(tpMonitor, m_monitor, _L("Device"), std::string("tab_monitor_active"), + std::string("tab_monitor_active")); + } + + if (m_printer_view == nullptr) { + m_printer_view = new PrinterWebView(m_tabpanel); + Bind(EVT_LOAD_PRINTER_URL, [this](LoadPrinterViewEvent& evt) { + wxString url = evt.GetString(); + wxString key = evt.GetAPIkey(); + // select_tab(MainFrame::tpMonitor); + m_printer_view->load_url(url, key); + }); + } + + if (wxGetApp().is_enable_multi_machine()) { + if (!m_multi_machine) { + m_multi_machine = new MultiMachinePage(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); + m_multi_machine->SetBackgroundColour(*wxWHITE); + } + // TODO: change the bitmap + if (m_tabpanel->FindPage(m_multi_machine) == wxNOT_FOUND) { + m_multi_machine->Show(false); + m_tabpanel->InsertPage(tpMultiDevice, m_multi_machine, _L("Multi-device"), std::string("tab_multi_active"), + std::string("tab_multi_active"), false); + } + } + if (!m_calibration) { + m_calibration = new CalibrationPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); + m_calibration->SetBackgroundColour(*wxWHITE); + } + // Calibration is always the last page, so don't use InsertPage here. Otherwise, if multi_machine page is not enabled, + // the calibration tab won't be properly added as well, due to the TabPosition::tpCalibration no longer matches the real tab position. + if (m_tabpanel->FindPage(m_calibration) == wxNOT_FOUND) { + m_calibration->Show(false); + m_tabpanel->AddPage(m_calibration, _L("Calibration"), std::string("tab_calibration_active"), + std::string("tab_calibration_active"), false); + } + + if ((idx = m_tabpanel->FindPage(m_printer_view)) == wxNOT_FOUND) { + m_printer_view->Show(false); + m_tabpanel->AddPage(m_printer_view, _L("Device (Web)"), std::string("tab_monitor_active"), + std::string("tab_monitor_active"), false); + } else { + m_tabpanel->SetPageText(idx, _L("Device (Web)")); + } + +#ifdef _MSW_DARK_MODE + wxGetApp().UpdateDarkUIWin(this); +#endif // _MSW_DARK_MODE + + fit_tab_labels(); // ORCA on printer change + + return; + } + + if (should_use_native) { if (m_tabpanel->FindPage(m_monitor) != wxNOT_FOUND) { fit_tab_labels(); // ORCA on printer change - same button layout return; @@ -1999,7 +2078,8 @@ wxBoxSizer* MainFrame::create_side_tools() SidePopup* p = new SidePopup(this); if (wxGetApp().preset_bundle - && !wxGetApp().preset_bundle->is_bbl_vendor()) { + && !wxGetApp().preset_bundle->is_bbl_vendor() + && !wxGetApp().app_config->get_bool("use_printer_agents")) { // ThirdParty Buttons SideButton* export_gcode_btn = new SideButton(p, _L("Export G-code file"), ""); export_gcode_btn->SetCornerRadius(0); @@ -2132,7 +2212,7 @@ wxBoxSizer* MainFrame::create_side_tools() const auto preset_bundle = wxGetApp().preset_bundle; if (preset_bundle) { - if (preset_bundle->use_bbl_network()) { + if (preset_bundle->use_bbl_network() || wxGetApp().app_config->get_bool("use_printer_agents")) { // BBL network support everything } else { support_send = false; // All 3rd print hosts do not have the send options @@ -4253,14 +4333,26 @@ void MainFrame::load_printer_url(wxString url, wxString apikey) void MainFrame::load_printer_url() { PresetBundle &preset_bundle = *wxGetApp().preset_bundle; - if (preset_bundle.use_bbl_device_tab() || NetworkAgentFactory::is_current_printer_agent_plugin()) + if (preset_bundle.use_bbl_device_tab() && !wxGetApp().app_config->get_bool("use_printer_agents")) return; auto cfg = preset_bundle.printers.get_edited_preset().config; + if (cfg.opt_string("print_host").empty()) { + if (auto *device_manager = wxGetApp().getDeviceManager()) { + auto *machine = device_manager->get_selected_machine(); + if (!machine) { + auto machines = device_manager->get_my_machine_list(); + if (machines.size() == 1) + machine = machines.begin()->second; + } + if (machine && !machine->get_dev_ip().empty()) + cfg.opt_string("print_host") = machine->get_dev_ip(); + } + } wxString url = from_u8(PrintHost::get_print_host_webui(&cfg)); wxString apikey; const auto host_type = cfg.option>("host_type")->value; - if (cfg.has("printhost_apikey") && (host_type == htPrusaLink || host_type == htPrusaConnect)) + if (cfg.has("printhost_apikey") && host_type != htSimplyPrint) apikey = cfg.opt_string("printhost_apikey"); if (!url.empty()) { load_printer_url(url, apikey); diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 20229a611e..a614783c31 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -358,7 +358,7 @@ public: void RunScript(wxString js); //SoftFever - void show_device(bool bBBLPrinter); + void show_device(bool should_use_native); void fit_tab_labels(); // ORCA PA_Calibration_Dlg* m_pa_calib_dlg{ nullptr }; @@ -385,7 +385,7 @@ public: CalibrationPanel* m_calibration{ nullptr }; WebViewPanel* m_webview { nullptr }; PrinterWebView* m_printer_view{nullptr}; - wxLogWindow* m_log_window { nullptr }; + wxLogWindow* m_log_window { nullptr }; // BBS //wxBookCtrlBase* m_tabpanel { nullptr }; Notebook* m_tabpanel{ nullptr }; diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp index ebf4db6846..7f1effd162 100644 --- a/src/slic3r/GUI/MsgDialog.cpp +++ b/src/slic3r/GUI/MsgDialog.cpp @@ -9,8 +9,13 @@ #include #include #include +#include + +#include #include +#include +#include #include "libslic3r/libslic3r.h" #include "libslic3r/Utils.hpp" @@ -229,12 +234,82 @@ void MsgDialog::finalize() } +// A placeholder-parser caret line, pointing at the column where parsing failed. +static bool is_caret_line(const std::string &line) +{ + return std::count(line.begin(), line.end(), '^') == 1 && + std::all_of(line.begin(), line.end(), [](char c) { return c == ' ' || c == '^'; }); +} + +// Tag each line as a code excerpt (a caret line or the source line above one) that must stay +// monospaced for the '^' to align. +static std::vector> classify_code_lines(const std::string &msg) +{ + std::vector lines; + boost::split(lines, msg, boost::is_any_of("\n")); + for (std::string &line : lines) + if (!line.empty() && line.back() == '\r') + line.pop_back(); + + std::vector> tagged; + tagged.reserve(lines.size()); + for (size_t i = 0; i < lines.size(); ++i) { + bool is_code = is_caret_line(lines[i]) || (i + 1 < lines.size() && is_caret_line(lines[i + 1])); + tagged.emplace_back(std::move(lines[i]), is_code); + } + return tagged; +} + +// Keeps whitespace literal so the caret's leading spaces survive. +// Used inside , which supplies the fixed face.
 does both but adds a blank line above it.
+class CodeExcerptTagHandler : public wxHtmlWinTagHandler
+{
+public:
+    wxString GetSupportedTags() override { return wxT("EXCERPT"); }
+    bool     HandleTag(const wxHtmlTag &tag) override
+    {
+        const wxHtmlWinParser::WhitespaceMode ws = m_WParser->GetWhitespaceMode();
+        m_WParser->SetWhitespaceMode(wxHtmlWinParser::Whitespace_Pre);
+        ParseInner(tag);
+        m_WParser->SetWhitespaceMode(ws);
+        return true;
+    }
+};
+
+// Render the message as HTML, monospacing only the code excerpts.
+static std::string format_parser_error_html(const std::string &msg)
+{
+    std::string out;
+    for (const auto &[text, is_code] : classify_code_lines(msg)) {
+        if (!out.empty()) out += "
"; // join, not trail; a trailing
forces a scrollbar + std::string escaped = xml_escape(text); + if (is_code) + out += "" + escaped + ""; + else + out += escaped; + } + return out; +} + +// Measure each line in the font it will render in, so the dialog fits the longest line without slack. +static wxSize measure_mixed_text(wxWindow *parent, const std::string &msg, const wxFont &prose_font, const wxFont &code_font) +{ + wxClientDC dc(parent); + int width = 0, height = 0; + for (const auto &[text, is_code] : classify_code_lines(msg)) { + dc.SetFont(is_code ? code_font : prose_font); + width = std::max(width, dc.GetTextExtent(wxString::FromUTF8(text.c_str())).GetWidth()); + height += dc.GetCharHeight(); + } + return wxSize(width, height); +} + // Text shown as HTML, so that mouse selection and Ctrl-V to copy will work. static void add_msg_content(wxWindow *parent, wxBoxSizer *content_sizer, wxString msg, - bool monospaced_font = false, - bool is_marked_msg = false, + bool has_code_excerpts = false, + bool is_marked_msg = false, const wxString &link_text = "", std::function link_callback = nullptr) { @@ -243,7 +318,7 @@ static void add_msg_content(wxWindow *parent, // count lines in the message int msg_lines = 0; - if (!monospaced_font) { + if (!has_code_excerpts) { int line_len = 55;// count of symbols in one line int start_line = 0; for (auto i = msg.begin(); i != msg.end(); ++i) { @@ -300,13 +375,23 @@ static void add_msg_content(wxWindow *parent, page_size = wxSize(info_width, page_height); } else { - wxClientDC dc(parent); - dc.SetFont(font); // ORCA without this it calculates bigger size - wxSize msg_sz = dc.GetMultiLineTextExtent(msg) + parent->FromDIP(wxSize(10,5)); // added extra spacing to prevent wrapping + wxSize msg_sz; + if (has_code_excerpts) { + msg_sz = measure_mixed_text(parent, msg.ToUTF8().data(), font, monospace); + } else { + wxClientDC dc(parent); + dc.SetFont(font); // ORCA without this it calculates bigger size + msg_sz = dc.GetMultiLineTextExtent(msg); + } + msg_sz += parent->FromDIP(wxSize(10,5)); // added extra spacing to prevent wrapping - page_size = wxSize(std::min(msg_sz.GetX(), info_width), std::min(msg_sz.GetY(), info_width)); + int page_height = msg_sz.GetY(); + // Reserve the horizontal scrollbar's height, or it clips the last line. + if (msg_sz.GetX() > info_width) + page_height += wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y, parent); + page_size = wxSize(std::min(msg_sz.GetX(), info_width), std::min(page_height, info_width)); // Extra line breaks in message dialog - if (link_text.IsEmpty() && !link_callback && is_marked_msg == false) {//for common text + if (link_text.IsEmpty() && !link_callback && is_marked_msg == false && !has_code_excerpts) {//for common text html->Destroy(); if (msg_sz.GetX() < info_width) {//No need for line breaks info_width = msg_sz.GetX(); @@ -337,12 +422,15 @@ static void add_msg_content(wxWindow *parent, } html->SetMinSize(page_size); - std::string msg_escaped = xml_escape(msg.ToUTF8().data(), is_marked_msg); - boost::replace_all(msg_escaped, "\r\n", "
"); - boost::replace_all(msg_escaped, "\n", "
"); - if (monospaced_font) - // Code formatting will be preserved. This is useful for reporting errors from the placeholder parser. - msg_escaped = std::string("
") + msg_escaped + "
"; + std::string msg_escaped; + if (has_code_excerpts) { + html->GetParser()->AddTagHandler(new CodeExcerptTagHandler()); + msg_escaped = format_parser_error_html(msg.ToUTF8().data()); + } else { + msg_escaped = xml_escape(msg.ToUTF8().data(), is_marked_msg); + boost::replace_all(msg_escaped, "\r\n", "
"); + boost::replace_all(msg_escaped, "\n", "
"); + } if (!link_text.IsEmpty() && link_callback) { msg_escaped += "" + std::string(link_text.ToUTF8().data()) + ""; @@ -360,15 +448,15 @@ static void add_msg_content(wxWindow *parent, // ErrorDialog -ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &temp_msg, bool monospaced_font) +ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &temp_msg, bool has_code_excerpts) : MsgDialog(parent, wxString::Format(_(L("%s error")), SLIC3R_APP_FULL_NAME), wxString::Format(_(L("%s has encountered an error")), SLIC3R_APP_FULL_NAME), wxOK) , msg(temp_msg) { - add_msg_content(this, content_sizer, msg, monospaced_font); + add_msg_content(this, content_sizer, msg, has_code_excerpts); - // Use a small bitmap with monospaced font, as the error text will not be wrapped. - logo->SetBitmap(create_scaled_bitmap("OrcaSlicer_192px_grayscale.png", this, monospaced_font ? 48 : /*1*/64)); + // Use a small bitmap for code excerpts, which cannot wrap and so need the width. + logo->SetBitmap(create_scaled_bitmap("OrcaSlicer_192px_grayscale.png", this, has_code_excerpts ? 48 : /*1*/64)); SetMaxSize(MSG_DLG_MAX_SIZE); diff --git a/src/slic3r/GUI/MsgDialog.hpp b/src/slic3r/GUI/MsgDialog.hpp index 174d734336..90fd160310 100644 --- a/src/slic3r/GUI/MsgDialog.hpp +++ b/src/slic3r/GUI/MsgDialog.hpp @@ -106,9 +106,9 @@ protected: class ErrorDialog : public MsgDialog { public: - // If monospaced_font is true, the error message is displayed using html
tags, - // so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser. - ErrorDialog(wxWindow *parent, const wxString &temp_msg, bool courier_font); + // If has_code_excerpts is true, code excerpts (a source line and the caret line below it) render + // monospaced so the caret aligns. Used for placeholder-parser errors. + ErrorDialog(wxWindow *parent, const wxString &temp_msg, bool has_code_excerpts); ErrorDialog(ErrorDialog &&) = delete; ErrorDialog(const ErrorDialog &) = delete; ErrorDialog &operator=(ErrorDialog &&) = delete; diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 0f6cdba602..25c13c4b8d 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -54,6 +54,9 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co case ConfigOptionDef::GUIType::one_string: m_fields.emplace(id, TextCtrl::Create(this->ctrl_parent(), opt, id)); break; case ConfigOptionDef::GUIType::plugin_picker: m_fields.emplace(id, PluginField::Create(this->ctrl_parent(), opt, id)); break; case ConfigOptionDef::GUIType::plugin_config: m_fields.emplace(id, PluginConfigField::Create(this->ctrl_parent(), opt, id)); break; + case ConfigOptionDef::GUIType::printer_agent_select: m_fields.emplace( + id, PrinterAgentChoice::Create(this->ctrl_parent(), opt, id)); + break; default: switch (opt.type) { case coFloatOrPercent: @@ -386,6 +389,7 @@ void OptionsGroup::activate_line(Line& line) } if (label != nullptr && line.label_tooltip != "") label->SetToolTip(line.label_tooltip); + line.label_widget = label; } } @@ -574,6 +578,7 @@ void OptionsGroup::clear(bool destroy_custom_ctrl) for (Line& line : m_lines) { if (line.near_label_widget_win) line.near_label_widget_win = nullptr; + line.label_widget = nullptr; if (line.widget_sizer) { line.widget_sizer->Clear(true); @@ -652,6 +657,16 @@ Option ConfigOptionsGroup::get_option(const std::string& opt_key, int opt_index void ConfigOptionsGroup::on_change_OG(const t_config_option_key& opt_id, const boost::any& value) { + if (opt_id == "printer_agent") { + // TODO: Replace this option-specific branch with a generic value adapter if + // more fields need custom field-value to config-value conversion. + if (const std::string* id = boost::any_cast(&value)) + this->change_opt_value("printer_agent", wxGetApp().canonical_printer_agent_id(*id)); + + OptionsGroup::on_change_OG(opt_id, value); + return; + } + if (!m_opt_map.empty()) { auto it = m_opt_map.find(opt_id); if (it == m_opt_map.end()) { @@ -770,6 +785,19 @@ void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config, } } #endif + else if (opt_key == "printer_agent") + { + // why: printer_agent is a coString kept out of m_opt_map. The generic non-opt_map revert + // below restores the edited config from get_value(), but a deregistered/"(missing)" saved + // id has no selectable row, so the field yields no value and the edited config keeps the + // user's interim pick -> stuck dirty. Restore the SAVED id straight into the edited config + // (displayable or not; config is the saved or system baseline), then repaint and notify. + const std::string saved_id = config.opt_string("printer_agent"); + set_value(opt_key, saved_id); + this->change_opt_value(opt_key, saved_id); + OptionsGroup::on_change_OG(opt_key, saved_id); + return; + } else if (m_opt_map.find(opt_key) == m_opt_map.end() || // This option don't have corresponded field opt_key == "printable_area" || opt_key == "compatible_printers" || opt_key == "compatible_prints" || opt_key == "thumbnails" || diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp index 5e1f55dfd8..c808545145 100644 --- a/src/slic3r/GUI/OptionsGroup.hpp +++ b/src/slic3r/GUI/OptionsGroup.hpp @@ -62,6 +62,7 @@ public: widget_t widget {nullptr}; std::function near_label_widget{ nullptr }; wxWindow* near_label_widget_win {nullptr}; + wxStaticText* label_widget {nullptr}; wxSizer* widget_sizer {nullptr}; wxSizer* extra_widget_sizer {nullptr}; //BBS: export the extra colume widget @@ -81,6 +82,14 @@ public: label(_(label)), label_tooltip(_(tooltip)) {} Line() : m_is_separator(true) {} + void set_label(const wxString& new_label) { + label = new_label; + if (label_widget != nullptr) { + label_widget->SetLabel(label + (label.IsEmpty() ? "" : ": ")); + label_widget->Refresh(); + } + } + bool is_separator() const { return m_is_separator; } bool has_only_option(const std::string& opt_key) const { return m_options.size() == 1 && m_options[0].opt_id == opt_key; } diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 4b52592f2d..910c761c06 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -2262,6 +2262,12 @@ Vec3d PartPlate::estimate_wipe_tower_size(const DynamicPrintConfig & config, con } double volume = wipe_volume * (extruder_count == 2 ? plate_extruder_size : (plate_extruder_size - 1)); if (extruder_count == 2) volume += filament_change_volume * (int) (plate_extruder_size / 2); + // Read from the passed plate config — m_print may not have been applied yet + // (fresh plates, CLI), in which case its PrintConfig still holds defaults. + const auto *purge_opt = config.option("purge_in_prime_tower"); + const auto *semm_opt = config.option("single_extruder_multi_material"); + const bool semm_flush = purge_opt && purge_opt->value && semm_opt && semm_opt->value; + if (semm_flush) volume = WipeTower2::estimate_semm_flush_volume(config, plate_extruder_size); if (use_rib_wall) { depth = std::sqrt(volume / layer_height * extra_spacing); if (need_wipe_tower || plate_extruder_size > 1) { @@ -2274,7 +2280,9 @@ Vec3d PartPlate::estimate_wipe_tower_size(const DynamicPrintConfig & config, con } } else { - depth = volume/ (layer_height * w) *extra_spacing; + depth = volume / (layer_height * w); + // The flush volumes already hold the spacing between wipes. + if (!semm_flush) depth *= extra_spacing; if (need_wipe_tower || depth > EPSILON) { float min_wipe_tower_depth = WipeTower::get_limit_depth_by_height(max_height); depth = std::max((double)min_wipe_tower_depth, depth); @@ -2298,6 +2306,7 @@ arrangement::ArrangePolygon PartPlate::estimate_wipe_tower_polygon(const Dynamic bool enable_wrapping = (wrapping_opt != nullptr) && wrapping_opt->value; wt_size = estimate_wipe_tower_size(config, w, v, extruder_count, plate_extruder_size, use_global_objects, enable_wrapping); int plate_width=m_width, plate_depth=m_depth; + w = wt_size(0); // effective width; differs from prime_tower_width when the rib wall squares the tower float depth = wt_size(1); float margin = WIPE_TOWER_MARGIN + tower_brim_width, wp_brim_width = 0.f; const ConfigOption* wipe_tower_brim_width_opt = config.option("prime_tower_brim_width"); @@ -3336,6 +3345,11 @@ BoundingBoxf3 PartPlate::get_build_volume(bool use_share) return plate_box; } +Polygon PartPlate::get_shared_printable_polygon() const +{ + return m_extruder_areas.empty() ? Polygon::new_scale(m_shape) : get_shared_poly(m_extruder_areas); +} + bool PartPlate::contains(const Vec3d& point) const { return m_bounding_box.contains(point); @@ -4374,22 +4388,21 @@ void PartPlateList::set_default_wipe_tower_pos_for_plate(int plate_idx, bool ini f_volume_maps = wxGetApp().preset_bundle->get_default_nozzle_volume_types_for_filaments(filament_maps); } DynamicPrintConfig full_config = wxGetApp().preset_bundle->full_config(false, filament_maps, f_volume_maps); - const DynamicPrintConfig &print_cfg = wxGetApp().preset_bundle->prints.get_edited_preset().config; - float w = dynamic_cast(print_cfg.option("prime_tower_width"))->value; + float w = dynamic_cast(full_config.option("prime_tower_width"))->value; float v = dynamic_cast(full_config.option("prime_volume"))->value; bool enable_wrapping = false; const ConfigOptionBool *wrapping_opt = dynamic_cast(full_config.option("enable_wrapping_detection")); if (wrapping_opt) enable_wrapping = wrapping_opt->value; int nozzle_nums = wxGetApp().preset_bundle->get_printer_extruder_count(); - Vec3d wipe_tower_size = part_plate->estimate_wipe_tower_size(print_cfg, w, v, nozzle_nums, init_pos ? 2 : 0, false, enable_wrapping); + Vec3d wipe_tower_size = part_plate->estimate_wipe_tower_size(full_config, w, v, nozzle_nums, init_pos ? 2 : 0, false, enable_wrapping); if (!init_pos && (is_approx(wipe_tower_size(0), 0.0) || is_approx(wipe_tower_size(1), 0.0))) { - wipe_tower_size = part_plate->estimate_wipe_tower_size(print_cfg, w, v, nozzle_nums, 2, false, enable_wrapping); + wipe_tower_size = part_plate->estimate_wipe_tower_size(full_config, w, v, nozzle_nums, 2, false, enable_wrapping); } // Compute brim-aware margin: brim extends outward from tower position float brim_width = 0.f; - const ConfigOptionFloat *brim_opt = print_cfg.option("prime_tower_brim_width"); + const ConfigOptionFloat *brim_opt = full_config.option("prime_tower_brim_width"); if (brim_opt) { brim_width = brim_opt->value; if (brim_width < 0) brim_width = WipeTower::get_auto_brim_by_height((float) wipe_tower_size.z()); @@ -4411,6 +4424,18 @@ void PartPlateList::set_default_wipe_tower_pos_for_plate(int plate_idx, bool ini } } + // The bounding box above still allows a corner a delta or hexagonal bed does not have, and the + // prime tower is validated against the real outline — pull it onto the bed before storing. + { + Polygons bed{part_plate->get_shared_printable_polygon()}; + bed.front().translate(Point(-scaled(plate_origin.x()), -scaled(plate_origin.y()))); // into the frame x/y live in + const BoundingBox tower(Point::new_scale(x, y), + Point::new_scale(x + wipe_tower_size(0), y + wipe_tower_size(1))); + const Vec2f move = WipeTower::move_box_inside_polygon(tower, bed, scaled(margin)); + x += move.x(); + y += move.y(); + } + ConfigOptionFloat wt_x_opt(x); ConfigOptionFloat wt_y_opt(y); dynamic_cast(proj_cfg.option("wipe_tower_x"))->set_at(&wt_x_opt, plate_idx, 0); diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index 8f4055706f..47481dcad4 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -425,6 +425,9 @@ public: const BoundingBox get_bounding_box_crd(); BoundingBoxf3 get_plate_box() {return get_build_volume();} BoundingBoxf3 get_build_volume(bool use_share = false); + // Polygon counterpart of get_build_volume(true), in scaled world coordinates. The bounding box + // that one returns hides the corners a non-rectangular bed does not have. + Polygon get_shared_printable_polygon() const; const std::vector& get_exclude_areas() { return m_exclude_bounding_box; } diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index b40cd22697..989cf204e1 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -25,7 +25,6 @@ #include "GUI.hpp" #include "GUI_App.hpp" #include "MainFrame.hpp" -#include "slic3r/Utils/NetworkAgentFactory.hpp" #include "format.hpp" #include "Tab.hpp" #include "wxExtensions.hpp" @@ -128,22 +127,8 @@ PhysicalPrinterDialog::~PhysicalPrinterDialog() void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgroup) { m_optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) { - // Special handling for printer_agent: convert fake enum index to string agent ID - if (opt_key == "printer_agent") { - try { - int selected_idx = boost::any_cast(value); - auto agents = NetworkAgentFactory::get_registered_printer_agents(); - if (selected_idx >= 0 && selected_idx < static_cast(agents.size())) { - m_config->set_key_value("printer_agent", - new ConfigOptionString(agents[selected_idx].id)); - } - } catch (const boost::bad_any_cast&) { - // If value is not an int, ignore - } + if (opt_key == "host_type" || opt_key == "printhost_authorization_type") this->update(); - } else if (opt_key == "host_type" || opt_key == "printhost_authorization_type") { - this->update(); - } if (opt_key == "print_host") this->update_printhost_buttons(); if (opt_key == "printhost_port") @@ -154,47 +139,6 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr m_optgroup->append_single_option_line("host_type"); - // Build printer agent dropdown from registry (only if network agent is available) - if (wxGetApp().getAgent() != nullptr) { - auto agents = NetworkAgentFactory::get_registered_printer_agents(); - - if (!agents.empty()) { - // Create a fake enum option to force a Choice widget instead of TextCtrl - // (printer_agent is coString in config, but we need a dropdown) - ConfigOptionDef def; - def.type = coEnum; - def.width = Field::def_width_wider(); - def.label = L("Printer Agent"); - def.tooltip = L("Select the network agent implementation for printer communication. " - "Available agents are registered at startup."); - def.mode = comAdvanced; - - // Populate enum values and labels from registered agents - for (const auto& agent : agents) { - def.enum_values.push_back(agent.id); - def.enum_labels.push_back(agent.display_name); - } - - // Resolve selected agent: use config value if valid, otherwise fall back to default - std::string selected_agent = m_config->opt_string("printer_agent"); - auto it = std::find_if(agents.begin(), agents.end(), [&selected_agent](const auto& a) { return a.id == selected_agent; }); - if (it == agents.end()) { - selected_agent = ORCA_PRINTER_AGENT_ID; - it = std::find_if(agents.begin(), agents.end(), [&selected_agent](const auto& a) { return a.id == selected_agent; }); - } - - if (it != agents.end()) { - size_t default_idx = std::distance(agents.begin(), it); - def.set_default_value(new ConfigOptionInt(static_cast(default_idx))); - } - - // Create and append the option line - auto agent_option = Option(def, "printer_agent"); - Line agent_line = m_optgroup->create_single_option_line(agent_option); - m_optgroup->append_line(agent_line); - } - } - auto create_sizer_with_btn = [](wxWindow* parent, Button** btn, const std::string& icon_name, const wxString& label) { *btn = new Button(parent, label); (*btn)->SetStyle(ButtonStyle::Regular, ButtonType::Parameter); @@ -725,7 +669,7 @@ void PhysicalPrinterDialog::update(bool printer_change) } // For bbl printers, show option to control the device tab - if (wxGetApp().preset_bundle->is_bbl_vendor()) { + if (wxGetApp().preset_bundle->is_bbl_vendor() || wxGetApp().app_config->get_bool("use_printer_agents")) { m_optgroup->show_field("bbl_use_print_host_webui"); const bool use_print_host_webui = !current_webui.empty(); if (Field* printhost_webui_field = m_optgroup->get_field("bbl_use_print_host_webui"); printhost_webui_field) { @@ -816,31 +760,6 @@ void PhysicalPrinterDialog::update_host_type(bool printer_change) } } -void PhysicalPrinterDialog::update_printer_agent_type() -{ - if (m_config == nullptr) - return; - - Field* agent_field = m_optgroup->get_field("printer_agent"); - if (!agent_field) - return; - - Choice* agent_choice = dynamic_cast(agent_field); - if (!agent_choice) - return; - - // Sync selection with current config value - const std::string current_agent = m_config->opt_string("printer_agent"); - - auto agents = NetworkAgentFactory::get_registered_printer_agents(); - for (size_t i = 0; i < agents.size(); ++i) { - if (agents[i].id == current_agent) { - agent_choice->set_value(i); - return; - } - } -} - void PhysicalPrinterDialog::update_printers() { wxBusyCursor wait; @@ -894,11 +813,6 @@ void PhysicalPrinterDialog::OnOK(wxEvent& event) { wxGetApp().get_tab(Preset::TYPE_PRINTER)->save_preset("", false, false, true, m_preset_name); event.Skip(); - - // Defer printer agent switch to ensure preset save completes first - wxGetApp().CallAfter([] { - wxGetApp().switch_printer_agent(); - }); } }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.hpp b/src/slic3r/GUI/PhysicalPrinterDialog.hpp index 694e7aaf90..0ba2cad54f 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.hpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.hpp @@ -60,7 +60,6 @@ public: void update(bool printer_change = false); void update_host_type(bool printer_change); - void update_printer_agent_type(); void update_preset_input(); void update_printhost_buttons(); void update_printers(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 106c142fea..5b06db9d3e 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3246,7 +3246,8 @@ void Sidebar::update_all_preset_comboboxes() auto p_mainframe = wxGetApp().mainframe; auto cfg = preset_bundle.printers.get_edited_preset().config; - const bool use_native_device_tab = preset_bundle.use_bbl_device_tab() || NetworkAgentFactory::is_current_printer_agent_plugin(); + const bool use_printer_agents = wxGetApp().app_config->get_bool("use_printer_agents"); + const bool use_native_device_tab = preset_bundle.use_bbl_device_tab() || use_printer_agents; if (preset_bundle.use_bbl_network()) { //only show connection button for not-BBL printer @@ -3258,7 +3259,8 @@ void Sidebar::update_all_preset_comboboxes() p_mainframe->set_print_button_to_default(MainFrame::PrintSelectType::ePrintPlate); } else { //p->btn_connect_printer->Show(); - p->m_printer_connect->Show(); + // ORCA: hide the physical-printer connection button when printer agents are enabled + p->m_printer_connect->Show(!use_printer_agents); // ORCA: show/hide sync-ams button based on filament sync mode auto agent = wxGetApp().getAgent(); @@ -3280,10 +3282,14 @@ void Sidebar::update_all_preset_comboboxes() const auto host_type = cfg.option>("host_type")->value; if (cfg.has("printhost_apikey") && (host_type != htSimplyPrint)) apikey = cfg.opt_string("printhost_apikey"); - print_btn_type = preset_bundle.is_bbl_vendor() ? MainFrame::PrintSelectType::ePrintPlate : MainFrame::PrintSelectType::eSendGcode; + print_btn_type = (preset_bundle.is_bbl_vendor() || wxGetApp().app_config->get_bool("use_printer_agents")) + ? MainFrame::PrintSelectType::ePrintPlate + : MainFrame::PrintSelectType::eSendGcode; } - if (!use_native_device_tab) + if (use_printer_agents) + p_mainframe->load_printer_url(); + else if (!use_native_device_tab) p_mainframe->load_printer_url(url, apikey); @@ -3439,7 +3445,10 @@ void Sidebar::update_presets(Preset::Type preset_type) bool isBBL = preset_bundle.is_bbl_vendor(); bool is_dual_extruder = extruder_variants->size() == 2; - p->layout_printer(preset_bundle.use_bbl_network(), isBBL && is_dual_extruder); + // why: agent mode drives the native device tab, so the sidebar lays out like BBL + // (no physical-printer connect button). + p->layout_printer(preset_bundle.use_bbl_network() || wxGetApp().app_config->get_bool("use_printer_agents"), + isBBL && is_dual_extruder); // Update nozzle titles from printer config (e.g. "Main Nozzle" / "Auxiliary Nozzle" for N6) // UI left = DEPUTY_EXTRUDER_ID(1), UI right = MAIN_EXTRUDER_ID(0) @@ -5625,6 +5634,7 @@ struct Plater::priv void on_action_slice_all(SimpleEvent&); void on_action_publish(wxCommandEvent &evt); void on_action_print_plate(SimpleEvent&); + void open_machine_select_dialog(int plate_idx, PrintFromType print_type = PrintFromType::FROM_NORMAL); void on_action_print_all(SimpleEvent&); void on_action_export_gcode(SimpleEvent&); void on_action_send_gcode(SimpleEvent&); @@ -9493,7 +9503,7 @@ void Plater::priv::replace_all_with_stl() return; } - std::string status = _L("Replaced with 3D files from directory:\n").ToStdString() + out_path.string() + "\n\n"; + wxString status = _L("Replaced with 3D files from directory:\n") + from_u8(out_path.string()) + "\n\n"; for (unsigned int idx : volume_idxs) { const GLVolume* v = selection.get_volume(idx); @@ -9513,13 +9523,13 @@ void Plater::priv::replace_all_with_stl() std::string volume_name = volume->name; if (new_path == input_path) { - status += boost::str(boost::format(_L("✖ Skipped %1%: same file.\n").ToStdString()) % volume_name); + status += wxString::Format(_L("✖ Skipped %s: same file.\n"), from_u8(volume_name)); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " skipping replace volume : same filename " << new_path; continue; } if (!fs::exists(new_path)) { - status += boost::str(boost::format(_L("✖ Skipped %1%: file does not exist.\n").ToStdString()) % volume_name); + status += wxString::Format(_L("✖ Skipped %s: file does not exist.\n"), from_u8(volume_name)); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " cannot replace volume : filen does not exist " << new_path; continue; } @@ -9527,12 +9537,12 @@ void Plater::priv::replace_all_with_stl() BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " replacing volume : " << input_path << " with " << new_path; if (!replace_volume_with_stl(object_idx, volume_idx, new_path, _u8L("Replace with 3D file"))) { - status += boost::str(boost::format(_L("✖ Skipped %1%: failed to replace.\n").ToStdString()) % volume_name); + status += wxString::Format(_L("✖ Skipped %s: failed to replace.\n"), from_u8(volume_name)); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " cannot replace volume : failed to replace with " << new_path; continue; } - status += boost::str(boost::format(_L("✔ Replaced %1%.\n").ToStdString()) % volume_name); + status += wxString::Format(_L("✔ Replaced %s.\n"), from_u8(volume_name)); } // update 3D scene @@ -11166,18 +11176,23 @@ void Plater::priv::on_action_print_plate(SimpleEvent&) } PresetBundle& preset_bundle = *wxGetApp().preset_bundle; - if (preset_bundle.use_bbl_network()) { - // BBS - if (!m_select_machine_dlg) - m_select_machine_dlg = new SelectMachineDialog(q); - m_select_machine_dlg->set_print_type(PrintFromType::FROM_NORMAL); - m_select_machine_dlg->prepare(partplate_list.get_curr_plate_index()); - m_select_machine_dlg->ShowModal(); + if (preset_bundle.use_bbl_network() || wxGetApp().app_config->get_bool("use_printer_agents")) { + open_machine_select_dialog(partplate_list.get_curr_plate_index()); } else { q->send_gcode_legacy(PLATE_CURRENT_IDX, nullptr); } } +void Plater::priv::open_machine_select_dialog(int plate_idx, PrintFromType print_type) +{ + // BBS + if (!m_select_machine_dlg) + m_select_machine_dlg = new SelectMachineDialog(q); + m_select_machine_dlg->set_print_type(print_type); + m_select_machine_dlg->prepare(plate_idx); + m_select_machine_dlg->ShowModal(); +} + void Plater::priv::on_action_send_to_multi_machine(SimpleEvent&) { if (!m_send_multi_dlg) @@ -11193,10 +11208,7 @@ void Plater::priv::on_action_print_plate_from_sdcard(SimpleEvent&) } //BBS - if (!m_select_machine_dlg) m_select_machine_dlg = new SelectMachineDialog(q); - m_select_machine_dlg->set_print_type(PrintFromType::FROM_SDCARD_VIEW); - m_select_machine_dlg->prepare(0); - m_select_machine_dlg->ShowModal(); + open_machine_select_dialog(0, PrintFromType::FROM_SDCARD_VIEW); } void Plater::priv::on_tab_selection_changing(wxBookCtrlEvent& e) @@ -11211,13 +11223,13 @@ void Plater::priv::on_tab_selection_changing(wxBookCtrlEvent& e) sidebar_layout.show = new_sel == MainFrame::tp3DEditor || new_sel == MainFrame::tpPreview; update_sidebar(); int old_sel = e.GetOldSelection(); - const bool is_printer_agent_plugin = NetworkAgentFactory::is_current_printer_agent_plugin(); + const bool use_printer_agents = wxGetApp().app_config->get_bool("use_printer_agents"); const bool use_native_device_tab = wxGetApp().preset_bundle && - (wxGetApp().preset_bundle->use_bbl_device_tab() || is_printer_agent_plugin); + (wxGetApp().preset_bundle->use_bbl_device_tab() || use_printer_agents); if (use_native_device_tab && new_sel == MainFrame::tpMonitor) { // BBL network module is only required for BBL-vendor printers. // Non-BBL Python plugins (e.g. moonraker) drive the Device tab without it. - if (!is_printer_agent_plugin && wxGetApp().preset_bundle->is_bbl_vendor() && !Slic3r::NetworkAgent::is_network_module_loaded()) { + if (!use_printer_agents && wxGetApp().preset_bundle->is_bbl_vendor() && !Slic3r::NetworkAgent::is_network_module_loaded()) { e.Veto(); BOOST_LOG_TRIVIAL(info) << boost::format("skipped tab switch from %1% to %2%, lack of network plugins") % old_sel % new_sel; if (q) { @@ -11226,9 +11238,14 @@ void Plater::priv::on_tab_selection_changing(wxBookCtrlEvent& e) } } } else { - if (new_sel == MainFrame::tpMonitor && wxGetApp().preset_bundle != nullptr) { + const bool selecting_web_device_tab = main_frame->m_printer_view && + main_frame->m_tabpanel->GetPage(new_sel) == main_frame->m_printer_view; + if (selecting_web_device_tab) { + // Use the selected discovered machine when the preset has no host. + main_frame->load_printer_url(); + } else if (new_sel == MainFrame::tpMonitor && wxGetApp().preset_bundle != nullptr) { auto cfg = wxGetApp().preset_bundle->printers.get_edited_preset().config; - wxString url = cfg.opt_string("print_host_webui").empty() ? cfg.opt_string("print_host") : cfg.opt_string("print_host_webui"); + wxString url = from_u8(PrintHost::get_print_host_webui(&cfg)); if (main_frame->m_printer_view && url.empty()) { // It's missing_connection page, reload so that we can replay the gif image main_frame->m_printer_view->reload(); @@ -11273,13 +11290,8 @@ void Plater::priv::on_action_print_all(SimpleEvent&) } PresetBundle& preset_bundle = *wxGetApp().preset_bundle; - if (preset_bundle.use_bbl_network()) { - // BBS - if (!m_select_machine_dlg) - m_select_machine_dlg = new SelectMachineDialog(q); - m_select_machine_dlg->set_print_type(PrintFromType::FROM_NORMAL); - m_select_machine_dlg->prepare(PLATE_ALL_IDX); - m_select_machine_dlg->ShowModal(); + if (preset_bundle.use_bbl_network() || wxGetApp().app_config->get_bool("use_printer_agents")) { + open_machine_select_dialog(PLATE_ALL_IDX); } else { q->send_gcode_legacy(PLATE_ALL_IDX, nullptr); } diff --git a/src/slic3r/GUI/PluginSource.hpp b/src/slic3r/GUI/PluginSource.hpp index ee1464c8df..8742153c9e 100644 --- a/src/slic3r/GUI/PluginSource.hpp +++ b/src/slic3r/GUI/PluginSource.hpp @@ -11,6 +11,7 @@ namespace Slic3r // IMPORTANT: ordinal order is the Plugins dialog Source sort priority. Mine, Subscribed, + Orphaned, Local }; @@ -20,6 +21,7 @@ namespace Slic3r { case PluginSource::Mine: return "mine"; case PluginSource::Subscribed: return "subscribed"; + case PluginSource::Orphaned: return "orphaned"; case PluginSource::Local: return "local"; } diff --git a/src/slic3r/GUI/PluginsDialog.cpp b/src/slic3r/GUI/PluginsDialog.cpp index 23cf7a2648..a39fcbc535 100644 --- a/src/slic3r/GUI/PluginsDialog.cpp +++ b/src/slic3r/GUI/PluginsDialog.cpp @@ -103,6 +103,7 @@ struct PluginDialogItem bool loading = false; bool is_cloud_plugin = false; + bool orphaned = false; bool has_local_package = false; bool unauthorized = false; bool has_script_capability = false; @@ -246,6 +247,7 @@ nlohmann::json build_plugin_payload_item(const PluginDialogItem& dialog_item) payload_item["sharing_token"] = dialog_item.sharing_token; payload_item["thumbnail_url"] = dialog_item.thumbnail_url; payload_item["installed"] = dialog_item.has_local_package; + payload_item["orphaned"] = dialog_item.orphaned; payload_item["installed_version"] = dialog_item.installed_version; payload_item["latest_version"] = dialog_item.latest_version; return payload_item; @@ -268,7 +270,8 @@ PluginSource derive_plugin_source(const PluginDescriptor& descriptor) const bool is_cloud = descriptor.is_cloud_plugin(); const bool is_mine = is_cloud && has_cloud_meta && descriptor.cloud->is_mine; - // Source is ownership/locality only; issue states never replace this badge. + if (is_cloud && has_cloud_meta && descriptor.cloud->orphaned) + return PluginSource::Orphaned; if (is_mine) return PluginSource::Mine; if (is_cloud) @@ -281,11 +284,12 @@ PluginAvailableActions evaluate_action_policy(const PluginDialogItem& item) PluginAvailableActions available_actions; const bool is_loading = item.status == PluginStatus::Loading; const bool is_cloud = item.is_cloud_plugin; + const bool is_orphaned = item.orphaned; const bool is_mine = item.source == PluginSource::Mine; const bool has_local = item.has_local_package; const bool authorized_for_install = !item.unauthorized; - available_actions.toggle_installs_cloud_plugin = is_cloud && !has_local && authorized_for_install; + available_actions.toggle_installs_cloud_plugin = is_cloud && !is_orphaned && !has_local && authorized_for_install; available_actions.can_toggle = !is_loading && (has_local || available_actions.toggle_installs_cloud_plugin); auto add_action = [&available_actions](const char* id, const char* label, bool enabled = true, bool danger = false) { @@ -294,7 +298,7 @@ PluginAvailableActions evaluate_action_policy(const PluginDialogItem& item) // Owned cloud plugins fall through to the local delete: it removes the installed package only. // Deleting a plugin from the cloud is a plugin hub operation and is never offered here. - if (is_cloud && !is_mine) { + if (is_cloud && !is_orphaned && !is_mine) { add_action("unsubscribe_plugin", "Unsubscribe", true, true); } else if (has_local) { add_action("delete_plugin", "Delete", true, true); @@ -302,11 +306,13 @@ PluginAvailableActions evaluate_action_policy(const PluginDialogItem& item) add_action("open_folder", "Show in folder", has_local); - if (is_cloud) { - add_action("reinstall_plugin", "Reinstall"); - } else { - add_action("reload_plugin", "Reload"); - add_action("clear_cache_reload_plugin", "Delete cache and reload"); + if (!is_orphaned) { + if (is_cloud) { + add_action("reinstall_plugin", "Reinstall"); + } else { + add_action("reload_plugin", "Reload"); + add_action("clear_cache_reload_plugin", "Delete cache and reload"); + } } return available_actions; @@ -360,6 +366,7 @@ PluginDialogItem build_plugin_dialog_item(const PluginDescriptor& descriptor) item.error_text = descriptor.normalized_error(); item.has_error = descriptor.has_error(); item.is_cloud_plugin = descriptor.is_cloud_plugin(); + item.orphaned = descriptor.cloud.has_value() && descriptor.cloud->orphaned; item.has_local_package = descriptor.has_local_package(); item.unauthorized = descriptor.is_unauthorized(); item.is_loaded = manager.is_plugin_loaded(descriptor.plugin_key); @@ -592,7 +599,35 @@ bool PluginsDialog::get_descriptor(const std::string& plugin_key, PluginDescript void PluginsDialog::refresh_plugin_metadata_async(const wxString& title, const wxString& message, bool fetch_cloud) { - run_with_dialog([fetch_cloud]() { refresh_plugin_metadata_blocking(fetch_cloud); }, [this]() { send_plugins(); }, title, message); + run_with_dialog([fetch_cloud]() { refresh_plugin_metadata_blocking(fetch_cloud); }, [this]() { + prompt_for_missing_plugins(); + send_plugins(); + }, title, message); +} + +void PluginsDialog::prompt_for_missing_plugins() +{ + PluginManager& manager = PluginManager::instance(); + const std::vector missing = manager.get_missing_plugin_descriptors(); + if (missing.empty()) + return; + + wxString names; + std::vector keys; + keys.reserve(missing.size()); + for (const PluginDescriptor& plugin : missing) { + keys.push_back(plugin.plugin_key); + names += "\n- "; + names += plugin_display_name(plugin.plugin_key); + } + + const int result = wxMessageBox( + wxString::Format(_L("The following installed plugins were not found on disk:\n%s\n\nRemove them from OrcaSlicer?"), names), + _L("Missing Plugins"), wxYES_NO | wxNO_DEFAULT | wxICON_WARNING, this); + restore_z_order(); + + if (result == wxYES) + manager.remove_missing_plugins(keys); } void PluginsDialog::refresh_plugins() diff --git a/src/slic3r/GUI/PluginsDialog.hpp b/src/slic3r/GUI/PluginsDialog.hpp index a0e7bd8022..e663de79e4 100644 --- a/src/slic3r/GUI/PluginsDialog.hpp +++ b/src/slic3r/GUI/PluginsDialog.hpp @@ -68,6 +68,7 @@ private: bool get_descriptor(const std::string& plugin_key, Slic3r::PluginDescriptor& descriptor) const; void refresh_plugin_metadata_async(const wxString& title, const wxString& message, bool fetch_cloud); + void prompt_for_missing_plugins(); void refresh_plugins(); void toggle_plugin(const std::string& plugin_key, bool enabled); void toggle_plugin_capability(const std::string& plugin_key, PluginCapabilityType type, const std::string& capability_name, bool enabled); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index bd5b7420ff..f802ba6ecb 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -700,6 +700,12 @@ wxBoxSizer *PreferencesDialog::create_item_spinctrl(wxString title, wxString tit auto input = new SpinInput(m_parent, wxEmptyString, side_label, wxDefaultPosition, DESIGN_INPUT_SIZE, wxSP_ARROW_KEYS, min, max, stoi(app_config->get(param))); input->SetToolTip(tip); + // ORCA: this one is only meaningful while the dimming it controls is enabled + if (param == "preview_dim_previous_layers_brightness") { + m_dim_previous_layers_brightness_input = input; + input->Enable(app_config->get_bool("preview_dim_previous_layers")); + } + m_sizer->Add(input, 0, wxALIGN_CENTER_VERTICAL); if(!title2.empty()){ @@ -1050,8 +1056,10 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxString too wxGetApp().mainframe->m_webview->SendCloudProvidersInfo(); } } - // ORCA: apply the preview dimming change immediately to the currently loaded preview (ported from preFlight) + // ORCA: apply the preview dimming change immediately to the currently loaded preview else if (param == "preview_dim_previous_layers") { + if (m_dim_previous_layers_brightness_input) + m_dim_previous_layers_brightness_input->Enable(app_config->get_bool(param)); if (Plater* plater = wxGetApp().plater()) { if (GLCanvas3D* canvas = plater->get_preview_canvas3D()) { canvas->get_gcode_viewer().set_dim_previous_layers(app_config->get_bool(param)); @@ -1127,6 +1135,14 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxString too wxGetApp().plater()->sidebar().update_presets(Preset::TYPE_FILAMENT); } + if (param == "use_printer_agents") + { + // Rebuild the Device tab so the native/web-UI choice reflects the new flag + // immediately, instead of only on the next printer-preset change or restart. + if (wxGetApp().plater()) + wxGetApp().plater()->sidebar().update_all_preset_comboboxes(); + } + if (param == "enable_high_low_temp_mixed_printing") { if (checkbox->GetValue()) { const wxString warning_title = _L("Bed Temperature Difference Warning"); @@ -1914,6 +1930,28 @@ void PreferencesDialog::create_items() ); g_sizer->Add(item_dim_previous_layers); + auto item_dim_previous_layers_brightness = create_item_spinctrl( + _L("Dimmed layer brightness"), + "", + _L("%"), + _L("How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n" + "99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option."), + "preview_dim_previous_layers_brightness", + 0, + 99, + // ORCA: apply the new brightness immediately to the currently loaded preview + [](int value) { + if (Plater* plater = wxGetApp().plater()) { + if (GLCanvas3D* canvas = plater->get_preview_canvas3D()) { + canvas->get_gcode_viewer().set_dim_previous_layers_brightness(0.01f * value); + canvas->set_as_dirty(); + canvas->request_extra_frame(); + } + } + } + ); + g_sizer->Add(item_dim_previous_layers_brightness); + g_sizer->AddSpacer(FromDIP(10)); sizer_page->Add(g_sizer, 0, wxEXPAND); @@ -2071,6 +2109,12 @@ void PreferencesDialog::create_items() auto item_show_unsupported = create_item_checkbox(_L("Show unsupported presets"), _L("Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."), "show_unsupported_presets"); g_sizer->Add(item_show_unsupported); + auto item_plugin_printer_agents = create_item_checkbox( + _L("(Experimental) Use printer agents instead of print hosts"), _L( + "Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\nWhen disabled, OrcaSlicer uses the legacy print-host behavior."), + "use_printer_agents"); + g_sizer->Add(item_plugin_printer_agents); + //// DEVELOPER > Experimental Features g_sizer->Add(create_item_title(_L("Experimental Features")), 1, wxEXPAND); diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp index 95bfcb5367..94340ce619 100644 --- a/src/slic3r/GUI/Preferences.hpp +++ b/src/slic3r/GUI/Preferences.hpp @@ -13,6 +13,7 @@ #include "Widgets/ComboBox.hpp" #include "Widgets/CheckBox.hpp" #include "Widgets/TextInput.hpp" +#include "Widgets/SpinInput.hpp" #include "Widgets/TabCtrl.hpp" #include "slic3r/Utils/bambu_networking.hpp" @@ -71,6 +72,7 @@ public: ::CheckBox * m_sync_user_preset_checkbox = {nullptr}; ::CheckBox * m_bambu_cloud_checkbox = {nullptr}; ::TextInput *m_backup_interval_textinput = {nullptr}; + ::SpinInput *m_dim_previous_layers_brightness_input = {nullptr}; ::ComboBox * m_network_version_combo = {nullptr}; std::vector m_available_versions; diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 8fdca030c6..c979fc3212 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -865,6 +865,9 @@ PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset clr_picker = new wxBitmapButton(parent, wxID_ANY, {}, wxDefaultPosition, wxSize(FromDIP(20), FromDIP(20)), wxBU_EXACTFIT | wxBU_AUTODRAW | wxBORDER_NONE); clr_picker->SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); clr_picker->SetToolTip(_L("Click to select filament color")); +#ifdef __WXGTK__ + RemoveButtonBorder(clr_picker); +#endif clr_picker->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) { // Check if it's an official filament auto fila_type = Preset::remove_suffix_modified(GetValue().ToUTF8().data()); diff --git a/src/slic3r/GUI/ReleaseNote.cpp b/src/slic3r/GUI/ReleaseNote.cpp index 22f65f4a60..7b2d091176 100644 --- a/src/slic3r/GUI/ReleaseNote.cpp +++ b/src/slic3r/GUI/ReleaseNote.cpp @@ -1991,7 +1991,7 @@ void InputIpAddressDialog::workerThreadFunc(std::string str_ip, std::string str_ if (w.expired()) return; if (m_obj) { - m_obj->set_user_access_code(str_access_code); + m_obj->set_access_code(str_access_code); wxGetApp().getDeviceManager()->set_selected_machine(m_obj->get_dev_id()); } @@ -2055,6 +2055,11 @@ void InputIpAddressDialog::on_text(wxCommandEvent &evt) { auto str_ip = m_input_ip->GetTextCtrl()->GetValue(); auto str_access_code = m_input_access_code->GetTextCtrl()->GetValue(); + + if (str_access_code.empty()) { + str_access_code = "88888888"; + } + auto str_name = m_input_printer_name->GetTextCtrl()->GetValue().Strip(wxString::both); auto str_sn = m_input_sn->GetTextCtrl()->GetValue().Strip(wxString::both); bool invalid_access_code = true; @@ -2062,7 +2067,7 @@ void InputIpAddressDialog::on_text(wxCommandEvent &evt) for (char c : str_access_code) { if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))) { invalid_access_code = false; - return; + break; } } diff --git a/src/slic3r/GUI/SavePresetDialog.cpp b/src/slic3r/GUI/SavePresetDialog.cpp index 52bcbed4de..0b33e48ec4 100644 --- a/src/slic3r/GUI/SavePresetDialog.cpp +++ b/src/slic3r/GUI/SavePresetDialog.cpp @@ -112,12 +112,56 @@ SavePresetDialog::Item::Item(Preset::Type type, const std::string &suffix, wxBox sizer->Add(m_radio_group, 0, wxEXPAND | wxTOP | wxLEFT, BORDER_W); if (parent->m_mode == comDevelop) { - m_detach_checkbox = new wxCheckBox(parent, wxID_ANY, _L("Detach from parent")); - sizer->Add(m_detach_checkbox, 0, wxALIGN_LEFT | wxALL, BORDER_W); - // Set initial state (unchecked by default) - m_detach_checkbox->SetValue(m_detach); - // Bind the checkbox event to update the detach state for this item - m_detach_checkbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) { m_detach = m_detach_checkbox->GetValue(); }); + // A new user copy of a system preset inherits from the selected system preset. + const std::string parent_name = sel_preset.is_system ? sel_preset.name : sel_preset.inherits(); + const bool can_detach = !parent_name.empty(); + + wxBoxSizer *detach_sizer = new wxBoxSizer(wxHORIZONTAL); + + auto detach_tooltip = _L("Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."); + + auto detach_checkbox = new ::CheckBox(parent); + detach_checkbox->SetToolTip(detach_tooltip); + + auto detach_label = new wxStaticText(parent, wxID_ANY, _L("Detach from parent")); + detach_label->SetFont(::Label::Body_14); + detach_label->SetToolTip(detach_tooltip); + + detach_sizer->Add(detach_checkbox, 0, wxALIGN_LEFT | wxLEFT, BORDER_W); + detach_sizer->Add(detach_label , 0, wxALIGN_CENTRE_VERTICAL | wxLEFT, FromDIP(5)); + sizer->Add(detach_sizer, 0, wxEXPAND | wxTOP, BORDER_W); + sizer->AddSpacer(FromDIP(5)); + + const wxString parent_text = can_detach ? from_u8(parent_name) : _L("Unique preset"); + auto parent_label = new wxStaticText(parent, wxID_ANY, parent_text); + parent_label->SetFont(::Label::Body_12); + parent_label->SetForegroundColour(wxColour("#6B6B6B")); + parent_label->SetToolTip(can_detach ? _L("Parent preset") : _L("This preset does not inherit from another preset.")); + sizer->Add(parent_label, 0, wxEXPAND | wxLEFT, BORDER_W + FromDIP(24)); + + sizer->AddSpacer(FromDIP(5)); + + if (!can_detach) { + detach_checkbox->Disable(); + detach_label->SetForegroundColour(wxColour("#6B6B6B")); + } + else { + // Set initial state (unchecked by default) + detach_checkbox->SetValue(m_detach); + // Bind the checkbox event to update the detach state for this item + detach_checkbox->Bind(wxEVT_TOGGLEBUTTON, [this, detach_checkbox](wxCommandEvent&) { m_detach = detach_checkbox->GetValue(); }); + + detach_label->SetForegroundColour(wxColour("#363636")); + + auto on_toggle = [this, detach_checkbox]() { + detach_checkbox->SetValue(!detach_checkbox->GetValue()); + wxCommandEvent ev(wxEVT_TOGGLEBUTTON, detach_checkbox->GetId()); + ev.SetEventObject(detach_checkbox); + detach_checkbox->GetEventHandler()->ProcessEvent(ev); + }; + detach_label->Bind(wxEVT_LEFT_DOWN, [on_toggle](wxMouseEvent& e) {if(!e.LeftDClick()) on_toggle();}); + detach_label->Bind(wxEVT_LEFT_DCLICK, [on_toggle](wxMouseEvent& e) {on_toggle();}); + } } m_radio_group->Bind(wxEVT_COMMAND_RADIOBOX_SELECTED, [this](wxCommandEvent &e) { diff --git a/src/slic3r/GUI/SavePresetDialog.hpp b/src/slic3r/GUI/SavePresetDialog.hpp index 0b71325927..05aa1b2d39 100644 --- a/src/slic3r/GUI/SavePresetDialog.hpp +++ b/src/slic3r/GUI/SavePresetDialog.hpp @@ -75,7 +75,6 @@ class SavePresetDialog : public DPIDialog bool m_save_to_project {false}; RadioGroup* m_radio_group; // ORCA bool m_detach{false}; - wxCheckBox* m_detach_checkbox{nullptr}; void update(); }; diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 1ab78fcc11..6cc988b879 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -3629,7 +3629,7 @@ void SelectMachineDialog::on_send_print() BOOST_LOG_TRIVIAL(error) << "build_nozzle_info errors"; } - m_print_job->sdcard_state = obj_->GetStorage()->get_sdcard_state(); + m_print_job->sdcard_state = obj_->GetStorage()->get_sdcard_state(); m_print_job->has_sdcard = wxGetApp().app_config->get("allow_abnormal_storage") == "true" ? (m_print_job->sdcard_state == DevStorage::SdcardState::HAS_SDCARD_NORMAL || m_print_job->sdcard_state == DevStorage::SdcardState::HAS_SDCARD_ABNORMAL) @@ -3868,12 +3868,11 @@ _compare_obj_names(MachineObject* obj1, MachineObject* obj2) } /******************************************************************* -*@note _collect_machine_list -*@param dev_manager -- the device manager -*@param sorted_machine_objs -- return the sorted machine objects -*@param best_one -- return the best one -*/ -/*******************************************************************/ +* @note _collect_machine_list +* @param dev_manager -- the device manager +* @param sorted_machine_objs -- return the sorted machine objects +* @param best_one -- return the best one +*******************************************************************/ static void _collect_sorted_machines(Slic3r::DeviceManager* dev_manager, std::vector& sorted_machine_objs) diff --git a/src/slic3r/GUI/SelectMachinePop.cpp b/src/slic3r/GUI/SelectMachinePop.cpp index 492199569e..96324fb4d8 100644 --- a/src/slic3r/GUI/SelectMachinePop.cpp +++ b/src/slic3r/GUI/SelectMachinePop.cpp @@ -704,7 +704,6 @@ void SelectMachinePopup::update_user_devices() } mobj->set_access_code(""); - mobj->erase_user_access_code(); } if (GUI::wxGetApp().plater()) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 5d6a545873..b6d7abde21 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1270,9 +1270,7 @@ void Selection::translate(const Vec3d &displacement, TransformationType transfor } else { if (v.is_wipe_tower) {//in world cs int plate_idx = v.object_idx() - 1000; - BoundingBoxf3 plate_bbox = wxGetApp().plater()->get_partplate_list().get_plate(plate_idx)->get_build_volume(true); - BoundingBox plate_bbox2d = BoundingBox(scaled(Vec2f(plate_bbox.min[0], plate_bbox.min[1])), scaled(Vec2f(plate_bbox.max[0], plate_bbox.max[1]))); - Vec3d tower_size = v.bounding_box().size(); + const Polygons bed_polys{wxGetApp().plater()->get_partplate_list().get_plate(plate_idx)->get_shared_printable_polygon()}; Vec3d tower_origin = m_cache.volumes_data[i].get_volume_position(); Vec3d actual_displacement = displacement; bool show_read_wipe_tower = wxGetApp().plater()->get_partplate_list().get_plate(plate_idx)->fff_print()->is_step_done(psWipeTower); @@ -1287,18 +1285,7 @@ void Selection::translate(const Vec3d &displacement, TransformationType transfor BoundingBoxf3 tower_bbox = v.bounding_box(); tower_bbox.translate(actual_displacement + tower_origin); BoundingBox tower_bbox2d = BoundingBox(scaled(Vec2f(tower_bbox.min[0], tower_bbox.min[1])), scaled(Vec2f(tower_bbox.max[0], tower_bbox.max[1]))); - Vec2f offset = WipeTower::move_box_inside_box(tower_bbox2d, plate_bbox2d,scaled(margin)); - //if (tower_origin(0) + actual_displacement(0) - margin < plate_bbox.min(0)) { - // actual_displacement(0) = plate_bbox.min(0) - tower_origin(0) + margin; - //} else if (tower_origin(0) + actual_displacement(0) + tower_size(0) + margin > plate_bbox.max(0)) { - // actual_displacement(0) = plate_bbox.max(0) - tower_origin(0) - tower_size(0) - margin; - //} - - //if (tower_origin(1) + actual_displacement(1) - margin < plate_bbox.min(1)) { - // actual_displacement(1) = plate_bbox.min(1) - tower_origin(1) + margin; - //} else if (tower_origin(1) + actual_displacement(1) + tower_size(1) + margin > plate_bbox.max(1)) { - // actual_displacement(1) = plate_bbox.max(1) - tower_origin(1) - tower_size(1) - margin; - //} + const Vec2f offset = WipeTower::move_box_inside_polygon(tower_bbox2d, bed_polys, scaled(margin)); actual_displacement += Vec3d(offset[0], offset[1],0); v.set_volume_offset(m_cache.volumes_data[i].get_volume_position() + actual_displacement); } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index ef830b7f35..1a31355d0e 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -33,6 +33,7 @@ #include "GUI_App.hpp" #include "GUI_ObjectList.hpp" +#include "slic3r/Utils/NetworkAgentFactory.hpp" #include "slic3r/Utils/PresetUpdater.hpp" #include "slic3r/plugin/PluginConfig.hpp" #include "Plater.hpp" @@ -1738,6 +1739,13 @@ void Tab::toggle_line(const std::string &opt_key, bool toggle, int opt_index) if (line) line->toggle_visible = toggle; }; +void Tab::set_option_label(const std::string &opt_key, const wxString &label, int opt_index) +{ + if (!m_active_page) return; + Line *line = m_active_page->get_line(opt_key, opt_index); + if (line) line->set_label(label); +} + // To be called by custom widgets, load a value into a config, // update the preset selection boxes (the dirty flags) // If value is saved before calling this function, put saved_value = true, @@ -2128,43 +2136,9 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) m_last_sparse_infill_rotate_template_value = m_config->opt_string("sparse_infill_rotate_template"); } - if(opt_key=="layer_height"){ - auto min_layer_height_from_nozzle=m_preset_bundle->full_config().option("min_layer_height")->values; - auto max_layer_height_from_nozzle=m_preset_bundle->full_config().option("max_layer_height")->values; - auto layer_height_floor = *std::min_element(min_layer_height_from_nozzle.begin(), min_layer_height_from_nozzle.end()); - auto layer_height_ceil = *std::max_element(max_layer_height_from_nozzle.begin(), max_layer_height_from_nozzle.end()); - const auto lh = m_config->opt_float("layer_height"); - bool exceed_minimum_flag = lh < layer_height_floor; - bool exceed_maximum_flag = lh > layer_height_ceil; - - if (exceed_maximum_flag || exceed_minimum_flag) { - if (lh < EPSILON) { - auto msg_text = _(L("Layer height is too small.\nIt will set to min_layer_height\n")); - MessageDialog dialog(wxGetApp().plater(), msg_text, "", wxICON_WARNING | wxOK); - dialog.SetButtonLabel(wxID_OK, _L("OK")); - dialog.ShowModal(); - auto new_conf = *m_config; - new_conf.set_key_value("layer_height", new ConfigOptionFloat(layer_height_floor)); - m_config_manipulation.apply(m_config, &new_conf); - } else { - wxString msg_text = _(L("Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, " - "this may cause printing quality issues.")); - msg_text += "\n\n" + _(L("Adjust to the set range automatically?\n")); - MessageDialog dialog(wxGetApp().plater(), msg_text, "", wxICON_WARNING | wxYES | wxNO); - dialog.SetButtonLabel(wxID_YES, _L("Adjust")); - dialog.SetButtonLabel(wxID_NO, _L("Ignore")); - auto answer = dialog.ShowModal(); - auto new_conf = *m_config; - if (answer == wxID_YES) { - if (exceed_maximum_flag) - new_conf.set_key_value("layer_height", new ConfigOptionFloat(layer_height_ceil)); - if (exceed_minimum_flag) - new_conf.set_key_value("layer_height", new ConfigOptionFloat(layer_height_floor)); - m_config_manipulation.apply(m_config, &new_conf); - } - } + if (opt_key == "layer_height") { + if (m_config_manipulation.check_layer_height(m_config)) wxGetApp().plater()->update(); - } } string opt_key_without_idx = opt_key.substr(0, opt_key.find('#')); @@ -2816,6 +2790,7 @@ void TabPrint::build() optgroup->append_single_option_line("fill_multiline", "strength_settings_infill#fill-multiline"); optgroup->append_single_option_line("sparse_infill_pattern", "strength_settings_infill#sparse-infill-pattern"); optgroup->append_single_option_line("gyroid_optimized", "strength_settings_patterns#gyroid-optimized"); + optgroup->append_single_option_line("sparse_infill_smooth_factor", "strength_settings_patterns#sparse-infill-smooth-factor"); optgroup->append_single_option_line("infill_direction", "strength_settings_infill#direction"); optgroup->append_single_option_line("sparse_infill_rotate_template", "strength_settings_infill_rotation_template_metalanguage"); optgroup->append_single_option_line("skin_infill_density", "strength_settings_patterns#locked-zag"); @@ -3069,6 +3044,7 @@ void TabPrint::build() optgroup->append_single_option_line("combine_brims", "others_settings_brim#combine-brims"); optgroup->append_single_option_line("brim_ears_max_angle", "others_settings_brim#ear-max-angle"); optgroup->append_single_option_line("brim_ears_detection_length", "others_settings_brim#ear-detection-radius"); + optgroup->append_single_option_line("brim_ears_outer_only", "others_settings_brim#brim-ears-outer-only"); optgroup = page->new_optgroup(L("Special mode"), L"param_special"); optgroup->append_single_option_line("slicing_mode", "others_settings_special_mode#slicing-mode"); @@ -3997,13 +3973,12 @@ void TabFilament::add_filament_overrides_page() const int extruder_idx = 0; // #ys_FIXME - ConfigOptionsGroupShp retraction_optgroup = page->new_optgroup(L("Retraction"), L"param_retraction"); - auto append_retraction_option = [this, retraction_optgroup](const std::string& opt_key, int opt_index) + auto append_retraction_option = [this](ConfigOptionsGroupShp optgroup, const std::string& opt_key, int opt_index) { Line line {"",""}; - line = retraction_optgroup->create_single_option_line(retraction_optgroup->get_option(opt_key, opt_index)); + line = optgroup->create_single_option_line(optgroup->get_option(opt_key, opt_index)); - line.near_label_widget = [this, optgroup_wk = ConfigOptionsGroupWkp(retraction_optgroup), opt_key, opt_index](wxWindow* parent) { + line.near_label_widget = [this, optgroup_wk = ConfigOptionsGroupWkp(optgroup), opt_key, opt_index](wxWindow* parent) { auto check_box = new ::CheckBox(parent); // ORCA modernize checkboxes check_box->Bind(wxEVT_TOGGLEBUTTON, [this, optgroup_wk, opt_key, opt_index](wxCommandEvent& evt) { const bool is_checked = evt.IsChecked(); @@ -4030,9 +4005,10 @@ void TabFilament::add_filament_overrides_page() return check_box; }; - retraction_optgroup->append_line(line); + optgroup->append_line(line); }; + ConfigOptionsGroupShp retraction_optgroup = page->new_optgroup(L("Retraction"), L"param_retraction"); for (const std::string opt_key : { "filament_retraction_length", "filament_z_hop", "filament_z_hop_types", @@ -4056,7 +4032,13 @@ void TabFilament::add_filament_overrides_page() //SoftFever // "filament_seam_gap" }) - append_retraction_option(opt_key, extruder_idx); + append_retraction_option(retraction_optgroup, opt_key, extruder_idx); + + ConfigOptionsGroupShp toolchange_optgroup = page->new_optgroup(L("Retraction when switching material"), L"param_retraction_material_change"); + for (const std::string opt_key : { "filament_retract_length_toolchange", + "filament_retract_restart_extra_toolchange" + }) + append_retraction_option(toolchange_optgroup, opt_key, extruder_idx); ConfigOptionsGroupShp ironing_optgroup = page->new_optgroup(L("Ironing"), L"param_ironing"); auto append_ironing_option = [this, ironing_optgroup](const std::string& opt_key, int opt_index) @@ -4171,6 +4153,8 @@ void TabFilament::update_filament_overrides_page(const DynamicPrintConfig* print "filament_retraction_speed", "filament_deretraction_speed", "filament_retract_restart_extra", + "filament_retract_length_toolchange", + "filament_retract_restart_extra_toolchange", "filament_retraction_minimum_travel", "filament_retract_when_changing_layer", "filament_wipe", @@ -4201,7 +4185,8 @@ void TabFilament::update_filament_overrides_page(const DynamicPrintConfig* print is_checked &= !dynamic_cast(m_config->option(opt_key))->is_nil(extruder_idx); m_overrides_options[opt_key]->SetValue(is_checked); - Field* field = optgroup->get_fieldc(opt_key, 0); + // the toolchange overrides live in their own optgroup, so search the whole page + Field* field = page->get_field(opt_key, 0); if (field == nullptr) continue; if (opt_key == "filament_long_retractions_when_cut") { @@ -5007,8 +4992,43 @@ void TabPrinter::build_fff() optgroup->append_single_option_line("printer_structure", "printer_basic_information_advanced#printer-structure"); optgroup->append_single_option_line("gcode_flavor", "printer_basic_information_advanced#g-code-flavor"); + optgroup->append_single_option_line("gcode_skip_config_block", "printer_basic_information_advanced#skip-g-code-config-block"); optgroup->append_single_option_line("pellet_modded_printer", "printer_basic_information_advanced#pellet-modded-printer"); optgroup->append_single_option_line("bbl_use_printhost", "printer_basic_information_advanced#use-3rd-party-print-host"); + + // "Printer Agent" dropdown - printer_agent is a coString; gui_type routes it to + // PrinterAgentChoice instead of a TextCtrl. Rows and values come from the live agent + // registry, and the value is stored as the agent-id string. + if (wxGetApp().getAgent() != nullptr) + { + auto registered_printer_agents = NetworkAgentFactory::get_registered_printer_agents(); + if (!registered_printer_agents.empty()) + { + ConfigOptionDef def; + def.type = coString; + def.gui_type = ConfigOptionDef::GUIType::printer_agent_select; + def.width = 3 * Field::def_width_wider() / 2; + def.label = L("Printer Agent"); + def.tooltip = L("Select the network agent implementation for printer communication. " + "Available agents are registered at startup."); + def.mode = comAdvanced; + + // Create the field without get_option() so it is not registered in m_opt_map. + // ConfigOptionsGroup handles printer_agent before the generic mapped write path. + Line agent_line = optgroup->create_single_option_line(Option(def, "printer_agent")); + optgroup->append_line(agent_line); + if (Field* agent_field = get_field("printer_agent")) + { + if (auto* choice = dynamic_cast(agent_field); choice && choice->getWindow()) + choice->set_value(m_config->opt_string("printer_agent"), false); + } + + // Register by hand so the UnsavedChanges dialog can render a row for it. + wxGetApp().sidebar().get_searcher().add_key("printer_agent", m_type, optgroup->title, + optgroup->config_category()); + } + } + optgroup->append_single_option_line("use_3mf"); optgroup->append_single_option_line("scan_first_layer" , "printer_basic_information_advanced#scan-first-layer"); optgroup->append_single_option_line("enable_power_loss_recovery", "printer_basic_information_advanced#power-loss-recovery"); @@ -5573,6 +5593,7 @@ if (is_marlin_flavor) optgroup->append_single_option_line("purge_in_prime_tower", "printer_multimaterial_wipe_tower#purge-in-prime-tower"); optgroup->append_single_option_line("enable_filament_ramming", "printer_multimaterial_wipe_tower#enable-filament-ramming"); optgroup->append_single_option_line("tool_change_on_wipe_tower", "printer_multimaterial_wipe_tower#tool-change-on-wipe-tower"); + optgroup->append_single_option_line("wait_for_temp_on_wipe_tower", "printer_multimaterial_wipe_tower#wait-for-temperature-on-wipe-tower"); optgroup = page->new_optgroup(L("Single extruder multi-material parameters"), "param_settings"); @@ -5875,6 +5896,16 @@ void TabPrinter::reload_config() // so update it implicitly if (m_active_page && m_active_page->title() == "Multimaterial") m_active_page->set_value("extruders_count", int(m_extruders_count)); + + // m_opt_map-driven reload does not cover printer_agent, so sync this custom field explicitly. + if (Field* agent_field = get_field("printer_agent")) + { + if (auto* choice = dynamic_cast(agent_field); choice && choice->getWindow()) + { + const std::string selected_agent = m_config->opt_string("printer_agent"); + choice->set_value(selected_agent, false); + } + } } void TabPrinter::activate_selected_page(std::function throw_if_canceled) @@ -5885,6 +5916,16 @@ void TabPrinter::activate_selected_page(std::function throw_if_canceled) // so update it implicitly if (m_active_page && m_active_page->title() == "Multimaterial") m_active_page->set_value("extruders_count", int(m_extruders_count)); + + // m_opt_map-driven reload does not cover printer_agent, so sync this custom field explicitly. + if (Field* agent_field = get_field("printer_agent")) + { + if (auto* choice = dynamic_cast(agent_field); choice && choice->getWindow()) + { + const std::string selected_agent = m_config->opt_string("printer_agent"); + choice->set_value(selected_agent, false); + } + } } void TabPrinter::clear_pages() @@ -6086,6 +6127,7 @@ void TabPrinter::toggle_options() // so the option is irrelevant there. const size_t extruders_count = m_config->option("nozzle_diameter")->size(); toggle_option("tool_change_on_wipe_tower", !bSEMM && supports_wipe_tower_2 && extruders_count > 1); + toggle_option("wait_for_temp_on_wipe_tower", !bSEMM && supports_wipe_tower_2 && extruders_count > 1); } wxString extruder_number; long val = 1; @@ -7843,6 +7885,24 @@ bool TabPrinter::apply_extruder_cnt_from_cache() return false; } +void TabPrinter::refresh_printer_agent_dropdown() const +{ + auto* choice = dynamic_cast(get_field("printer_agent")); + if (!choice || !choice->getWindow()) + return; + + const auto agents = NetworkAgentFactory::get_registered_printer_agents(); + if (agents.empty()) + return; + + // why: rows live on PrinterAgentChoice now; rebuild them from the live registry and re-select the stored id. + const std::string selected_agent = wxGetApp().preset_bundle->printers.get_edited_preset() + .config.opt_string("printer_agent"); + choice->reload_rows(); + choice->set_value(selected_agent, false); + this->GetParent()->Layout(); +} + bool Tab::validate_custom_gcodes() { if (m_type != Preset::TYPE_FILAMENT && @@ -8934,11 +8994,15 @@ ConfigManipulation Tab::get_config_manipulation() return toggle_line(opt_key, toggle, opt_index >= 0 ? opt_index + 256 : opt_index); }; + auto cb_set_option_label = [this](const t_config_option_key &opt_key, const wxString &label, int opt_index) { + return set_option_label(opt_key, label, opt_index >= 0 ? opt_index + 256 : opt_index); + }; + auto cb_value_change = [this](const std::string& opt_key, const boost::any& value) { return on_value_change(opt_key, value); }; - return ConfigManipulation(load_config, cb_toggle_field, cb_toggle_line, cb_value_change, nullptr, this); + return ConfigManipulation(load_config, cb_toggle_field, cb_toggle_line, cb_value_change, nullptr, this, cb_set_option_label); } diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 9be9bc17f8..19eb0b849d 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -402,6 +402,7 @@ public: Field* get_field(const t_config_option_key &opt_key, Page** selected_page, int opt_index = -1); void toggle_option(const std::string &opt_key, bool toggle, int opt_index = -1); void toggle_line(const std::string &opt_key, bool toggle, int opt_index = -1); // BBS: hide some line + void set_option_label(const std::string &opt_key, const wxString &label, int opt_index = -1); wxSizer* description_line_widget(wxWindow* parent, ogStaticText** StaticText, wxString text = wxEmptyString); bool current_preset_is_dirty() const; bool saved_preset_is_dirty() const; @@ -674,6 +675,7 @@ public: wxSizer* create_bed_shape_widget(wxWindow* parent); void cache_extruder_cnt(const DynamicPrintConfig* config = nullptr); bool apply_extruder_cnt_from_cache(); + void refresh_printer_agent_dropdown() const; }; class TabSLAMaterial : public Tab diff --git a/src/slic3r/GUI/Widgets/CheckBox.cpp b/src/slic3r/GUI/Widgets/CheckBox.cpp index 54e98887e7..91cbb8c4e1 100644 --- a/src/slic3r/GUI/Widgets/CheckBox.cpp +++ b/src/slic3r/GUI/Widgets/CheckBox.cpp @@ -2,7 +2,7 @@ #include "../wxExtensions.hpp" -#ifdef __WXGTK3__ +#ifdef __WXGTK__ #include "../GUI_Utils.hpp" #endif @@ -29,7 +29,7 @@ CheckBox::CheckBox(wxWindow *parent, int id) Bind(wxEVT_LEAVE_WINDOW, &CheckBox::updateBitmap, this); #endif -#ifdef __WXGTK3__ +#ifdef __WXGTK__ Slic3r::GUI::RemoveButtonBorder(this); #endif diff --git a/src/slic3r/GUI/Widgets/RadioBox.cpp b/src/slic3r/GUI/Widgets/RadioBox.cpp index a8a1d8a1ef..7f20b8724c 100644 --- a/src/slic3r/GUI/Widgets/RadioBox.cpp +++ b/src/slic3r/GUI/Widgets/RadioBox.cpp @@ -2,6 +2,10 @@ #include "../wxExtensions.hpp" +#ifdef __WXGTK__ +#include "../GUI_Utils.hpp" +#endif + namespace Slic3r { namespace GUI { RadioBox::RadioBox(wxWindow *parent) @@ -15,6 +19,7 @@ RadioBox::RadioBox(wxWindow *parent) // Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { update(); e.Skip(); }); update(); #ifdef __WXGTK__ + Slic3r::GUI::RemoveButtonBorder(this); wxSize bestSize = GetBestSize(); bestSize.IncTo(m_on.GetBmpSize()); SetSize(bestSize); diff --git a/src/slic3r/GUI/Widgets/SpinInput.cpp b/src/slic3r/GUI/Widgets/SpinInput.cpp index ccd7a80447..fba5a45233 100644 --- a/src/slic3r/GUI/Widgets/SpinInput.cpp +++ b/src/slic3r/GUI/Widgets/SpinInput.cpp @@ -5,6 +5,10 @@ #include +#ifdef __WXGTK__ +#include "../GUI_Utils.hpp" +#endif + BEGIN_EVENT_TABLE(SpinInput, StaticBox) EVT_KEY_DOWN(SpinInput::keyPressed) @@ -58,6 +62,11 @@ void SpinInput::Create(wxWindow *parent, state_handler.attach({&label_color, &text_color}); state_handler.update_binds(); text_ctrl = new TextCtrl(this, wxID_ANY, text, {20, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER, wxTextValidator(wxFILTER_DIGITS)); + +#ifdef __WXGTK__ + Slic3r::GUI::RemoveInputBorder(text_ctrl); +#endif + text_ctrl->SetFont(Label::Body_14); text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states())); text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states())); diff --git a/src/slic3r/GUI/Widgets/SwitchButton.cpp b/src/slic3r/GUI/Widgets/SwitchButton.cpp index 9e780c0f02..c391ddd017 100644 --- a/src/slic3r/GUI/Widgets/SwitchButton.cpp +++ b/src/slic3r/GUI/Widgets/SwitchButton.cpp @@ -12,7 +12,7 @@ #include "libslic3r/MacUtils.hpp" #endif -#ifdef __WXGTK3__ +#ifdef __WXGTK__ #include "../GUI_Utils.hpp" #endif @@ -37,7 +37,7 @@ SwitchButton::SwitchButton(wxWindow* parent, wxWindowID id) Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { update(); e.Skip(); }); SetFont(Label::Body_12); -#ifdef __WXGTK3__ +#ifdef __WXGTK__ Slic3r::GUI::RemoveButtonBorder(this); #endif diff --git a/src/slic3r/GUI/Widgets/TextInput.cpp b/src/slic3r/GUI/Widgets/TextInput.cpp index 362e4c99b3..49605e048d 100644 --- a/src/slic3r/GUI/Widgets/TextInput.cpp +++ b/src/slic3r/GUI/Widgets/TextInput.cpp @@ -6,6 +6,10 @@ #include #include +#ifdef __WXGTK__ +#include "../GUI_Utils.hpp" +#endif + BEGIN_EVENT_TABLE(TextInput, StaticBox) EVT_PAINT(TextInput::paintEvent) @@ -60,6 +64,11 @@ void TextInput::Create(wxWindow * parent, state_handler.attach({&label_color, & text_color}); state_handler.update_binds(); text_ctrl = new TextCtrl(this, wxID_ANY, text, {4, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER); + +#ifdef __WXGTK__ + Slic3r::GUI::RemoveInputBorder(text_ctrl); +#endif + text_ctrl->SetFont(Label::Body_14); text_ctrl->SetInitialSize(text_ctrl->GetBestSize()); text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states())); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index e40046c37d..2ca8f3cfbd 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -1022,6 +1022,10 @@ ScalableButton::ScalableButton( wxWindow * parent, m_width = size.x * 10 / em; m_height= size.y * 10 / em; } + +#ifdef __WXGTK__ + Slic3r::GUI::RemoveButtonBorder(this); +#endif } diff --git a/src/slic3r/Utils/IPrinterAgent.hpp b/src/slic3r/Utils/IPrinterAgent.hpp index 91d271316e..0fa3616344 100644 --- a/src/slic3r/Utils/IPrinterAgent.hpp +++ b/src/slic3r/Utils/IPrinterAgent.hpp @@ -2,6 +2,13 @@ #define __I_PRINTER_AGENT_HPP__ #include "bambu_networking.hpp" +// why: these extend the BAMBU_NETWORK_* return space rather than opening a new one - the value +// flows through the same int domain callers already compare against BAMBU_NETWORK_SUCCESS. +// They live here and not in bambu_networking.hpp because that file is a vendor header replaced +// wholesale by header-sync commits (see c09252ce11), which would silently clobber them. +// -70xx is free: the vendor occupies -1..-25 and -10xx through -60xx. +#define ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED -7010 // no translation exists for this command +#define ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE -7020 // a translation exists; this printer lacks the capability #include #include diff --git a/src/slic3r/Utils/MoonrakerPrinterAgent.cpp b/src/slic3r/Utils/MoonrakerPrinterAgent.cpp index d21dce5070..cd3ef82b62 100644 --- a/src/slic3r/Utils/MoonrakerPrinterAgent.cpp +++ b/src/slic3r/Utils/MoonrakerPrinterAgent.cpp @@ -1359,7 +1359,6 @@ void MoonrakerPrinterAgent::announce_printhost_device() if (auto* app_config = GUI::wxGetApp().app_config) { const std::string access_code = device_info.api_key.empty() ? "88888888" : device_info.api_key; app_config->set_str("access_code", device_info.dev_id, access_code); - app_config->set_str("user_access_code", device_info.dev_id, access_code); } nlohmann::json payload; diff --git a/src/slic3r/Utils/NetworkAgentFactory.cpp b/src/slic3r/Utils/NetworkAgentFactory.cpp index 3883d99f2e..ff950d0946 100644 --- a/src/slic3r/Utils/NetworkAgentFactory.cpp +++ b/src/slic3r/Utils/NetworkAgentFactory.cpp @@ -465,25 +465,5 @@ void NetworkAgentFactory::deregister_python_printer_agent(const std::string& plu << plugin_key << "' with agent ID '" << agent_id << "'"; } -bool NetworkAgentFactory::is_current_printer_agent_plugin() -{ - auto* preset_bundle = GUI::wxGetApp().preset_bundle; - if (!preset_bundle) - return false; - - std::string agent_key = ORCA_PRINTER_AGENT_ID; - if (preset_bundle->is_bbl_vendor()) - agent_key = BBL_PRINTER_AGENT_ID; - - const auto& cfg = preset_bundle->printers.get_edited_preset().config; - if (cfg.has("printer_agent")) { - const std::string& value = cfg.option("printer_agent")->value; - if (!value.empty()) - agent_key = value; - } - - const PrinterAgentInfo* info = get_printer_agent_info(agent_key); - return info && info->is_plugin(); -} } // namespace Slic3r diff --git a/src/slic3r/Utils/NetworkAgentFactory.hpp b/src/slic3r/Utils/NetworkAgentFactory.hpp index cfff6fb1c7..a055b19493 100644 --- a/src/slic3r/Utils/NetworkAgentFactory.hpp +++ b/src/slic3r/Utils/NetworkAgentFactory.hpp @@ -166,8 +166,6 @@ public: static void register_python_printer_agent(const std::string& plugin_key, const std::string& capability_name); static void deregister_python_printer_agent(const std::string& plugin_key, const std::string& capability_name); - static bool is_current_printer_agent_plugin(); - private: // Factory is not instantiable NetworkAgentFactory() = delete; diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 9ec57fd653..18a9db4e26 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -1,12 +1,14 @@ #include "PresetUpdater.hpp" #include +#include #include +#include #include #include #include -#include #include +#include #include #include #include @@ -19,6 +21,7 @@ #include #include +#include #include #include @@ -204,7 +207,6 @@ struct PresetUpdater::priv // Per-vendor update checking std::set checked_vendors; - std::mutex vendor_check_mutex; std::vector vendor_check_threads; std::atomic vendor_check_cancel{false}; @@ -221,10 +223,10 @@ struct PresetUpdater::priv priv(); void set_download_prefs(AppConfig *app_config); - bool get_file(const std::string &url, const fs::path &target_path) const; - //BBS: refine preset update logic + bool get_file(const std::string &url, const fs::path &target_path) const; + //BBS: refine preset update logic bool extract_file(const fs::path &source_path, const fs::path &dest_path = {}); - void prune_tmps() const; + void prune_tmp(const std::string& vendor_id) const; void sync_version() const; void parse_version_string(const std::string& body) const; void sync_resources(std::string http_url, std::map &resources, bool check_patch = false, std::string current_version="", std::string changelog_file=""); @@ -371,14 +373,14 @@ bool PresetUpdater::priv::extract_file(const fs::path &source_path, const fs::pa return true; } -// Remove leftover paritally downloaded files, if any. -void PresetUpdater::priv::prune_tmps() const +// Remove a leftover partial archive for the vendor about to be synchronized. +void PresetUpdater::priv::prune_tmp(const std::string& vendor_id) const { - for (auto &dir_entry : boost::filesystem::directory_iterator(cache_path)) - if (is_plain_file(dir_entry) && dir_entry.path().extension() == TMP_EXTENSION) { - BOOST_LOG_TRIVIAL(debug) << "[Orca Updater]remove old cached files: " << dir_entry.path().string(); - fs::remove(dir_entry.path()); - } + boost::system::error_code ec; + const fs::path tmp_path = cache_path / (vendor_id + TMP_EXTENSION); + fs::remove(tmp_path, ec); + if (ec) + BOOST_LOG_TRIVIAL(warning) << "[Orca Updater]failed to remove " << tmp_path.string() << ": " << ec.message(); } //BBS: refine the Preset Updater logic @@ -1060,10 +1062,9 @@ void PresetUpdater::priv::check_installed_vendor_profiles() const Semver resource_ver = get_version_from_json(file_path); Semver vendor_ver = get_version_from_json(path_in_vendor.string()); - bool version_match = ((resource_ver.maj() == vendor_ver.maj()) && (resource_ver.min() == vendor_ver.min())); - - if (!version_match || (vendor_ver < resource_ver)) { - BOOST_LOG_TRIVIAL(info) << "[Orca Updater]:found vendor "<set_download_prefs(GUI::wxGetApp().app_config); if (!p->enabled_version_check && !p->enabled_config_update) { return; } - // Copy the whole vendors data for use in the background thread - // Unfortunatelly as of C++11, it needs to be copied again - // into the closure (but perhaps the compiler can elide this). - VendorMap vendors = preset_bundle ? preset_bundle->vendors : VendorMap{}; - - // Determine active vendor before entering the thread - std::string active_vendor; - if (preset_bundle) { - const Preset& printer = preset_bundle->printers.get_edited_preset(); - if (printer.vendor) - active_vendor = printer.vendor->id; - } - - p->thread = std::thread([this, vendors, active_vendor, http_url, language, plugin_version]() { - this->p->prune_tmps(); - if (p->cancel) - return; - this->p->sync_version(); - if (p->cancel) - return; - // Per-vendor config check for the active vendor at startup - if (!active_vendor.empty() && !vendors.empty()) { - this->p->sync_vendor_config(active_vendor); - if (p->cancel) - return; - { - std::lock_guard lock(this->p->vendor_check_mutex); - this->p->checked_vendors.insert(active_vendor); - } - } - if (p->cancel) - return; - this->p->sync_plugins(http_url, plugin_version); - this->p->sync_printer_config(http_url); - //if (p->cancel) - // return; - //remove the tooltip currently - //this->p->sync_tooltip(http_url, language); + p->thread = std::thread([this, http_url, language, plugin_version]() { + try { + this->p->sync_version(); + if (p->cancel) + return; + // Vendor profile updates are triggered by check_vendor_update() + // after the startup printer preset has been restored. + this->p->sync_plugins(http_url, plugin_version); + this->p->sync_printer_config(http_url); + //if (p->cancel) + // return; + //remove the tooltip currently + //this->p->sync_tooltip(http_url, language); + } catch (const std::exception &e) { + BOOST_LOG_TRIVIAL(error) << "[Orca Updater] background sync failed: " << e.what(); + } catch (...) { + BOOST_LOG_TRIVIAL(error) << "[Orca Updater] background sync failed with an unknown exception"; + } }); } @@ -1356,16 +1337,17 @@ void PresetUpdater::check_vendor_update(const std::string& vendor_id) if (!p->enabled_config_update) return; if (vendor_id.empty()) return; - std::lock_guard lock(p->vendor_check_mutex); - if (!p->checked_vendors.insert(vendor_id).second) return; p->vendor_check_threads.emplace_back([this, vendor_id]() { try { + this->p->prune_tmp(vendor_id); this->p->sync_vendor_config(vendor_id); } catch (const std::exception& e) { BOOST_LOG_TRIVIAL(error) << "[Orca Updater] vendor update failed for " << vendor_id << ": " << e.what(); + } catch (...) { + BOOST_LOG_TRIVIAL(error) << "[Orca Updater] vendor update failed for " << vendor_id << " with an unknown exception"; } }); } diff --git a/src/slic3r/Utils/RaycastManager.cpp b/src/slic3r/Utils/RaycastManager.cpp index c51a19ebd9..62c7a922d7 100644 --- a/src/slic3r/Utils/RaycastManager.cpp +++ b/src/slic3r/Utils/RaycastManager.cpp @@ -107,7 +107,7 @@ std::optional RaycastManager::first_hit(const Vec3d& point, const AABBMesh *hit_mesh = nullptr; double hit_squared_distance = 0.; int hit_face = -1; - Vec3d hit_world; + Vec3d hit_world { Vec3d::Zero() }; const Transform3d *hit_tramsformation = nullptr; const TrKey *hit_key = nullptr; diff --git a/src/slic3r/plugin/PluginDescriptor.hpp b/src/slic3r/plugin/PluginDescriptor.hpp index b7792e2e31..b0d2d214c3 100644 --- a/src/slic3r/plugin/PluginDescriptor.hpp +++ b/src/slic3r/plugin/PluginDescriptor.hpp @@ -20,6 +20,7 @@ struct CloudPluginState bool update_available = false; // Cloud version > the local package version. bool unauthorized = false; // Cloud plugin is valid locally, but cannot receive cloud updates. bool is_mine = false; // Plugin was created (and uploaded) by the current user. + bool orphaned = false; // Cloud identity remains locally, but the plugin is no longer subscribed/available. }; enum class PluginUpdateStatus @@ -106,6 +107,8 @@ struct PluginDescriptor { if (!cloud.has_value()) return PluginUpdateStatus::Normal; + if (cloud->orphaned) + return PluginUpdateStatus::Normal; if (cloud->unauthorized) return PluginUpdateStatus::Unauthorized; if (cloud->update_available) diff --git a/src/slic3r/plugin/PluginFsUtils.cpp b/src/slic3r/plugin/PluginFsUtils.cpp index 3e014eaec7..112c6ebf2b 100644 --- a/src/slic3r/plugin/PluginFsUtils.cpp +++ b/src/slic3r/plugin/PluginFsUtils.cpp @@ -120,8 +120,7 @@ bool delete_plugin_root(const boost::filesystem::path& resolved_root, const std: } if (removed_count == 0) { - error = "Plugin folder was not found: " + resolved_root.string(); - return false; + return true; } BOOST_LOG_TRIVIAL(info) << "Deleted plugin: " << plugin_id << " from " << resolved_root.string(); diff --git a/src/slic3r/plugin/PluginManager.cpp b/src/slic3r/plugin/PluginManager.cpp index 6ef0cc8d53..d84f629112 100644 --- a/src/slic3r/plugin/PluginManager.cpp +++ b/src/slic3r/plugin/PluginManager.cpp @@ -311,6 +311,7 @@ void PluginManager::merge_discovered_plugins(std::vector disco } seen.push_back(descriptor.plugin_key); + m_missing_plugin_keys.erase(descriptor.plugin_key); Plugin* existing = find_plugin_locked(descriptor.plugin_key); if (existing == nullptr) { @@ -331,12 +332,47 @@ void PluginManager::merge_discovered_plugins(std::vector disco return; } - // Unloading may call Python and lifecycle subscribers may re-enter the manager, so never do it - // while holding m_mutex. unload_and_erase_if() retries until no matching entry is loaded at the - // moment of erase, in case another caller starts a load between the initial snapshot and the - // teardown. - unload_and_erase_if( - [&seen](const Plugin& plugin) { return std::find(seen.begin(), seen.end(), plugin.descriptor.plugin_key) == seen.end(); }); + // A package can be temporarily absent while an external side-loader replaces it. Keep the + // descriptor and its persisted enable state until the user explicitly removes the missing + // entry, or a later scan rediscovers it. In particular, do not unload here: the unload callback + // would turn a transient filesystem gap into enabled=false in the sidecar. + { + std::lock_guard lock(m_mutex); + for (const Plugin& plugin : m_plugins) { + if (plugin.descriptor.has_local_package() && + std::find(seen.begin(), seen.end(), plugin.descriptor.plugin_key) == seen.end()) + m_missing_plugin_keys.insert(plugin.descriptor.plugin_key); + } + } +} + +std::vector PluginManager::get_missing_plugin_descriptors() const +{ + std::lock_guard lock(m_mutex); + + std::vector result; + result.reserve(m_missing_plugin_keys.size()); + for (const Plugin& plugin : m_plugins) + if (m_missing_plugin_keys.count(plugin.descriptor.plugin_key) != 0) + result.push_back(plugin.descriptor); + return result; +} + +void PluginManager::remove_missing_plugins(const std::vector& plugin_keys) +{ + const std::unordered_set requested(plugin_keys.begin(), plugin_keys.end()); + + // The predicate is evaluated only while m_mutex is held by unload_and_erase_if(). Checking the + // current missing set here prevents a package that reappeared between the dialog and removal + // from being erased. + unload_and_erase_if([this, &requested](const Plugin& plugin) { + return requested.count(plugin.descriptor.plugin_key) != 0 && + m_missing_plugin_keys.count(plugin.descriptor.plugin_key) != 0; + }); + + std::lock_guard lock(m_mutex); + for (const std::string& plugin_key : requested) + m_missing_plugin_keys.erase(plugin_key); } void PluginManager::unload_and_erase_if(const std::function& should_remove, @@ -1464,7 +1500,8 @@ void PluginManager::fetch_plugins_from_cloud(std::vector* out_not_f std::vector cloud_list{}; std::vector not_found{}, unauthorized{}; - if (!m_cloud_service.fetch_manifests_into_descriptors(cloud_list, not_found, unauthorized)) { + const bool cloud_fetch_succeeded = m_cloud_service.fetch_manifests_into_descriptors(cloud_list, not_found, unauthorized); + if (!cloud_fetch_succeeded) { if (wxTheApp != nullptr) { GUI::wxGetApp().CallAfter([] { if (GUI::wxGetApp().is_closing()) @@ -1479,9 +1516,10 @@ void PluginManager::fetch_plugins_from_cloud(std::vector* out_not_f } } - update_cloud_metadata(cloud_list); + if (cloud_fetch_succeeded) + update_cloud_metadata(cloud_list); - { + if (cloud_fetch_succeeded) { std::lock_guard lock(m_mutex); // Clear the previous cloud verdicts before re-applying the fresh ones. @@ -1490,19 +1528,28 @@ void PluginManager::fetch_plugins_from_cloud(std::vector* out_not_f if (!entry.is_cloud_plugin()) continue; entry.set_unauthorized(false); + if (entry.cloud.has_value()) + entry.cloud->orphaned = false; if (entry.normalized_error() == CLOUD_PLUGIN_NOT_FOUND_ERROR) entry.clear_error(); } - for (const std::string& uuid : not_found) { - for (Plugin& plugin : m_plugins) { - PluginDescriptor& entry = plugin.descriptor; - if (!entry.is_cloud_plugin() || entry.cloud_uuid() != uuid) - continue; - if (!entry.has_local_package()) - entry.set_error(CLOUD_PLUGIN_NOT_FOUND_ERROR); - break; - } + // A successful subscriptions response may report missing UUIDs explicitly, or it may + // simply omit an unsubscribed plugin from `data`. Both cases leave a locally retained + // cloud package orphaned. Owned plugins are returned by the separate mine endpoint and + // must not be orphaned merely because they are not subscribed. + for (Plugin& plugin : m_plugins) { + PluginDescriptor& entry = plugin.descriptor; + if (!entry.is_cloud_plugin() || entry.cloud->is_mine) + continue; + + const bool explicitly_not_found = std::find(not_found.begin(), not_found.end(), entry.cloud_uuid()) != not_found.end(); + const bool returned_by_cloud = std::any_of(cloud_list.begin(), cloud_list.end(), [&entry](const PluginDescriptor& cloud_entry) { + return cloud_entry.cloud_uuid() == entry.cloud_uuid(); + }); + entry.cloud->orphaned = explicitly_not_found || !returned_by_cloud; + if (entry.cloud->orphaned) + entry.cloud->update_available = false; } for (const std::string& uuid : unauthorized) { diff --git a/src/slic3r/plugin/PluginManager.hpp b/src/slic3r/plugin/PluginManager.hpp index ee7eab3106..26a02c09ec 100644 --- a/src/slic3r/plugin/PluginManager.hpp +++ b/src/slic3r/plugin/PluginManager.hpp @@ -132,6 +132,11 @@ public: bool try_get_plugin_descriptor(const std::string& plugin_key, PluginDescriptor& out) const; // Same, but only for packages that are loadable (i.e. not an invalid package). bool try_get_valid_plugin_descriptor(const std::string& plugin_key, PluginDescriptor& out) const; + // Packages that were present in the previous discovery pass but were not found on disk in the + // latest rescan. They are retained until the user explicitly removes them or a later scan finds + // them again. + std::vector get_missing_plugin_descriptors() const; + void remove_missing_plugins(const std::vector& plugin_keys); // Packages whose .install_state.json marks them for auto-load. std::vector get_enabled_plugin_keys() const; // The package owning a loaded capability, for the by-name dispatch path. @@ -265,6 +270,7 @@ private: // Every discovered plugin, loaded or not. module == nullptr => not loaded. std::vector m_plugins; + std::unordered_set m_missing_plugin_keys; std::unordered_set m_load_in_progress; // Keys whose in-flight load has been cancelled. Cancellation does NOT remove the key from diff --git a/src/slic3r/plugin/host/PluginHostApp.cpp b/src/slic3r/plugin/host/PluginHostApp.cpp index a17f160bb7..75acd4cc7b 100644 --- a/src/slic3r/plugin/host/PluginHostApp.cpp +++ b/src/slic3r/plugin/host/PluginHostApp.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -55,6 +56,15 @@ void host_bindings::register_app(py::module_& host) return current_plater()->model(); }, py::return_value_policy::reference); host.def("preset_bundle", ¤t_preset_bundle, py::return_value_policy::reference); + // UI language of the running app ("en_US", "ru_RU", ...), so plugins can + // localize their own dialogs. The app config file that stores this value + // is deny-listed by the audit hook (it sits next to cloud secrets), so a + // read-only accessor is the supported way to get just the language. + host.def("app_language", []() -> std::string { + if (wxTheApp == nullptr) + throw std::runtime_error("OrcaSlicer application is not initialized"); + return GUI::into_u8(GUI::wxGetApp().current_language_code_safe()); + }); } } // namespace Slic3r diff --git a/tests/data/wipe_tower_temperature_trace_main.txt b/tests/data/wipe_tower_temperature_trace_main.txt new file mode 100644 index 0000000000..f755008c26 --- /dev/null +++ b/tests/data/wipe_tower_temperature_trace_main.txt @@ -0,0 +1,172 @@ +# Temperature and tool-change commands of a wait_for_temp_on_wipe_tower-off slice, +# captured from the main branch at a10d9e77cf. Regeneration is described +# at the test that reads this file: "Toolchange temperature commands are unchanged +# when the wipe tower wait is off" in tests/fff_print/test_multifilament.cpp. +# +# The "time:" and "lead" values are toolchain-specific -- GCC, Clang and MSVC each produce +# slightly different estimates from an identical toolpath -- so they are compared with a +# tolerance, not exactly. Do not regenerate this file to resolve a mismatch in them: no single +# capture satisfies all three, and recapturing just moves the failure to other platforms. +M104 S215 T0 ; set nozzle temperature +M104 S215 T1 ; set nozzle temperature +; CP PRIMING START +T1 ; change extruder +M109 S215 T1 ; set nozzle temperature and wait for it to be reached +M104 S175 T1 ; set nozzle temperature ;cooldown +T0 ; change extruder +M109 S215 T0 ; set nozzle temperature and wait for it to be reached +; CP PRIMING END +M104 S215 T1 ; preheat T1 time: 30s lead 30.2s +; CP TOOLCHANGE START +M104 S175 T0 ; set nozzle temperature ;cooldown +T1 ; change extruder +M109 S215 T1 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T1 ; set nozzle temperature +M104 S240 T0 ; preheat T0 time: 30s lead 30.0s +; CP TOOLCHANGE START +M104 S200 T1 ; set nozzle temperature ;cooldown +T0 ; change extruder +M109 S240 T0 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T1 ; preheat T1 time: 30s lead 30.4s +; CP TOOLCHANGE START +M104 S200 T0 ; set nozzle temperature ;cooldown +T1 ; change extruder +M109 S240 T1 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T0 ; preheat T0 time: 31s lead 30.9s +; CP TOOLCHANGE START +M104 S200 T1 ; set nozzle temperature ;cooldown +T0 ; change extruder +M109 S240 T0 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T1 ; preheat T1 time: 30s lead 30.2s +; CP TOOLCHANGE START +M104 S200 T0 ; set nozzle temperature ;cooldown +T1 ; change extruder +M109 S240 T1 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T0 ; preheat T0 time: 30s lead 30.2s +; CP TOOLCHANGE START +M104 S200 T1 ; set nozzle temperature ;cooldown +T0 ; change extruder +M109 S240 T0 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T1 ; preheat T1 time: 30s lead 30.2s +; CP TOOLCHANGE START +M104 S200 T0 ; set nozzle temperature ;cooldown +T1 ; change extruder +M109 S240 T1 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T0 ; preheat T0 time: 30s lead 30.2s +; CP TOOLCHANGE START +M104 S200 T1 ; set nozzle temperature ;cooldown +T0 ; change extruder +M109 S240 T0 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T1 ; preheat T1 time: 30s lead 30.2s +; CP TOOLCHANGE START +M104 S200 T0 ; set nozzle temperature ;cooldown +T1 ; change extruder +M109 S240 T1 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T0 ; preheat T0 time: 30s lead 30.2s +; CP TOOLCHANGE START +M104 S200 T1 ; set nozzle temperature ;cooldown +T0 ; change extruder +M109 S240 T0 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T1 ; preheat T1 time: 31s lead 30.7s +; CP TOOLCHANGE START +M104 S200 T0 ; set nozzle temperature ;cooldown +T1 ; change extruder +M109 S240 T1 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T0 ; preheat T0 time: 31s lead 30.6s +; CP TOOLCHANGE START +M104 S200 T1 ; set nozzle temperature ;cooldown +T0 ; change extruder +M109 S240 T0 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T1 ; preheat T1 time: 30s lead 30.3s +; CP TOOLCHANGE START +M104 S200 T0 ; set nozzle temperature ;cooldown +T1 ; change extruder +M109 S240 T1 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T0 ; preheat T0 time: 31s lead 30.6s +; CP TOOLCHANGE START +M104 S200 T1 ; set nozzle temperature ;cooldown +T0 ; change extruder +M109 S240 T0 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T1 ; preheat T1 time: 30s lead 30.0s +; CP TOOLCHANGE START +M104 S200 T0 ; set nozzle temperature ;cooldown +T1 ; change extruder +M109 S240 T1 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T0 ; preheat T0 time: 30s lead 30.2s +; CP TOOLCHANGE START +M104 S200 T1 ; set nozzle temperature ;cooldown +T0 ; change extruder +M109 S240 T0 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T1 ; preheat T1 time: 30s lead 30.2s +; CP TOOLCHANGE START +M104 S200 T0 ; set nozzle temperature ;cooldown +T1 ; change extruder +M109 S240 T1 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T0 ; preheat T0 time: 30s lead 30.2s +; CP TOOLCHANGE START +M104 S200 T1 ; set nozzle temperature ;cooldown +T0 ; change extruder +M109 S240 T0 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T1 ; preheat T1 time: 30s lead 30.2s +; CP TOOLCHANGE START +M104 S200 T0 ; set nozzle temperature ;cooldown +T1 ; change extruder +M109 S240 T1 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T0 ; preheat T0 time: 30s lead 30.2s +; CP TOOLCHANGE START +M104 S200 T1 ; set nozzle temperature ;cooldown +T0 ; change extruder +M109 S240 T0 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T1 ; preheat T1 time: 31s lead 30.7s +; CP TOOLCHANGE START +M104 S200 T0 ; set nozzle temperature ;cooldown +T1 ; change extruder +M109 S240 T1 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T0 ; preheat T0 time: 30s lead 30.4s +; CP TOOLCHANGE START +M104 S200 T1 ; set nozzle temperature ;cooldown +T0 ; change extruder +M109 S240 T0 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T1 ; preheat T1 time: 30s lead 30.4s +; CP TOOLCHANGE START +M104 S200 T0 ; set nozzle temperature ;cooldown +T1 ; change extruder +M109 S240 T1 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T0 ; preheat T0 time: 30s lead 30.0s +; CP TOOLCHANGE START +M104 S200 T1 ; set nozzle temperature ;cooldown +T0 ; change extruder +M109 S240 T0 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +M104 S240 T1 ; preheat T1 time: 30s lead 30.0s +; CP TOOLCHANGE START +M104 S200 T0 ; set nozzle temperature ;cooldown +T1 ; change extruder +M109 S240 T1 ; set nozzle temperature and wait for it to be reached +; CP TOOLCHANGE END +; CP TOOLCHANGE START +; CP TOOLCHANGE END +M104 S0 ; turn off temperature diff --git a/tests/fff_print/CMakeLists.txt b/tests/fff_print/CMakeLists.txt index abddfebe5e..08f86de8a7 100644 --- a/tests/fff_print/CMakeLists.txt +++ b/tests/fff_print/CMakeLists.txt @@ -11,12 +11,14 @@ add_executable(${_TEST_NAME}_tests test_gcodewriter.cpp test_model.cpp test_multifilament.cpp + test_perimeters.cpp test_print.cpp test_printobject.cpp test_skirt_brim.cpp test_slicing_pipeline_hook.cpp test_support_material.cpp test_trianglemesh.cpp + test_wipe_tower.cpp ) target_link_libraries(${_TEST_NAME}_tests test_common libslic3r Catch2::Catch2WithMain) set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") diff --git a/tests/fff_print/test_multifilament.cpp b/tests/fff_print/test_multifilament.cpp index f33a8e1e61..484b7fb68a 100644 --- a/tests/fff_print/test_multifilament.cpp +++ b/tests/fff_print/test_multifilament.cpp @@ -1,12 +1,25 @@ #include +#include "libslic3r/GCode/GCodeProcessor.hpp" #include "libslic3r/GCodeReader.hpp" #include "test_helpers.hpp" +#include "test_utils.hpp" +#include #include +#include +#include +#include +#include +#include +#include #include +#include #include +#include +#include +#include using namespace Slic3r; using namespace Slic3r::Test; @@ -27,6 +40,210 @@ static std::set tools_for_role(const std::string& gcode, const std::string& return tools; } +// X where the nozzle sits while each tagged _WAIT_FOR_TEMP_ON_WIPE_TOWER M109 blocks: +// the nearest preceding G1 carrying an X (the park travel emitted just before the wait). +static std::vector wait_park_xs(const std::string& gcode) +{ + std::vector lines; + std::istringstream stream(gcode); + for (std::string line; std::getline(stream, line);) + lines.emplace_back(std::move(line)); + std::vector xs; + for (size_t i = 0; i < lines.size(); ++i) { + if (lines[i].rfind("M109", 0) != 0 || lines[i].find("_WAIT_FOR_TEMP_ON_WIPE_TOWER") == std::string::npos) + continue; + for (size_t j = i; j-- > 0;) { + if (lines[j].rfind("G1 ", 0) != 0) + continue; + const size_t x_pos = lines[j].find('X'); + if (x_pos == std::string::npos) + continue; + xs.push_back(std::stod(lines[j].substr(x_pos + 1))); + break; + } + } + return xs; +} + +// Estimated print time at each 1-based line of an exported G-code file, from a second +// GCodeProcessor pass over it. MoveVertex::time is the duration of one move and gcode_id is the +// line it came from (already rebased past the M73 insertions), so the running sum before the first +// move of a line is the elapsed time at that line. The file carries its own config footer, so +// process_file configures the processor -- including the shared s_IsBBLPrinter static that other +// tests in this binary mutate -- from the settings the export itself used. +static std::vector elapsed_time_by_line(const std::string& gcode) +{ + ScopedTemporaryFile temp_gcode(".gcode"); + { + std::ofstream os(temp_gcode.string()); + os << gcode; + } + GCodeProcessor processor; + processor.process_file(temp_gcode.string()); + + constexpr size_t NORMAL = size_t(PrintEstimatedStatistics::ETimeMode::Normal); + const size_t n_lines = size_t(std::count(gcode.begin(), gcode.end(), '\n')) + 2; + std::vector elapsed(n_lines, 0.); + double running = 0.; + size_t next = 0; + for (const auto& move : processor.get_result().moves) { + const size_t id = std::min(move.gcode_id, n_lines - 1); + while (next <= id) + elapsed[next++] = running; + running += move.time[NORMAL]; + } + while (next < n_lines) + elapsed[next++] = running; + return elapsed; +} + +// The temperature-relevant projection of `gcode`: every M104/M109/Tn line, plus the toolchange and +// priming markers that anchor them, in order. A preheat -- an M104 the GCodeProcessor backtrace +// inserts mid-object, outside any block, naming a tool other than the one currently loaded -- also +// carries "lead s", the estimated time from there to the tool change it heats for, which is the +// property preheat_time controls. No other temperature command gets one: for an M104 retargeting +// the active tool (the first-layer-to-other-layers bump) or one inside a block, the distance to the +// next Tn is a layer time or a handful of moves and says nothing about preheat_time. Everything +// else is dropped, so the trace does not move when travel, tower geometry or line numbering do. +static std::vector temperature_trace(const std::string& gcode) +{ + std::vector lines; + std::istringstream stream(gcode); + for (std::string line; std::getline(stream, line);) { + line.erase(0, line.find_first_not_of(" \t")); + while (!line.empty() && (line.back() == '\r' || line.back() == ' ' || line.back() == '\t')) + line.pop_back(); + lines.emplace_back(std::move(line)); + } + const std::vector elapsed = elapsed_time_by_line(gcode); + + const auto is_tool = [](const std::string& l) { return l.size() >= 2 && l[0] == 'T' && std::isdigit((unsigned char) l[1]); }; + const auto is_temp = [](const std::string& l) { return l.rfind("M104", 0) == 0 || l.rfind("M109", 0) == 0; }; + const auto marker = [](const std::string& l) -> const char* { + for (const char* m : { "; CP TOOLCHANGE START", "; CP TOOLCHANGE END", "; CP PRIMING START", "; CP PRIMING END" }) + if (l.find(m) != std::string::npos) + return m; + return nullptr; + }; + + // Tool a "T" line, or the "T" argument of an M104, names -- or -1 when it names none. + const auto tool_of = [&is_tool](const std::string& l) -> int { + size_t t = std::string::npos; // index of the 'T' + if (is_tool(l)) + t = 0; + else if (l.rfind("M104", 0) == 0 && l.find(" T") != std::string::npos) + t = l.find(" T") + 1; + if (t == std::string::npos || t + 1 >= l.size() || !std::isdigit((unsigned char) l[t + 1])) + return -1; + return std::stoi(l.substr(t + 1)); + }; + + std::vector trace; + bool in_block = false; + int current_tool = -1; + for (size_t i = 0; i < lines.size(); ++i) { + if (const char* m = marker(lines[i])) { + in_block = std::string(m).find("START") != std::string::npos; + trace.emplace_back(m); // the marker alone: some carry a trailing tool id, some do not + } else if (is_tool(lines[i]) || is_temp(lines[i])) { + std::string entry = lines[i]; + const int named = tool_of(lines[i]); + if (!in_block && lines[i].rfind("M104", 0) == 0 && current_tool != -1 && named != -1 && named != current_tool) { + size_t tn = i; + while (tn < lines.size() && !is_tool(lines[tn])) + ++tn; + if (tn < lines.size()) { + char lead[32]; + std::snprintf(lead, sizeof(lead), "\tlead %.1fs", elapsed[tn + 1] - elapsed[i + 1]); + entry += lead; + } + } + if (is_tool(lines[i])) + current_tool = named; + trace.emplace_back(std::move(entry)); + } + } + return trace; +} + +// "M104 S240 T0 ; preheat T0 time: 31slead 30.9s" carries the same quantity twice, and both +// vary by toolchain: the backtrace picks the first line at least preheat_time out, so a sub-tenth +// difference in the estimate selects a neighbouring move and "lead" steps by that move's duration. +// Tolerate "lead", still far below the tens of seconds a displaced preheat would shift it. Check +// "time:" against its own entry's "lead" instead of across runs -- being a rounding of it, that +// still catches a change in how it is derived without tracking the absolute estimate. +static constexpr double TRACE_TIME_TOLERANCE_S = 1.5; +static constexpr double TRACE_ROUNDING_SLACK_S = 0.05; // correct rounding keeps |time - lead| <= 0.5 + +struct TraceEntry +{ + std::string text; // timing values replaced by a placeholder + std::optional time_s; + std::optional lead_s; +}; + +static TraceEntry parse_trace_entry(const std::string& entry) +{ + TraceEntry out; + std::string text = entry; + + // Split off the tail only when it really is a "lead s", so an unexpected one still compares. + const size_t tab = text.find('\t'); + if (tab != std::string::npos) { + const std::string tail = text.substr(tab + 1); // "lead 30.2s" + const size_t sp = tail.find(' '); + if (sp != std::string::npos && sp + 1 < tail.size() + && std::isdigit(static_cast(tail[sp + 1]))) { + out.lead_s = std::stod(tail.substr(sp + 1)); + text.erase(tab); + } + } + + static constexpr std::string_view k_time = "time: "; + const size_t at = text.find(k_time); + // Require a digit first: a dots-only run would otherwise reach std::stod and throw. + if (at != std::string::npos && at + k_time.size() < text.size() + && std::isdigit(static_cast(text[at + k_time.size()]))) { + const size_t first = at + k_time.size(); + size_t last = first; + while (last < text.size() && (std::isdigit(static_cast(text[last])) || text[last] == '.')) + ++last; + out.time_s = std::stod(text.substr(first, last - first)); + text.replace(first, last - first, ""); // surrounding text, incl. the "s", still compared + } + + out.text = std::move(text); + return out; +} + +static bool timings_match(const std::optional& a, const std::optional& b) +{ + if (a.has_value() != b.has_value()) + return false; + return !a.has_value() || std::abs(*a - *b) <= TRACE_TIME_TOLERANCE_S; +} + +// "time:" must be its own entry's "lead" rounded to a whole second. +static bool time_is_rounded_lead(const TraceEntry& e) +{ + if (!e.time_s.has_value() || !e.lead_s.has_value()) + return true; // nothing to cross-check + return std::abs(*e.time_s - *e.lead_s) <= 0.5 + TRACE_ROUNDING_SLACK_S; +} + +// `a` is the slice under test, `b` the recorded golden. +static bool trace_entries_match(const std::string& a, const std::string& b) +{ + const auto x = parse_trace_entry(a); + const auto y = parse_trace_entry(b); + if (x.text != y.text) + return false; + // A field appearing or disappearing is a real change even though the values are tolerated. + if (x.time_s.has_value() != y.time_s.has_value()) + return false; + return timings_match(x.lead_s, y.lead_s) && time_is_rounded_lead(x); +} + // Tool index = filament id - 1; brim and skirt follow the wall filament. TEST_CASE("Each feature prints with its assigned filament", "[MultiFilament]") { @@ -86,6 +303,399 @@ TEST_CASE("Per-object wall filament override is honored", "[MultiFilament]") CHECK(tools_for_role(gcode, "infill") == std::set{ 0 }); // infill not overridden: stays on F1 } +// With wait_for_temp_on_wipe_tower the blocking M109 moves from right after the Tn command to +// a stop point parked beside the wipe tower (heat-up drool falls next to the tower, not onto +// its top): tagged with _WAIT_FOR_TEMP_ON_WIPE_TOWER, after the toolchange and before the +// repositioning move and the first extrusion of the purge. The restore that used to block there +// demotes to a non-blocking M104 and moves ahead of the Tn, so the incoming tool heats up over +// the change itself. Ordering and the off-tower stop are the contract here. +TEST_CASE("Toolchange temperature wait moves to the wipe tower when enabled", "[MultiFilament]") +{ + const bool wait_on_tower = GENERATE(false, true); + DYNAMIC_SECTION("wait_for_temp_on_wipe_tower " << (wait_on_tower ? 1 : 0)) { + const std::string gcode = slice_with_object_overrides( + { cube(20), cube(20) }, + multifilament_config(2, { + { "nozzle_diameter", "0.4,0.4" }, + { "printer_extruder_id", "1,2" }, + { "printer_extruder_variant", "Direct Drive Standard,Direct Drive Standard" }, + { "extruder_printable_height", "0,0" }, + { "single_extruder_multi_material", 0 }, + { "enable_prime_tower", 1 }, + { "prime_tower_width", 35 }, + { "wipe_tower_x", "50" }, + { "wipe_tower_y", "50" }, + { "ooze_prevention", 1 }, + { "standby_temperature_delta", -40 }, + // The post-processor's own preheat pass also inserts an M104 for the incoming + // filament ahead of the Tn; switch it off so the temperature commands under test + // are the only ones in the toolchange block. + { "preheat_time", 0 }, + { "wait_for_temp_on_wipe_tower", wait_on_tower ? 1 : 0 }, + }), + // One filament per object -> a toolchange on every layer. Assigned at the object + // level: the used-filament count that gates the prime tower is derived from + // object/volume configs on the harness's single apply (region filament ids such + // as sparse_infill_filament_id are not counted there and the tower would be + // silently disabled). + { { { "extruder", 1 } }, { { "extruder", 2 } } }); + + // Split into lines and scan the "; CP TOOLCHANGE START".."; CP TOOLCHANGE END" blocks. + std::vector lines; + std::istringstream gcode_stream(gcode); + for (std::string line; std::getline(gcode_stream, line);) + lines.emplace_back(std::move(line)); + const auto is_tool_line = [](const std::string& l) { return l.size() >= 2 && l[0] == 'T' && std::isdigit((unsigned char)l[1]); }; + const auto is_m109_line = [](const std::string& l) { return l.rfind("M109", 0) == 0; }; + // A non-blocking set-temperature naming one specific tool, e.g. "M104 S255 T1". + const auto is_m104_for_tool = [](const std::string& l, int tool) { + if (l.rfind("M104", 0) != 0) + return false; + const std::string token = " T" + std::to_string(tool); + const size_t at = l.find(token); + return at != std::string::npos && !std::isdigit((unsigned char)l[at + token.size()]); + }; + const auto is_tagged_wait = [](const std::string& l) { return l.find("_WAIT_FOR_TEMP_ON_WIPE_TOWER") != std::string::npos; }; + const auto is_extruding = [](const std::string& l) { + if (l.rfind("G1 ", 0) != 0) + return false; + const size_t e = l.find(" E"); + return e != std::string::npos && l.find_first_of("XY") != std::string::npos && l[e + 2] != '-'; + }; + + int checked_blocks = 0; + for (size_t i = 0; i < lines.size(); ++i) { + if (lines[i].find("; CP TOOLCHANGE START") == std::string::npos) + continue; + size_t block_end = i; + while (block_end < lines.size() && lines[block_end].find("; CP TOOLCHANGE END") == std::string::npos) + ++block_end; + size_t tool_line = block_end; + for (size_t j = i; j < block_end; ++j) + if (is_tool_line(lines[j])) { tool_line = j; break; } + if (tool_line == block_end) + continue; // final unload block, no toolchange + ++checked_blocks; + + // Where the incoming tool's target temperature is raised, relative to its Tn. + const int new_tool = std::stoi(lines[tool_line].substr(1)); + size_t preheat = tool_line, restore = block_end; + for (size_t j = i; j < tool_line; ++j) + if (is_m104_for_tool(lines[j], new_tool)) { preheat = j; break; } + for (size_t j = tool_line + 1; j < block_end; ++j) + if (is_m104_for_tool(lines[j], new_tool)) { restore = j; break; } + + size_t tagged_wait = block_end, untagged_m109 = block_end, first_extrusion = block_end; + for (size_t j = tool_line + 1; j < block_end; ++j) { + if (is_m109_line(lines[j]) && tagged_wait == block_end && is_tagged_wait(lines[j])) + tagged_wait = j; + if (is_m109_line(lines[j]) && untagged_m109 == block_end && !is_tagged_wait(lines[j])) + untagged_m109 = j; + if (first_extrusion == block_end && is_extruding(lines[j])) + first_extrusion = j; + } + INFO("toolchange block at line " << i + 1); + if (wait_on_tower) { + // The only blocking wait is the tagged one, parked beside the tower before the purge. + REQUIRE(tagged_wait < block_end); + CHECK(untagged_m109 == block_end); + // The target is raised ahead of the toolchange, so the incoming tool heats up + // while it is picked up, and nothing sets it again afterwards. + CHECK(preheat < tool_line); + CHECK(restore == block_end); + REQUIRE(first_extrusion < block_end); + CHECK(tagged_wait < first_extrusion); + // The travel preceding the wait parks outside the tower footprint. The tower + // auto-sizes, so derive its extent from the purge extrusions of this block. + size_t stop_line = block_end; + for (size_t j = tagged_wait; j-- > tool_line;) + if (lines[j].rfind("G1 ", 0) == 0 && lines[j].find('X') != std::string::npos) { stop_line = j; break; } + REQUIRE(stop_line < block_end); + const double stop_x = std::stod(lines[stop_line].substr(lines[stop_line].find('X') + 1)); + double purge_min_x = std::numeric_limits::max(), purge_max_x = std::numeric_limits::lowest(); + for (size_t j = tagged_wait; j < block_end; ++j) { + const size_t x_pos = lines[j].find('X'); + if (!is_extruding(lines[j]) || x_pos == std::string::npos) + continue; + const double x = std::stod(lines[j].substr(x_pos + 1)); + purge_min_x = std::min(purge_min_x, x); + purge_max_x = std::max(purge_max_x, x); + } + REQUIRE(purge_min_x <= purge_max_x); + INFO("stop travel: " << lines[stop_line] << " purge x range: " << purge_min_x << ".." << purge_max_x); + const bool beside_tower = stop_x < purge_min_x - 0.5 || stop_x > purge_max_x + 0.5; + CHECK(beside_tower); + } else { + // Stock behavior: the blocking wait follows the toolchange command directly, and + // nothing raises the incoming tool's target before it. + REQUIRE(untagged_m109 < block_end); + CHECK(tagged_wait == block_end); + CHECK(preheat == tool_line); + if (first_extrusion < block_end) + CHECK(untagged_m109 < first_extrusion); + } + i = block_end; + } + REQUIRE(checked_blocks > 0); + if (!wait_on_tower) + CHECK(gcode.find("_WAIT_FOR_TEMP_ON_WIPE_TOWER") == std::string::npos); + } +} + +// Priming runs before the first layer is set up, so set_extruder sees no layer at all: its +// on_first_layer() test is false and print_z is the initial layer height rather than 0. The +// tower nonetheless blocks on the first layer temperature there, so the pre-heat raised ahead +// of each priming Tn has to name that same temperature — pre-heating to the "other layers" +// value instead leaves the tagged M109 asking the firmware to cool back down before the +// priming lines are extruded. +TEST_CASE("Wipe tower priming pre-heats to the first layer temperature", "[MultiFilament]") +{ + const std::string gcode = slice_with_object_overrides( + { cube(20), cube(20) }, + multifilament_config(2, { + { "nozzle_diameter", "0.4,0.4" }, + { "printer_extruder_id", "1,2" }, + { "printer_extruder_variant", "Direct Drive Standard,Direct Drive Standard" }, + { "extruder_printable_height", "0,0" }, + { "single_extruder_multi_material", 0 }, + { "single_extruder_multi_material_priming", 1 }, + { "enable_prime_tower", 1 }, + { "prime_tower_width", 35 }, + { "wipe_tower_x", "50" }, + { "wipe_tower_y", "50" }, + { "preheat_time", 0 }, // see the wait test above + // Distinct enough that picking the wrong one is unambiguous. + { "nozzle_temperature_initial_layer", "215,215" }, + { "nozzle_temperature", "240,240" }, + { "wait_for_temp_on_wipe_tower", 1 }, + }), + { { { "extruder", 1 } }, { { "extruder", 2 } } }); + + std::vector lines; + std::istringstream gcode_stream(gcode); + for (std::string line; std::getline(gcode_stream, line);) + lines.emplace_back(std::move(line)); + // Temperature of an M104/M109, or -1 when the line is neither. + const auto temp_of = [](const std::string& l) { + if (l.rfind("M104", 0) != 0 && l.rfind("M109", 0) != 0) + return -1; + const size_t s = l.find('S'); + return s == std::string::npos ? -1 : std::stoi(l.substr(s + 1)); + }; + + size_t start = lines.size(), end = lines.size(); + for (size_t i = 0; i < lines.size(); ++i) { + if (start == lines.size() && lines[i].find("; CP PRIMING START") != std::string::npos) + start = i; + else if (start < lines.size() && lines[i].find("; CP PRIMING END") != std::string::npos) { + end = i; + break; + } + } + REQUIRE(start < end); + + int checked_waits = 0; + for (size_t i = start; i < end; ++i) { + if (lines[i].find("_WAIT_FOR_TEMP_ON_WIPE_TOWER") == std::string::npos) + continue; + ++checked_waits; + INFO("priming wait at line " << i + 1 << ": " << lines[i]); + CHECK(temp_of(lines[i]) == 215); // the tower waits on the first layer temperature + // The most recent set-temperature before it is the pre-heat, and must agree with it. + int preheat = -1; + for (size_t j = i; j-- > start;) + if ((preheat = temp_of(lines[j])) != -1) + break; + CHECK(preheat == 215); + } + REQUIRE(checked_waits > 0); // the feature under test is active +} + +// The temperature-wait park picks its side of the tower by testing bed containment with the +// tower position at psWipeTower generation time, while WipeTowerIntegration shifts the cached +// moves by the CURRENT position at export. Moving the tower normally invalidates only +// psSkirtBrim (tower gcode is position-independent), but the park makes it bed-relative, so a +// GUI-style move-and-reslice on the same Print must regenerate the tower — otherwise the stale +// park prints outside the bed. Contract: every tagged wait parks inside the printable area. +TEST_CASE("Wipe tower temperature-wait park is regenerated when the tower moves", "[MultiFilament]") +{ + // Two objects, one filament each: a toolchange (and a tagged wait) on every layer, like + // the wait test above — but on a single-extruder machine profile: the synthetic + // dual-extruder keys would drag in the extruder-variant expansion, which is not + // idempotent on the default machine profile and would pollute the re-apply diff below. + // Rectangle wall and no brim keep the tower-local footprint inside [0, 35], so the park + // sits at the generator's 2mm side gap: local -2 or 37. + DynamicPrintConfig config = multifilament_config(2, { + { "single_extruder_multi_material", 0 }, + { "enable_prime_tower", 1 }, + { "prime_tower_width", 35 }, + { "wipe_tower_wall_type", "rectangle" }, // the default rib bulges past the width + { "prime_tower_brim_width", 0 }, // the default 3 widens the first-layer envelope + { "printable_area", "0x0,200x0,200x200,0x200" }, + { "wipe_tower_x", "0" }, + { "wipe_tower_y", "50" }, + { "ooze_prevention", 1 }, + { "standby_temperature_delta", -40 }, + { "wait_for_temp_on_wipe_tower", 1 }, + }); + // init_print force-sets this on its own copy; set it here too so the re-apply below + // diffs in wipe_tower_x ONLY — the exact GUI increment under test. + config.set_key_value("gcode_comments", new ConfigOptionBool(true)); + + Print print; + Model model; + const std::vector> overrides{ + { { "extruder", 1 } }, { { "extruder", 2 } } }; // object-level, see the wait test above + init_print(std::vector{ cube(20), cube(20) }, print, model, config, &overrides); + + const std::string at_edge = gcode(print); + const std::vector at_edge_parks = wait_park_xs(at_edge); + REQUIRE(!at_edge_parks.empty()); // the feature under test is active + for (double x : at_edge_parks) { + INFO("wait park X " << x << " with the tower at x=0 on a 200mm bed"); + CHECK(x >= -0.05); + CHECK(x <= 200.05); + } + REQUIRE(print.is_step_done(psWipeTower)); + + // Move the tower to the right bed edge (164 + 35 = 199 keeps the body printable) and + // re-apply on the SAME Print, as the GUI does. Base the re-apply on the print's own + // resolved config so the diff is wipe_tower_x alone — re-applying the caller's config + // would also diff the apply-time extruder normalization write-backs, and those keys + // regenerate the tower for the wrong reason. The cached right-side park would export + // at 164 + 37 = 201, off the bed; regeneration clamps the park against the bed edge. + // Assemble the moved config exactly the way init_print assembled the first one — the + // apply-time normalization is only idempotent when both applies start from the same + // derivation, and any stray diff key would regenerate the tower for the wrong reason. + config.set_deserialize_strict({ { "wipe_tower_x", "164" } }); + DynamicPrintConfig moved_config = DynamicPrintConfig::full_print_config(); + moved_config.apply(config); + moved_config.set_key_value("gcode_comments", new ConfigOptionBool(true)); + print.apply(model, moved_config); + CHECK_FALSE(print.is_step_done(psWipeTower)); // the move must re-generate the tower + + const std::string moved = gcode(print); + const std::vector moved_parks = wait_park_xs(moved); + REQUIRE(!moved_parks.empty()); // the waits must survive the re-slice + for (double x : moved_parks) { + INFO("wait park X " << x << " with the tower at x=164 on a 200mm bed"); + CHECK(x >= -0.05); + CHECK(x <= 200.05); + } +} + +// The flag-off half of the three tests above. Every site wait_for_temp_on_wipe_tower touches is +// guarded -- set_extruder's pre-toolchange preheat block and its post_toolchange skip, +// toolchange_Change's park, the interface-temp guard in WipeTower2::tool_change, and append_tcr2's +// tagged-M109 filter -- so with the option off the feature has to be inert and temperature emission +// has to stay exactly as it was before the option existed. That is pinned against a trace captured +// from main rather than against expectations written from the current code, which would be +// re-derived from the very code they are meant to guard. +// +// Note what main emits here, since it is easy to misread as a missing wait: with preheat_time set, +// the toolchange carries no blocking M109 at all. GCodeProcessor's backtrace moves the heat-up to +// an M104 preheat_time seconds earlier and demotes the in-place command, which is the entire point +// of preheating. The lead times below are what pin that placement. +TEST_CASE("Toolchange temperature commands are unchanged when the wipe tower wait is off", "[MultiFilament][Regression]") +{ + // 20x20x5 cubes at the default 0.2mm layer height are 25 layers, one filament each, so there is + // a toolchange -- and a preheat ahead of it -- on every layer. + const std::string gcode = slice_with_object_overrides( + { make_cube(20., 20., 5.), make_cube(20., 20., 5.) }, + multifilament_config(2, { + { "nozzle_diameter", "0.4,0.4" }, + { "printer_extruder_id", "1,2" }, + { "printer_extruder_variant", "Direct Drive Standard,Direct Drive Standard" }, + { "extruder_printable_height", "0,0" }, + { "single_extruder_multi_material", 0 }, + { "single_extruder_multi_material_priming", 1 }, // reaches toolchange_Change's priming path + { "enable_prime_tower", 1 }, + { "prime_tower_width", 35 }, + { "wipe_tower_x", "50" }, + { "wipe_tower_y", "50" }, + // GCodeProcessor::apply_config enables the preheat backtrace on + // ooze_prevention && preheat_time > 0 && !SEMM && filaments > 1. That is what puts an + // M104 preheat_time seconds ahead of every Tn, and it also gives set_extruder's + // standby/restore pair, which the option demotes and moves when it is on. + { "ooze_prevention", 1 }, + { "standby_temperature_delta", -40 }, + { "preheat_time", 30 }, + { "preheat_steps", 1 }, + // enable_tower_interface_features is deliberately left off: the interface temperature + // is observable only through a change_filament_gcode template that reads + // new_filament_temp, since append_tcr2 strips the tower's own M109 for it, and the + // default template here has none. The option's interface-temp guard is covered by the + // enabled-path tests above instead. + // + // Distinct enough that a wrong pick between the two is unambiguous in the trace. + { "nozzle_temperature_initial_layer", "215,215" }, + { "nozzle_temperature", "240,240" }, + { "wait_for_temp_on_wipe_tower", 0 }, + }), + // Object-level, so the used-filament count that gates the prime tower is derived from it. + { { { "extruder", 1 } }, { { "extruder", 2 } } }); + + const std::vector trace = temperature_trace(gcode); + REQUIRE(trace.size() > 1); + CHECK(gcode.find("_WAIT_FOR_TEMP_ON_WIPE_TOWER") == std::string::npos); + + const std::string golden_path = std::string(TEST_DATA_DIR PATH_SEPARATOR "wipe_tower_temperature_trace_main.txt"); + + // Regenerate by appending this test and its helpers to the same file on main (dropping the + // wait_for_temp_on_wipe_tower key, which main's config does not know), rebuilding + // fff_print_tests there, running it with ORCA_UPDATE_WIPE_TOWER_TEMP_TRACE=1, copying the file + // it writes back here, and filling in the commit it was captured from. + if (std::getenv("ORCA_UPDATE_WIPE_TOWER_TEMP_TRACE") != nullptr) { + std::ofstream out(golden_path); + REQUIRE(out.good()); + out << "# Temperature and tool-change commands of a wait_for_temp_on_wipe_tower-off slice,\n" + "# captured from the main branch at . Regeneration is described\n" + "# at the test that reads this file: \"Toolchange temperature commands are unchanged\n" + "# when the wipe tower wait is off\" in tests/fff_print/test_multifilament.cpp.\n"; + for (const std::string& entry : trace) + out << entry << "\n"; + WARN("Rewrote " << golden_path << " from this run; it no longer reflects main."); + return; + } + + std::vector golden; + { + std::ifstream in(golden_path); + INFO("reading " << golden_path); + REQUIRE(in.good()); + for (std::string line; std::getline(in, line);) { + if (!line.empty() && line.back() == '\r') + line.pop_back(); + if (!line.empty() && line[0] != '#') + golden.push_back(std::move(line)); + } + } + REQUIRE(!golden.empty()); + + // Reported separately from the golden comparison below: it is a different failure. + for (size_t i = 0; i < trace.size(); ++i) { + const auto entry = parse_trace_entry(trace[i]); + if (time_is_rounded_lead(entry)) + continue; + INFO("at trace entry " << i + 1); + INFO(" " << trace[i]); + FAIL("\"time:\" is not its entry's \"lead\" rounded to a whole second"); + } + + const size_t common = std::min(trace.size(), golden.size()); + for (size_t i = 0; i < common; ++i) { + if (trace_entries_match(trace[i], golden[i])) + continue; + // Report the first difference only: past it the two are misaligned and every later entry + // would be reported as a difference too. + INFO("first difference at trace entry " << i + 1); + INFO(" main: " << golden[i]); + INFO(" branch: " << trace[i]); + FAIL("temperature emission differs from main with wait_for_temp_on_wipe_tower off"); + } + CHECK(trace.size() == golden.size()); +} + // max_layer_height can be shorter than the extruder count (normalization sizes it to the // filament count under single_extruder_multi_material). calc_max_layer_height() in ToolOrdering // indexed it per-nozzle and read past the end. Shortened directly here to isolate that read; @@ -104,3 +714,4 @@ TEST_CASE("Multi-extruder slice stays in bounds with a short max_layer_height", init_and_process_print({ cube(20) }, print, config); REQUIRE_FALSE(print.objects().front()->layers().empty()); } + diff --git a/tests/fff_print/test_perimeters.cpp b/tests/fff_print/test_perimeters.cpp new file mode 100644 index 0000000000..a98877ad2f --- /dev/null +++ b/tests/fff_print/test_perimeters.cpp @@ -0,0 +1,257 @@ +#include + +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/ExtrusionEntityCollection.hpp" +#include "libslic3r/Layer.hpp" +#include "libslic3r/Print.hpp" + +#include +#include +#include + +#include "test_helpers.hpp" + +using namespace Slic3r; +using namespace Slic3r::Test; + +namespace { + +// The layer at this Z is the last one of the base, so its top surface is the ledge. +const double ledge_z = 5.0; + +// The first layer, at initial_layer_print_height. +const double first_layer_z = 0.2; + +// TestMesh::step scaled 3x in X/Y: a 60x60x5 base carrying a 54x54 column up to z=10, leaving a 3mm +// top ledge around a feature that keeps rising. That is the geometry both only_one_wall_top and the +// top surface expansion act on. The ledge has to stay wider than the wall band plus two top-infill +// lines, or the expansion discards it as a sliver and the tests below assert nothing. +TriangleMesh step_with_ledge() +{ + TriangleMesh m = Slic3r::Test::mesh(TestMesh::step); + m.scale(Vec3f(3.f, 3.f, 1.f)); + return m; +} + +// Every setting the assertions depend on, so none of them rests on a default. +DynamicPrintConfig base_config(const char *wall_generator) +{ + DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "wall_generator", wall_generator }, + { "layer_height", 0.2 }, // puts a layer boundary exactly on ledge_z + { "initial_layer_print_height", 0.2 }, + { "wall_loops", 3 }, + { "sparse_infill_density", "15%" }, + { "top_shell_layers", 3 }, + { "bottom_shell_layers", 3 }, + { "top_surface_density", "100%" }, + { "top_surface_expansion", 0.0 }, + { "only_one_wall_top", false }, + { "only_one_wall_first_layer", false }, + // Do not let the one-wall threshold discard the 3mm ledge before the feature sees it. + { "min_width_top_surface", 0.0 }, + }); + return config; +} + +double collection_length(const ExtrusionEntityCollection &coll) +{ + double len = 0.; + for (const ExtrusionEntity *entity : coll.flatten().entities) + if (! entity->is_collection()) + len += entity->length(); + return len; +} + +// Extruded length per layer. Two slices are compared through this rather than through their G-code, +// because the G-code carries a config block that differs whenever any setting differs. +struct SliceLengths { + std::vector perimeters; + std::vector fills; +}; + +SliceLengths slice_lengths(const Print &print) +{ + SliceLengths out; + for (const Layer *layer : print.objects().front()->layers()) { + double perimeters = 0., fills = 0.; + for (const LayerRegion *region : layer->regions()) { + perimeters += collection_length(region->perimeters); + fills += collection_length(region->fills); + } + out.perimeters.push_back(perimeters); + out.fills.push_back(fills); + } + return out; +} + +double perimeter_length_at(const Print &print, double print_z) +{ + for (const Layer *layer : print.objects().front()->layers()) + if (std::abs(layer->print_z - print_z) < 1e-4) { + double len = 0.; + for (const LayerRegion *region : layer->regions()) + len += collection_length(region->perimeters); + return len; + } + return 0.; +} + +// Largest per-layer difference between two series; a negative result means they are not comparable. +double max_difference(const std::vector &a, const std::vector &b) +{ + if (a.size() != b.size() || a.empty()) + return -1.; + double worst = 0.; + for (size_t i = 0; i < a.size(); ++ i) + worst = std::max(worst, std::abs(a[i] - b[i])); + return worst; +} + +} // namespace + +// The expansion only retypes area as top solid infill, so it can do nothing where there is no top +// fill to begin with: zero top shell layers retypes the top surfaces as internal, and a top surface +// density of 0% leaves the top layer with walls only. The last section is the control - the same +// expansion on the same model does change the slice once a top fill exists - without which the two +// equality checks above it would hold for an unrelated reason. +TEST_CASE("Top surface expansion only acts where there is a top fill", "[Perimeters]") +{ + const char *wall_generator = GENERATE("classic", "arachne"); + CAPTURE(wall_generator); + + auto lengths_for = [wall_generator](int top_shell_layers, const char *top_surface_density, double expansion) { + DynamicPrintConfig config = base_config(wall_generator); + config.set_deserialize_strict({ + { "top_shell_layers", top_shell_layers }, + { "top_surface_density", top_surface_density }, + { "top_surface_expansion", expansion }, + }); + Print print; + init_and_process_print({ step_with_ledge() }, print, config); + REQUIRE_FALSE(print.objects().empty()); + return slice_lengths(print); + }; + + SECTION("no top shell layers") { + const SliceLengths off = lengths_for(0, "100%", 0.0); + const SliceLengths on = lengths_for(0, "100%", 2.0); + REQUIRE(off.perimeters.size() == on.perimeters.size()); + CHECK_THAT(max_difference(off.perimeters, on.perimeters), Catch::Matchers::WithinAbs(0., 1.0)); + CHECK_THAT(max_difference(off.fills, on.fills), Catch::Matchers::WithinAbs(0., 1.0)); + } + + SECTION("zero top surface density") { + const SliceLengths off = lengths_for(3, "0%", 0.0); + const SliceLengths on = lengths_for(3, "0%", 2.0); + REQUIRE(off.perimeters.size() == on.perimeters.size()); + CHECK_THAT(max_difference(off.perimeters, on.perimeters), Catch::Matchers::WithinAbs(0., 1.0)); + CHECK_THAT(max_difference(off.fills, on.fills), Catch::Matchers::WithinAbs(0., 1.0)); + } + + SECTION("with a top fill the same expansion does change the slice") { + const SliceLengths off = lengths_for(3, "100%", 0.0); + const SliceLengths on = lengths_for(3, "100%", 2.0); + REQUIRE(off.fills.size() == on.fills.size()); + CHECK(max_difference(off.fills, on.fills) > scale_(0.5)); + } +} + +// With no top shell the top surfaces are retyped as internal, so the top surface density has nothing +// left to control: there is no top fill, and only_one_wall_top - the one route from the density to the +// perimeters - is itself switched off for want of a top surface to act on. +TEST_CASE("Top surface density does not affect a slice without a top shell", "[Perimeters]") +{ + const char *wall_generator = GENERATE("classic", "arachne"); + CAPTURE(wall_generator); + + auto lengths_for = [wall_generator](const char *top_surface_density) { + DynamicPrintConfig config = base_config(wall_generator); + config.set_deserialize_strict({ + { "top_shell_layers", 0 }, + { "only_one_wall_top", true }, + { "top_surface_density", top_surface_density }, + }); + Print print; + init_and_process_print({ step_with_ledge() }, print, config); + REQUIRE_FALSE(print.objects().empty()); + return slice_lengths(print); + }; + + const SliceLengths solid = lengths_for("100%"); + const SliceLengths none = lengths_for("0%"); + REQUIRE(solid.perimeters.size() == none.perimeters.size()); + CHECK_THAT(max_difference(solid.perimeters, none.perimeters), Catch::Matchers::WithinAbs(0., 1.0)); + CHECK_THAT(max_difference(solid.fills, none.fills), Catch::Matchers::WithinAbs(0., 1.0)); +} + +// On the ledge layer the inner walls are given up to the top fill, so that layer loses wall length. +// The handover needs a top fill that reaches the freed space: at a top surface density of 0% there is +// no top fill at all, and without top_surface_expansion the fill never grows over the walls. Either +// way the feature still runs, through the original generation, which keeps the inner walls up to the +// top boundary - putting that layer back between the plain and the one-wall slice. +TEST_CASE("Only one wall on top surfaces drops inner walls only where a top fill replaces them", "[Perimeters]") +{ + const char *wall_generator = GENERATE("classic", "arachne"); + CAPTURE(wall_generator); + + auto ledge_perimeters_for = [wall_generator](bool only_one_wall_top, const char *top_surface_density, double expansion) { + DynamicPrintConfig config = base_config(wall_generator); + config.set_deserialize_strict({ + { "only_one_wall_top", only_one_wall_top }, + { "top_surface_density", top_surface_density }, + { "top_surface_expansion", expansion }, + }); + Print print; + init_and_process_print({ step_with_ledge() }, print, config); + REQUIRE_FALSE(print.objects().empty()); + return perimeter_length_at(print, ledge_z); + }; + + const double plain = ledge_perimeters_for(false, "100%", 2.0); + const double one_wall = ledge_perimeters_for(true, "100%", 2.0); + const double one_wall_no_fill = ledge_perimeters_for(true, "0%", 2.0); + const double one_wall_no_expand = ledge_perimeters_for(true, "100%", 0.0); + + REQUIRE(plain > 0.); + CHECK(one_wall < plain); + // Both fall back to the original generation, which cuts the walls back to the top boundary but not past it. + CHECK(one_wall_no_fill > one_wall); + CHECK(one_wall_no_fill < plain); + CHECK(one_wall_no_expand > one_wall); + CHECK(one_wall_no_expand < plain); +} + +// The bottom counterpart: the first layer is thinned to a single wall only where a bottom shell fills the +// space behind it. With no bottom shell layers the bottom surfaces are retyped as internal, so that wall +// would ring sparse infill on the bed - the option is switched off instead, and the GUI hides it in that +// state so a profile that left it enabled cannot act behind a hidden checkbox. +TEST_CASE("Only one wall on the first layer needs a bottom shell", "[Perimeters]") +{ + const char *wall_generator = GENERATE("classic", "arachne"); + CAPTURE(wall_generator); + + auto first_layer_perimeters_for = [wall_generator](bool only_one_wall_first_layer, int bottom_shell_layers) { + DynamicPrintConfig config = base_config(wall_generator); + config.set_deserialize_strict({ + { "only_one_wall_first_layer", only_one_wall_first_layer }, + { "bottom_shell_layers", bottom_shell_layers }, + }); + Print print; + init_and_process_print({ step_with_ledge() }, print, config); + REQUIRE_FALSE(print.objects().empty()); + return perimeter_length_at(print, first_layer_z); + }; + + const double plain = first_layer_perimeters_for(false, 3); + const double one_wall = first_layer_perimeters_for(true, 3); + // Both at zero bottom shell layers, so everything else that setting changes cancels out between them. + const double plain_no_shell = first_layer_perimeters_for(false, 0); + const double one_wall_no_shell = first_layer_perimeters_for(true, 0); + + REQUIRE(plain > 0.); + CHECK(one_wall < plain); + // No bottom shell: the option is inert, down to the same walls an unchecked box gives. + CHECK_THAT(one_wall_no_shell, Catch::Matchers::WithinAbs(plain_no_shell, 1.0)); +} diff --git a/tests/fff_print/test_print.cpp b/tests/fff_print/test_print.cpp index 9cb085f78b..6bff945fc3 100644 --- a/tests/fff_print/test_print.cpp +++ b/tests/fff_print/test_print.cpp @@ -338,6 +338,22 @@ TEST_CASE("G-code lists the resolved extrusion-width settings", "[Print]") CHECK(with_first_layer.find("; first layer extrusion width") != std::string::npos); } +// gcode_skip_config_block suppresses the resolved-settings block while leaving the +// header and executable blocks intact. +TEST_CASE("gcode_skip_config_block omits the resolved-settings comment block", "[Print]") +{ + const std::string gcode = slice({ cube(20) }, { + { "gcode_skip_config_block", true }, + { "gcode_comments", true }, + }); + CHECK(gcode.find("; CONFIG_BLOCK_START") == std::string::npos); + CHECK(gcode.find("; CONFIG_BLOCK_END") == std::string::npos); + CHECK(gcode.find("; layer_height =") == std::string::npos); + CHECK(gcode.find("; fill_density =") == std::string::npos); + CHECK(gcode.find("; HEADER_BLOCK_START") != std::string::npos); + CHECK(gcode.find("; EXECUTABLE_BLOCK_START") != std::string::npos); +} + // Custom G-code templates substitute placeholders during export. TEST_CASE("Custom G-code placeholders are substituted", "[Print]") { diff --git a/tests/fff_print/test_skirt_brim.cpp b/tests/fff_print/test_skirt_brim.cpp index d957a4c649..17a79a7828 100644 --- a/tests/fff_print/test_skirt_brim.cpp +++ b/tests/fff_print/test_skirt_brim.cpp @@ -4,6 +4,7 @@ #include "libslic3r/Config.hpp" #include "libslic3r/Geometry.hpp" #include "libslic3r/Geometry/ConvexHull.hpp" +#include "libslic3r/Layer.hpp" #include @@ -32,6 +33,30 @@ static size_t brim_loop_count(Print &print) return n; } +static bool brim_enters_first_layer_hole(Print &print) +{ + const PrintObject *object = print.get_object(0); + Polygons holes; + for (const ExPolygon &slice : object->layers().front()->lslices) + holes.insert(holes.end(), slice.holes.begin(), slice.holes.end()); + + const Vec3d plate_origin = print.get_plate_origin(); + Point shift = object->instances().front().shift_without_plate_offset(); + shift += Point(scaled(plate_origin.x()), scaled(plate_origin.y())); + for (Polygon &hole : holes) + hole.translate(shift); + + for (const auto &kv : print.get_brimMap()) { + Polylines brim_paths; + kv.second.collect_polylines(brim_paths); + for (const Polyline &path : brim_paths) + for (const Point &point : path.points) + if (contains(holes, point, false)) + return true; + } + return false; +} + // The span is skirt_height layers, or every layer when a draft shield is on (forced even at // height 0); per-object skirts are rejected in By object printing (no room between objects). TEST_CASE("Skirt is emitted once per layer it spans", "[SkirtBrim]") @@ -153,6 +178,24 @@ TEST_CASE("Object brims are generated per instance", "[SkirtBrim]") } } +TEST_CASE("Uncombined neighboring brims precede their respective objects", "[SkirtBrim]") +{ + Print print; + Model model; + place_two_cubes_apart(0, { + { "skirt_loops", 0 }, + { "brim_type", "outer_only" }, + { "brim_width", 5 }, + { "combine_brims", 0 }, + }, print, model); + print.process(); + + REQUIRE(print.skirt_brim_groups().size() == 1); + REQUIRE(print.skirt_brim_groups().front().brims.size() == 2); + CHECK(role_sequence(gcode(print), { "brim", "perimeter" }) == + std::vector{ "brim", "perimeter", "brim", "perimeter" }); +} + TEST_CASE("Combine brims merges neighboring object instances", "[SkirtBrim]") { Print print; @@ -207,6 +250,131 @@ TEST_CASE("Brim ears appear only at corners within the max angle", "[SkirtBrim]" } } +TEST_CASE("Outer-only brim ears stay out of model holes", "[SkirtBrim]") +{ + const bool outer_only = GENERATE(false, true); + DYNAMIC_SECTION("brim_ears_outer_only=" << outer_only) { + Print print; + init_and_process_print({ TestMesh::cube_with_concave_hole }, print, { + { "skirt_loops", 0 }, + { "brim_type", "brim_ears" }, + { "brim_width", 2 }, + { "brim_ears_max_angle", 125 }, + { "brim_ears_detection_length", 0 }, + { "brim_ears_outer_only", outer_only }, + { "initial_layer_line_width", 0.5 }, + }); + + REQUIRE(brim_loop_count(print) > 0); + CHECK(brim_enters_first_layer_hole(print) != outer_only); + } +} + +TEST_CASE("Painted brim ear radius controls sliced size", "[SkirtBrim]") +{ + constexpr double ear_radius = 10.0; + + DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "skirt_loops", 0 }, + { "brim_type", "painted" }, + { "brim_width", 15 }, + { "brim_object_gap", 0.1 }, + { "brim_ears_outer_only", true }, + { "initial_layer_line_width", 0.5 }, + }); + + Print print; + Model model; + init_print({ cube(20) }, print, model, config); + print.process(); + + const PrintObject *object = print.get_object(0); + REQUIRE(!object->layers().front()->lslices.empty()); + const Point ear_center = object->layers().front()->lslices.front().contour.points.front(); + + Transform3d model_transform = model.objects.front()->instances.front()->get_transformation().get_matrix_no_offset(); + const Point ¢er_offset = object->center_offset(); + model_transform = model_transform.pretranslate( + Vec3d(-unscale(center_offset.x()), -unscale(center_offset.y()), 0)); + Vec3d model_pos = model_transform.inverse() * + Vec3d(unscale(ear_center.x()), unscale(ear_center.y()), 0); + model_pos.z() = model.objects.front()->raw_mesh_bounding_box().min.z() - 0.0001; + model.objects.front()->brim_points = { + BrimPoint(model_pos.cast(), float(ear_radius)), + }; + + print.apply(model, config); + print.process(); + + const Vec3d plate_origin = print.get_plate_origin(); + Point path_center = ear_center + object->instances().front().shift_without_plate_offset(); + path_center += Point(scaled(plate_origin.x()), scaled(plate_origin.y())); + + double max_path_radius = 0.0; + for (const auto &kv : print.get_brimMap()) { + Polylines brim_paths; + kv.second.collect_polylines(brim_paths); + for (const Polyline &path : brim_paths) + for (const Point &point : path.points) + max_path_radius = std::max(max_path_radius, unscale((point - path_center).cast().norm())); + } + + REQUIRE(max_path_radius > 0.0); + INFO("Outermost painted-ear path radius: " << max_path_radius << " mm"); + CHECK(max_path_radius > ear_radius - 0.5); + CHECK(max_path_radius < ear_radius); +} + +TEST_CASE("Outer-only painted brim ears stay out of model holes", "[SkirtBrim]") +{ + DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "skirt_loops", 0 }, + { "brim_type", "painted" }, + { "brim_ears_outer_only", true }, + { "initial_layer_line_width", 0.5 }, + }); + + Print print; + Model model; + init_print({ TestMesh::cube_with_concave_hole }, print, model, config); + + // Slice once to obtain exact outer and inner contour points in print + // coordinates, then express them in the model coordinates painted ears store. + print.process(); + const PrintObject *object = print.get_object(0); + REQUIRE(!object->layers().front()->lslices.empty()); + REQUIRE(!object->layers().front()->lslices.front().holes.empty()); + + Transform3d model_transform = model.objects.front()->instances.front()->get_transformation().get_matrix_no_offset(); + const Point ¢er_offset = object->center_offset(); + model_transform = model_transform.pretranslate( + Vec3d(-unscale(center_offset.x()), -unscale(center_offset.y()), 0)); + const double bottom_z = model.objects.front()->raw_mesh_bounding_box().min.z() - 0.0001; + auto painted_point = [&model_transform, bottom_z](const Point &point) { + Vec3d model_pos = model_transform.inverse() * + Vec3d(unscale(point.x()), unscale(point.y()), 0); + model_pos.z() = bottom_z; + return BrimPoint(model_pos.cast(), 3.f); + }; + + const ExPolygon &first_slice = object->layers().front()->lslices.front(); + Polygon inner_contour = first_slice.holes.front(); + inner_contour.reverse(); + const Points inner_ear_points = inner_contour.concave_points(55. * PI / 180.); + REQUIRE(!inner_ear_points.empty()); + model.objects.front()->brim_points = { + painted_point(first_slice.contour.points.front()), + painted_point(inner_ear_points.front()), + }; + print.apply(model, config); + print.process(); + + REQUIRE(brim_loop_count(print) > 0); + CHECK_FALSE(brim_enters_first_layer_hole(print)); +} + SCENARIO("Skirt has the configured number of loops", "[SkirtBrim]") { GIVEN("20mm cube and default config") { WHEN("skirt_loops is set to 2") { diff --git a/tests/fff_print/test_wipe_tower.cpp b/tests/fff_print/test_wipe_tower.cpp new file mode 100644 index 0000000000..2bd7ac4189 --- /dev/null +++ b/tests/fff_print/test_wipe_tower.cpp @@ -0,0 +1,184 @@ +#include + +#include +#include + +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/ClipperUtils.hpp" +#include "libslic3r/GCode/GCodeProcessor.hpp" +#include "libslic3r/GCode/WipeTower.hpp" +#include "libslic3r/PrintConfig.hpp" + +#include "test_helpers.hpp" + +using namespace Slic3r; +using namespace Slic3r::Test; + +// Taken from the config enum map rather than hand-listed, so a flavor added to GCodeFlavor later +// is covered here without editing this file. +static std::vector non_klipper_flavors() +{ + std::vector flavors; + for (const auto &[name, value] : ConfigOptionEnum::get_enum_values()) + if (GCodeFlavor(value) != gcfKlipper) + flavors.push_back(GCodeFlavor(value)); + return flavors; +} + +static std::string flavor_name(GCodeFlavor flavor) +{ + return ConfigOptionEnum::get_enum_names()[int(flavor)]; +} + +TEST_CASE("Klipper flushes the wipe tower planner queue with M400", "[WipeTower]") +{ + CHECK(std::string(flush_planner_queue_command(gcfKlipper)) == "M400\n"); +} + +TEST_CASE("Other flavors flush the wipe tower planner queue with a zero dwell", "[WipeTower]") +{ + const GCodeFlavor flavor = GENERATE(from_range(non_klipper_flavors())); + INFO("gcode flavor: " << flavor_name(flavor)); + CHECK(std::string(flush_planner_queue_command(flavor)) == "G4 S0\n"); +} + +// 1.5s is exactly representable as a float, so neither form can drift when rounded. +TEST_CASE("Klipper waits in the wipe tower with a millisecond dwell", "[WipeTower]") +{ + CHECK(wait_command(gcfKlipper, 1.5f) == "G4 P1500\n"); +} + +TEST_CASE("Other flavors wait in the wipe tower with a seconds dwell", "[WipeTower]") +{ + const GCodeFlavor flavor = GENERATE(from_range(non_klipper_flavors())); + INFO("gcode flavor: " << flavor_name(flavor)); + CHECK(wait_command(flavor, 1.5f) == "G4 S1.500\n"); +} + +// The prime tower is validated against the real printable outline, so the placement clamps have to +// agree with it wherever that outline is not a rectangle. A regular hexagon inscribed in a 200mm +// circle stands in for the shipped delta beds. +TEST_CASE("The wipe tower placement clamp follows a non-rectangular bed outline", "[WipeTower]") +{ + const coord_t margin = scaled(1.); + auto square_at = [](double x, double y, double side) { + return BoundingBox(Point::new_scale(x, y), Point::new_scale(x + side, y + side)); + }; + // Does the footprint, padded by pad, sit inside the outline once the returned move is applied? + auto lands_inside = [](BoundingBox box, const Polygons &bed, const Vec2f &move, coord_t pad) { + box.translate(Point::new_scale(move.x(), move.y())); + return diff(Polygons{box.inflated(pad).polygon()}, bed).empty(); + }; + + const Polygons hex_bed{make_circle_num_segments(scaled(100.), 6)}; + const Polygons square_bed{Polygon::new_scale(Pointfs{{0., 0.}, {200., 0.}, {200., 200.}, {0., 200.}})}; + + SECTION("a rectangular bed is left to the bounding box clamp") { + const Vec2f move = WipeTower::move_box_inside_polygon(square_at(50., 50., 30.), square_bed, margin); + CHECK_THAT(move.x(), Catch::Matchers::WithinAbs(0., 1e-6)); + CHECK_THAT(move.y(), Catch::Matchers::WithinAbs(0., 1e-6)); + } + + // Dragging the tower off one edge may not pull it away from the other, or it would jump out from + // under the cursor instead of sliding along the edge. + SECTION("only the violated axis is clamped") { + const Vec2f move = WipeTower::move_box_inside_polygon(square_at(185., 50., 30.), square_bed, margin); + CHECK_THAT(move.x(), Catch::Matchers::WithinAbs(-16., 1e-6)); + CHECK_THAT(move.y(), Catch::Matchers::WithinAbs(0., 1e-6)); + } + + SECTION("a footprint already inside the outline is left alone") { + const Vec2f move = WipeTower::move_box_inside_polygon(square_at(-15., -15., 30.), hex_bed, margin); + CHECK_THAT(move.x(), Catch::Matchers::WithinAbs(0., 1e-6)); + CHECK_THAT(move.y(), Catch::Matchers::WithinAbs(0., 1e-6)); + } + + SECTION("a footprint in the bounding box corner is pulled onto the bed") { + const BoundingBox box = square_at(55., 50., 30.); + REQUIRE_FALSE(lands_inside(box, hex_bed, Vec2f::Zero(), margin)); // in the bbox, off the hexagon + CHECK(lands_inside(box, hex_bed, WipeTower::move_box_inside_polygon(box, hex_bed, margin), margin)); + } + + // An unresolved auto brim width reaches the drag clamp as a negative margin. Padding by it would + // shrink the footprint and hand back a position the slice validation still rejects. + SECTION("a negative margin still lands the footprint inside the outline") { + const BoundingBox box = square_at(55., 50., 30.); + const coord_t brim = scaled(-0.5); + CHECK(lands_inside(box, hex_bed, WipeTower::move_box_inside_polygon(box, hex_bed, brim), 0)); + } + + SECTION("a footprint too large for the bed is left alone") { + const Vec2f move = WipeTower::move_box_inside_polygon(square_at(-200., -200., 400.), hex_bed, margin); + CHECK_THAT(move.x(), Catch::Matchers::WithinAbs(0., 1e-6)); + CHECK_THAT(move.y(), Catch::Matchers::WithinAbs(0., 1e-6)); + } +} + +// The cases above only exercise the helpers in isolation. The one below slices a real +// two-filament print, so it also covers the binding constraint of both changes: that the +// configured `gcode_flavor` reaches the wipe tower writer and lands in the exported G-code. + +// The G-code inside each WIPE_TOWER_START/WIPE_TOWER_END pair, concatenated, so an M400 emitted +// outside the tower (e.g. GCodeProcessor's pre-heat injector) cannot create a false match. +static std::string wipe_tower_regions(const std::string &gcode) +{ + const std::string &start_tag = GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start); + const std::string &end_tag = GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End); + std::string regions; + size_t pos = 0; + while (true) { + size_t start = gcode.find(start_tag, pos); + if (start == std::string::npos) + break; + size_t end = gcode.find(end_tag, start); + if (end == std::string::npos) + break; + regions.append(gcode, start, end - start); + pos = end + 1; + } + return regions; +} + +// A per-layer toolchange between the wall and infill filaments, same shape as +// test_multifilament.cpp's "Each feature prints with its assigned filament", so the wipe tower +// runs its toolchange path (and so `flush_planner_queue()`) on every layer. +static DynamicPrintConfig wipe_tower_toolchange_config(const std::string &gcode_flavor) +{ + return multifilament_config(2, { + { "sparse_infill_filament_id", 1 }, + { "internal_solid_filament_id", 1 }, + { "top_surface_filament_id", 1 }, + { "bottom_surface_filament_id", 1 }, + { "outer_wall_filament_id", 2 }, + { "inner_wall_filament_id", 2 }, + { "enable_prime_tower", true }, + { "layer_height", 0.3 }, + { "gcode_flavor", gcode_flavor }, + }); +} + +// Slices a 10mm cube under `config`. Not plain Test::slice: a brand-new Print's first `apply()` +// counts one filament in use, and DynamicPrintConfig::normalize_fdm_2's single-filament rule then +// clears `enable_prime_tower`. A second apply, once init_print's regions have settled, sees both +// filaments and the tower survives. +static std::string slice_with_prime_tower(const DynamicPrintConfig &config) +{ + Print print; + Model model; + init_print({ cube(10) }, print, model, config); + print.apply(model, config); + return gcode(print); +} + +TEST_CASE("The wipe tower's toolchange planner flush follows the gcode flavor", "[WipeTower]") +{ + auto [flavor, expected, unexpected] = GENERATE(table({ + { "klipper", "M400", "G4 S0" }, + { "marlin", "G4 S0", "M400" } })); + DYNAMIC_SECTION(flavor) { + const std::string tower = wipe_tower_regions(slice_with_prime_tower(wipe_tower_toolchange_config(flavor))); + REQUIRE_FALSE(tower.empty()); + CHECK_THAT(tower, Catch::Matchers::ContainsSubstring(expected)); + CHECK_THAT(tower, !Catch::Matchers::ContainsSubstring(unexpected)); + } +} diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index 7524c27479..1ad299473c 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -18,6 +18,7 @@ add_executable(${_TEST_NAME}_tests test_preset_setting_id.cpp test_preset_diff.cpp test_elephant_foot_compensation.cpp + test_fill_plane_path.cpp test_geometry.cpp test_multimaterial_segmentation.cpp test_placeholder_parser.cpp @@ -28,6 +29,7 @@ add_executable(${_TEST_NAME}_tests test_stl.cpp test_meshboolean.cpp test_marchingsquares.cpp + test_model.cpp test_utils.cpp test_timeutils.cpp test_voronoi.cpp diff --git a/tests/libslic3r/test_3mf.cpp b/tests/libslic3r/test_3mf.cpp index 1a082cd8e0..c839149f5f 100644 --- a/tests/libslic3r/test_3mf.cpp +++ b/tests/libslic3r/test_3mf.cpp @@ -155,10 +155,8 @@ SCENARIO("H2C multi-nozzle .3mf round-trip", "[3mf][MultiNozzle]") { // store_bbs_3mf stages Metadata/project_settings.config through the model's backup path; // point it at a writable temp dir (the default lives under a read-only root in CI). - std::string backup_dir = - (boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("orca_mn_%%%%%%%%")).string(); - boost::filesystem::create_directories(backup_dir); - model.set_backup_path(backup_dir); + ScopedTemporaryDir backup_dir("orca_mn"); + model.set_backup_path(backup_dir.string()); // Global (printer) config: give nozzle_volume_type a non-default value so the slice_info // read-back is a meaningful assertion (High Flow == 1). @@ -180,7 +178,8 @@ SCENARIO("H2C multi-nozzle .3mf round-trip", "[3mf][MultiNozzle]") { plate->config.set_key_value("enable_filament_dynamic_map", new ConfigOptionBool(true)); WHEN("stored to and reloaded from a .3mf") { - std::string test_file = std::string(TEST_DATA_DIR) + "/test_3mf/mn_roundtrip.3mf"; + ScopedTemporaryFile temp(".3mf"); + const std::string test_file = temp.string(); StoreParams store_params; store_params.path = test_file.c_str(); @@ -202,8 +201,6 @@ SCENARIO("H2C multi-nozzle .3mf round-trip", "[3mf][MultiNozzle]") { bool loaded = load_bbs_3mf(test_file.c_str(), &dst_config, &ctxt, &dst_model, &dst_plates, &project_presets, &is_bbl_3mf, &is_orca_3mf, &file_version, nullptr, LoadStrategy::LoadModel | LoadStrategy::LoadConfig); - boost::filesystem::remove(test_file); - THEN("every multi-nozzle key round-trips as expected") { REQUIRE(loaded); REQUIRE(dst_plates.size() >= 1); @@ -233,7 +230,6 @@ SCENARIO("H2C multi-nozzle .3mf round-trip", "[3mf][MultiNozzle]") { release_PlateData_list(dst_plates); } delete plate; // store_bbs_3mf does not take ownership of the source plate - boost::filesystem::remove_all(backup_dir); } } @@ -250,10 +246,8 @@ SCENARIO("Non-standard nozzle diameter survives .3mf save on a single-nozzle pri REQUIRE(load_stl(src_file.c_str(), &model)); model.add_default_instances(); - std::string backup_dir = - (boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("orca_nd_%%%%%%%%")).string(); - boost::filesystem::create_directories(backup_dir); - model.set_backup_path(backup_dir); + ScopedTemporaryDir backup_dir("orca_nd"); + model.set_backup_path(backup_dir.string()); // Single extruder with a non-standard 0.5 mm nozzle; extruder_max_nozzle_count stays at its // default (no nozzle cluster), so the writer must emit the exact config diameter. @@ -276,7 +270,8 @@ SCENARIO("Non-standard nozzle diameter survives .3mf save on a single-nozzle pri plate->slice_filaments_info.push_back(fi); WHEN("stored to and reloaded from a .3mf") { - std::string test_file = std::string(TEST_DATA_DIR) + "/test_3mf/nd_roundtrip.3mf"; + ScopedTemporaryFile temp(".3mf"); + const std::string test_file = temp.string(); StoreParams store_params; store_params.path = test_file.c_str(); @@ -296,8 +291,6 @@ SCENARIO("Non-standard nozzle diameter survives .3mf save on a single-nozzle pri bool loaded = load_bbs_3mf(test_file.c_str(), &dst_config, &ctxt, &dst_model, &dst_plates, &project_presets, &is_bbl_3mf, &is_orca_3mf, &file_version, nullptr, LoadStrategy::LoadModel | LoadStrategy::LoadConfig); - boost::filesystem::remove(test_file); - THEN("the saved nozzle diameter is the exact 0.5, not the rounded 0.4") { REQUIRE(loaded); REQUIRE(dst_plates.size() >= 1); @@ -315,7 +308,6 @@ SCENARIO("Non-standard nozzle diameter survives .3mf save on a single-nozzle pri release_PlateData_list(dst_plates); } delete plate; // store_bbs_3mf does not take ownership of the source plate - boost::filesystem::remove_all(backup_dir); } } @@ -436,10 +428,8 @@ SCENARIO("Nozzle-group metadata .3mf round-trip", "[3mf][MultiNozzle]") { REQUIRE(load_stl(src_file.c_str(), &model)); model.add_default_instances(); - std::string backup_dir = - (boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("orca_ng_%%%%%%%%")).string(); - boost::filesystem::create_directories(backup_dir); - model.set_backup_path(backup_dir); + ScopedTemporaryDir backup_dir("orca_ng"); + model.set_backup_path(backup_dir.string()); DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); @@ -459,7 +449,8 @@ SCENARIO("Nozzle-group metadata .3mf round-trip", "[3mf][MultiNozzle]") { plate->config.set_key_value("filament_map", new ConfigOptionInts({ 1, 2, 1 })); WHEN("stored to and reloaded from a .3mf") { - std::string test_file = std::string(TEST_DATA_DIR) + "/test_3mf/ng_roundtrip.3mf"; + ScopedTemporaryFile temp(".3mf"); + const std::string test_file = temp.string(); StoreParams store_params; store_params.path = test_file.c_str(); @@ -479,8 +470,6 @@ SCENARIO("Nozzle-group metadata .3mf round-trip", "[3mf][MultiNozzle]") { bool loaded = load_bbs_3mf(test_file.c_str(), &dst_config, &ctxt, &dst_model, &dst_plates, &project_presets, &is_bbl_3mf, &is_orca_3mf, &file_version, nullptr, LoadStrategy::LoadModel | LoadStrategy::LoadConfig); - boost::filesystem::remove(test_file); - THEN("the tags round-trip into the loaded plate's nozzles_info") { REQUIRE(loaded); REQUIRE(dst_plates.size() >= 1); @@ -506,67 +495,5 @@ SCENARIO("Nozzle-group metadata .3mf round-trip", "[3mf][MultiNozzle]") { release_PlateData_list(dst_plates); } delete plate; - boost::filesystem::remove_all(backup_dir); - } -} - -SCENARIO("2D convex hull of sinking object", "[3mf][.]") { - GIVEN("model") { - // load a model - Model model; - std::string src_file = std::string(TEST_DATA_DIR) + "/test_3mf/Prusa.stl"; - REQUIRE(load_stl(src_file.c_str(), &model)); - model.add_default_instances(); - - WHEN("model is rotated, scaled and set as sinking") { - ModelObject* object = model.objects[0]; - object->center_around_origin(false); - - // This outputs the same exact data as the Prusaslicer test - write_debug_stl("3mf/orca.ascii", object->volumes[0]->mesh()); - - // set instance's attitude so that it is rotated, scaled (and sinking? how is it sinking? the rotation? does it matter if it's sinking?) - ModelInstance* instance = object->instances[0]; - instance->set_rotation(X, -M_PI / 4.0); - instance->set_offset(Vec3d::Zero()); - instance->set_scaling_factor({ 2.0, 2.0, 2.0 }); - - // calculate 2D convex hull - auto trafo = instance->get_transformation().get_matrix(); - - // This matrix is the same exact matrix as the Prusaslicer test - CAPTURE(trafo); - Polygon hull_2d = object->convex_hull_2d(trafo); - - // But we get different hull_2d.points here (and somehow decimal numbers despite being int64_t values, but that's probabaly printing configuration somewhere -- Prusaslicer's prints out with newlines between the X&Y and not one between coordinates, which is about the worse possible output). - // I think it's something to do with PrusaSlicer ignoring everything under the Z plane, which makes sense from the results. - // See the comments added to ModelObject::convex_hull_2d for more information. - - // verify result - Points result = { - { -91501496, -15914144 }, - { 91501496, -15914144 }, - { 91501496, 4243 }, - { 78229680, 4246883 }, - { 56898100, 4246883 }, - { -85501496, 4242641 }, - { -91501496, 4243 } - }; - - THEN("2D convex hull should match with reference") { - // Allow 1um error due to floating point rounding. - bool res = hull_2d.points.size() == result.size(); - if (res) { - for (size_t i = 0; i < result.size(); ++ i) { - const Point &p1 = result[i]; - const Point &p2 = hull_2d.points[i]; - CHECK((std::abs(p1.x() - p2.x()) > 1 || std::abs(p1.y() - p2.y()) > 1)); - } - } - - CAPTURE(hull_2d.points); - REQUIRE(res); - } - } } } diff --git a/tests/libslic3r/test_config.cpp b/tests/libslic3r/test_config.cpp index f256ae3442..12b161322d 100644 --- a/tests/libslic3r/test_config.cpp +++ b/tests/libslic3r/test_config.cpp @@ -4,6 +4,8 @@ #include "libslic3r/PrintConfigConstants.hpp" #include "libslic3r/LocalesUtils.hpp" +#include "test_utils.hpp" + #include #include #include @@ -233,6 +235,56 @@ SCENARIO("Config ini load/save interface", "[Config]") { } } +TEST_CASE("Flush-volume warning predicate respects used filament transitions", "[Config][Regression]") +{ + const std::vector multipliers = {1.0}; + + SECTION("Single used filament does not trigger warning with zero transition entries") + { + const std::vector matrix = { + 0.0, 0.0, + 0.0, 0.0 + }; + const std::vector used_filaments = {1}; + + REQUIRE_FALSE(has_zero_flush_volume_for_used_filaments(matrix, multipliers, used_filaments)); + } + + SECTION("Two used filaments trigger warning when transition flush entry is zero") + { + const std::vector matrix = { + 0.0, 0.0, + 0.0, 0.0 + }; + const std::vector used_filaments = {1, 2}; + + REQUIRE(has_zero_flush_volume_for_used_filaments(matrix, multipliers, used_filaments)); + } + + SECTION("Two used filaments do not trigger warning when transitions are non-zero") + { + const std::vector matrix = { + 0.0, 280.0, + 280.0, 0.0 + }; + const std::vector used_filaments = {1, 2}; + + REQUIRE_FALSE(has_zero_flush_volume_for_used_filaments(matrix, multipliers, used_filaments)); + } + + SECTION("Zero multiplier still triggers warning when multiple filaments are used") + { + const std::vector matrix = { + 0.0, 280.0, + 280.0, 0.0 + }; + const std::vector zero_multiplier = {0.0}; + const std::vector used_filaments = {1, 2}; + + REQUIRE(has_zero_flush_volume_for_used_filaments(matrix, zero_multiplier, used_filaments)); + } +} + // TODO: https://github.com/SoftFever/OrcaSlicer/issues/11269 - Is this test still relevant? Delete if not. // It was failing so at least "nozzle_type" and "extruder_printable_area" could not be serialized // and an exception was thrown, but "nozzle_type" has been around for at least 3 months now. @@ -407,8 +459,7 @@ SCENARIO("update_diff_values_to_child_config tolerates legacy machine-limit vect // } TEST_CASE("save_to_json round-trips plugin capability references as strings", "[Config][plugins]") { - namespace fs = boost::filesystem; - const fs::path tmp = fs::temp_directory_path() / fs::unique_path("orca_plugins_%%%%-%%%%.json"); + ScopedTemporaryFile tmp(".json"); const std::vector refs = { "local_plugin;;inset", "cloud_plugin;550e8400-e29b-41d4-a716-446655440000;inset" @@ -435,8 +486,6 @@ TEST_CASE("save_to_json round-trips plugin capability references as strings", "[ REQUIRE(reloaded.load_from_json(tmp.string(), substitutions, true, key_values, reason) == 0); CHECK(reason.empty()); CHECK(reloaded.option("slicing_pipeline_plugin")->values == refs); - - fs::remove(tmp); } TEST_CASE("plugin capability references survive string-map serialization", "[Config][plugins]") { diff --git a/tests/libslic3r/test_config_variant_expansion.cpp b/tests/libslic3r/test_config_variant_expansion.cpp index 14675fd4dc..dd7de2af44 100644 --- a/tests/libslic3r/test_config_variant_expansion.cpp +++ b/tests/libslic3r/test_config_variant_expansion.cpp @@ -43,18 +43,33 @@ TEST_CASE("apply_override fills nil entries from the 0-based default index", "[C REQUIRE(resolved.values == std::vector({30., 42.})); } - SECTION("an index past the machine slots falls back to the first slot") { + SECTION("an index past the machine slots keeps the slot's own value") { std::vector slot_index{5, 0}; ConfigOptionFloats resolved(machine); REQUIRE(resolved.apply_override(&filament, slot_index)); REQUIRE(resolved.values == std::vector({10., 42.})); } - SECTION("a negative index (unresolved slot) falls back to the first slot") { - std::vector slot_index{-1, 0}; + SECTION("a negative index (unresolved slot) keeps the slot's own value") { + ConfigOptionFloatsNullable all_nil; + all_nil.values = {ConfigOptionFloatsNullable::nil_value(), ConfigOptionFloatsNullable::nil_value(), + ConfigOptionFloatsNullable::nil_value()}; + std::vector slot_index{2, -1, 0}; ConfigOptionFloats resolved(machine); - REQUIRE(resolved.apply_override(&filament, slot_index)); - REQUIRE(resolved.values == std::vector({10., 42.})); + REQUIRE(!resolved.apply_override(&all_nil, slot_index)); + REQUIRE(resolved.values == std::vector({30., 20., 10.})); + } + + SECTION("all-nil overrides keyed by unresolved slots leave the machine values intact") { + // The failed-lookup map a degenerate print_extruder_id used to produce; the negative + // slots must not collapse the machine array to its first value. + ConfigOptionFloats per_extruder({100., 70., 70., 70., 100.}); + ConfigOptionFloatsNullable all_nil; + all_nil.values.assign(5, ConfigOptionFloatsNullable::nil_value()); + std::vector slot_index{0, -1, -1, -1, 0}; + ConfigOptionFloats resolved(per_extruder); + REQUIRE(!resolved.apply_override(&all_nil, slot_index)); + REQUIRE(resolved.values == std::vector({100., 70., 70., 70., 100.})); } } @@ -272,6 +287,102 @@ TEST_CASE("update_values_to_printer_extruders expands one slot per (extruder x v } } +TEST_CASE("update_values_to_printer_extruders synthesizes degenerate process variant columns", "[Config]") +{ + // Non-BBL process presets and 3mf project configs keep the length-1 defaults for + // print_extruder_id/print_extruder_variant; only BBL system presets ship full-width columns. + auto add_degenerate_print_columns = [](DynamicPrintConfig &config) { + config.option("print_extruder_id", true)->values = {1}; + config.option("print_extruder_variant", true)->values = {"Direct Drive Standard"}; + config.option("outer_wall_speed", true)->values = {30.}; + }; + + SECTION("a single-column pair on a multi-extruder machine expands to one column per extruder") { + DynamicPrintConfig config; + config.option("extruder_type", true)->values = {etDirectDrive, etDirectDrive}; + config.option("nozzle_volume_type", true)->values = {nvtStandard, nvtStandard}; + config.option("extruder_variant_list", true)->values = {"Direct Drive Standard", "Direct Drive Standard"}; + add_degenerate_print_columns(config); + + std::vector> nozzle_volume_types; + int extruder_count = 2; + int count = config.get_extruder_nozzle_volume_count(extruder_count, nozzle_volume_types); + + std::vector variant_index = config.update_values_to_printer_extruders(config, extruder_count, count, nozzle_volume_types, + print_options_with_variant, "print_extruder_id", "print_extruder_variant"); + + REQUIRE(variant_index == std::vector({0, 1})); + REQUIRE(config.option("print_extruder_id")->values == std::vector({1, 2})); + REQUIRE(config.option("print_extruder_variant")->values == + std::vector({"Direct Drive Standard", "Direct Drive Standard"})); + // width-1 data arrays replicate their only column into every slot + REQUIRE(config.option("outer_wall_speed")->values == std::vector({30., 30.})); + } + + SECTION("a multi-variant list synthesizes one column per (extruder x variant)") { + DynamicPrintConfig config = make_hybrid_printer_config(); + add_degenerate_print_columns(config); + + std::vector> nozzle_volume_types; + int extruder_count = 2; + int count = config.get_extruder_nozzle_volume_count(extruder_count, nozzle_volume_types); + REQUIRE(count == 3); + + std::vector variant_index = config.update_values_to_printer_extruders(config, extruder_count, count, nozzle_volume_types, + print_options_with_variant, "print_extruder_id", "print_extruder_variant"); + + // same slot resolution as the explicit BBL-style 4-column layout + REQUIRE(variant_index == std::vector({0, 2, 3})); + REQUIRE(config.option("print_extruder_id")->values == std::vector({1, 2, 2})); + REQUIRE(config.option("print_extruder_variant")->values == + std::vector({"Direct Drive Standard", "Direct Drive Standard", "Direct Drive High Flow"})); + REQUIRE(config.option("outer_wall_speed")->values == std::vector({30., 30., 30.})); + } + + SECTION("a single-extruder single-column layout is not treated as degenerate") { + DynamicPrintConfig config; + config.option("extruder_type", true)->values = {etDirectDrive}; + config.option("nozzle_volume_type", true)->values = {nvtStandard}; + config.option("extruder_variant_list", true)->values = {"Direct Drive Standard"}; + add_degenerate_print_columns(config); + + std::vector> nozzle_volume_types; + int extruder_count = 1; + int count = config.get_extruder_nozzle_volume_count(extruder_count, nozzle_volume_types); + + config.update_values_to_printer_extruders(config, extruder_count, count, nozzle_volume_types, + print_options_with_variant, "print_extruder_id", "print_extruder_variant"); + + REQUIRE(config.option("print_extruder_id")->values == std::vector({1})); + REQUIRE(config.option("outer_wall_speed")->values == std::vector({30.})); + } + + SECTION("a second expansion leaves the synthesized layout unchanged") { + DynamicPrintConfig config; + config.option("extruder_type", true)->values = {etDirectDrive, etDirectDrive}; + config.option("nozzle_volume_type", true)->values = {nvtStandard, nvtStandard}; + config.option("extruder_variant_list", true)->values = {"Direct Drive Standard", "Direct Drive Standard"}; + add_degenerate_print_columns(config); + + std::vector> nozzle_volume_types; + int extruder_count = 2; + int count = config.get_extruder_nozzle_volume_count(extruder_count, nozzle_volume_types); + + config.update_values_to_printer_extruders(config, extruder_count, count, nozzle_volume_types, + print_options_with_variant, "print_extruder_id", "print_extruder_variant"); + DynamicPrintConfig once = config; + config.update_values_to_printer_extruders(config, extruder_count, count, nozzle_volume_types, + print_options_with_variant, "print_extruder_id", "print_extruder_variant"); + + REQUIRE(config.option("print_extruder_id")->values == + once.option("print_extruder_id")->values); + REQUIRE(config.option("print_extruder_variant")->values == + once.option("print_extruder_variant")->values); + REQUIRE(config.option("outer_wall_speed")->values == + once.option("outer_wall_speed")->values); + } +} + TEST_CASE("update_values_to_printer_extruders_for_multiple_filaments resolves per-filament slots", "[Config]") { auto make_filament_arrays = [](DynamicPrintConfig &config) { diff --git a/tests/libslic3r/test_fill_plane_path.cpp b/tests/libslic3r/test_fill_plane_path.cpp new file mode 100644 index 0000000000..bbb75dce58 --- /dev/null +++ b/tests/libslic3r/test_fill_plane_path.cpp @@ -0,0 +1,164 @@ +#include + +#include +#include +#include +#include + +#include "libslic3r/Fill/FillPlanePath.hpp" +#include "libslic3r/PrintConfig.hpp" + +using namespace Slic3r; + +namespace { + +constexpr double output_scale = 1'000'000.; + +class TestableHilbertCurve : public FillHilbertCurve +{ +public: + Points generate_points(double resolution, double smooth_factor = 0., coord_t max_coordinate = 7) + { + InfillPolylineOutput output(output_scale); + FillParams params; + params.smooth_factor = smooth_factor; + FillHilbertCurve::generate(0, 0, max_coordinate, max_coordinate, resolution, params, output); + return std::move(output.result()); + } +}; + +double path_length(const Points &points) +{ + double length = 0.; + for (size_t i = 1; i < points.size(); ++i) + length += (points[i] - points[i - 1]).cast().norm(); + return length; +} + +double discrete_curvature_at(const Points &points, const Point &point) +{ + const auto point_it = std::find(points.begin(), points.end(), point); + REQUIRE(point_it != points.end()); + const size_t point_idx = size_t(std::distance(points.begin(), point_it)); + REQUIRE(point_idx > 0); + REQUIRE(point_idx + 1 < points.size()); + + const Vec2d incoming = (points[point_idx] - points[point_idx - 1]).cast() / output_scale; + const Vec2d outgoing = (points[point_idx + 1] - points[point_idx]).cast() / output_scale; + const Vec2d chord = incoming + outgoing; + const double cross = std::abs(incoming.x() * outgoing.y() - incoming.y() * outgoing.x()); + return 2. * cross / (incoming.norm() * outgoing.norm() * chord.norm()); +} + +} // namespace + +TEST_CASE("Hilbert curve exposes a smoothing factor", "[FillPlanePath]") +{ + const ConfigOptionDef *factor_def = print_config_def.get("sparse_infill_smooth_factor"); + REQUIRE(factor_def != nullptr); + REQUIRE(factor_def->type == coPercent); + REQUIRE_THAT(factor_def->min, Catch::Matchers::WithinAbs(0., 1e-12)); + REQUIRE_THAT(factor_def->max, Catch::Matchers::WithinAbs(100., 1e-12)); + REQUIRE_THAT(factor_def->get_default_value()->value, + Catch::Matchers::WithinAbs(0., 1e-12)); +} + +TEST_CASE("Hilbert curve smoothing rounds right angle turns", "[FillPlanePath]") +{ + const Points sharp = TestableHilbertCurve().generate_points(0.005); + const Points smooth = TestableHilbertCurve().generate_points(0.005, 1.); + + REQUIRE(smooth.front() == sharp.front()); + REQUIRE(smooth.back() == sharp.back()); + REQUIRE(smooth.size() > sharp.size()); + + bool has_turn = false; + for (size_t i = 1; i < smooth.size(); ++i) { + const Vec2d segment = (smooth[i] - smooth[i - 1]).cast(); + REQUIRE(segment.squaredNorm() > 0.); + } + for (size_t i = 1; i + 1 < smooth.size(); ++i) { + const Vec2d incoming = (smooth[i] - smooth[i - 1]).cast(); + const Vec2d outgoing = (smooth[i + 1] - smooth[i]).cast(); + const double cross = incoming.x() * outgoing.y() - incoming.y() * outgoing.x(); + const double cosine = incoming.dot(outgoing) / (incoming.norm() * outgoing.norm()); + has_turn |= std::abs(cross) > 0.; + REQUIRE(cosine > 0.); + } + REQUIRE(has_turn); + + const coord_t upper_bound = coord_t(7 * output_scale); + for (const Point &point : smooth) { + REQUIRE(point.x() >= 0); + REQUIRE(point.y() >= 0); + REQUIRE(point.x() <= upper_bound); + REQUIRE(point.y() <= upper_bound); + } +} + +TEST_CASE("Smoothed Hilbert curve honors path resolution", "[FillPlanePath]") +{ + const Points coarse = TestableHilbertCurve().generate_points(0.1, 1.); + const Points fine = TestableHilbertCurve().generate_points(0.001, 1.); + + REQUIRE(fine.size() > coarse.size()); + REQUIRE(fine.front() == coarse.front()); + REQUIRE(fine.back() == coarse.back()); +} + +TEST_CASE("Smoothed Hilbert corners use a uniform subdivision depth", "[FillPlanePath]") +{ + const Points smooth = TestableHilbertCurve().generate_points(0.0035, 1., 1); + const Point curve_entry(0, coord_t(0.5 * output_scale)); + const Point curve_exit(coord_t(0.5 * output_scale), coord_t(output_scale)); + + const auto entry_it = std::find(smooth.begin(), smooth.end(), curve_entry); + REQUIRE(entry_it != smooth.end()); + const auto exit_it = std::find(entry_it, smooth.end(), curve_exit); + REQUIRE(exit_it != smooth.end()); + + const size_t segment_count = size_t(std::distance(entry_it, exit_it)); + REQUIRE(segment_count > 1); + REQUIRE((segment_count & (segment_count - 1)) == 0); + + double previous_length = (entry_it[1] - entry_it[0]).cast().norm(); + REQUIRE(previous_length > 0.); + double max_length_ratio = 1.; + for (size_t segment = 1; segment < segment_count; ++segment) { + const double current_length = (entry_it[segment + 1] - entry_it[segment]).cast().norm(); + REQUIRE(current_length > 0.); + max_length_ratio = std::max(max_length_ratio, + std::max(current_length / previous_length, previous_length / current_length)); + previous_length = current_length; + } + REQUIRE(max_length_ratio < 1.5); +} + +TEST_CASE("Hilbert smoothing joins straight segments with continuous curvature", "[FillPlanePath]") +{ + const Points coarse = TestableHilbertCurve().generate_points(0.005, 0.5, 1); + const Points fine = TestableHilbertCurve().generate_points(0.0001, 0.5, 1); + const Point first_curve_entry(0, coord_t(0.75 * output_scale)); + + const double coarse_entry_curvature = discrete_curvature_at(coarse, first_curve_entry); + const double fine_entry_curvature = discrete_curvature_at(fine, first_curve_entry); + REQUIRE(coarse_entry_curvature > 0.); + REQUIRE(fine_entry_curvature < 0.25 * coarse_entry_curvature); +} + +TEST_CASE("Hilbert curve smooth factor controls corner curvature", "[FillPlanePath]") +{ + const Points sharp = TestableHilbertCurve().generate_points(0.005); + const Points half_smooth = TestableHilbertCurve().generate_points(0.005, 0.5); + const Points full_smooth = TestableHilbertCurve().generate_points(0.005, 1.); + const Points invalid_factor = TestableHilbertCurve().generate_points( + 0.005, std::numeric_limits::quiet_NaN()); + + REQUIRE(full_smooth.front() == half_smooth.front()); + REQUIRE(full_smooth.back() == half_smooth.back()); + REQUIRE(path_length(full_smooth) < path_length(half_smooth)); + REQUIRE(invalid_factor == sharp); + + for (size_t i = 1; i < full_smooth.size(); ++i) + REQUIRE((full_smooth[i] - full_smooth[i - 1]).squaredNorm() > 0); +} diff --git a/tests/libslic3r/test_model.cpp b/tests/libslic3r/test_model.cpp new file mode 100644 index 0000000000..3a580e3be2 --- /dev/null +++ b/tests/libslic3r/test_model.cpp @@ -0,0 +1,40 @@ +#include + +#include "libslic3r/Model.hpp" + +using namespace Slic3r; + +// convex_hull_2d does not clip geometry below the bed, so these cases avoid +// sinking transforms. +TEST_CASE("A part's 2D convex hull is its footprint projected onto the bed", "[Model]") +{ + Model model; + ModelObject* object = model.add_object(); + // Keep the cube's raw coordinates ([0,20] on every axis): the default + // add_volume re-centers the geometry, which would move the footprint. + object->add_volume(make_cube(20, 20, 20), ModelVolumeType::MODEL_PART, false); + + SECTION("identity transform yields the 20 mm square") { + const Polygon hull = object->convex_hull_2d(Geometry::Transformation{}.get_matrix()); + const BoundingBox bb = hull.bounding_box(); + CHECK(hull.size() == 4); + CHECK(bb.min.x() == scaled(0.)); + CHECK(bb.min.y() == scaled(0.)); + CHECK(bb.max.x() == scaled(20.)); + CHECK(bb.max.y() == scaled(20.)); + } + + SECTION("scaling and offset move and grow the footprint") { + Geometry::Transformation t; + t.set_scaling_factor({2, 2, 2}); // cube now spans [0,40] + t.set_offset({10, 5, 0}); // then shift +10 in X, +5 in Y + + const Polygon hull = object->convex_hull_2d(t.get_matrix()); + const BoundingBox bb = hull.bounding_box(); + CHECK(hull.size() == 4); + CHECK(bb.min.x() == scaled(10.)); + CHECK(bb.min.y() == scaled(5.)); + CHECK(bb.max.x() == scaled(50.)); + CHECK(bb.max.y() == scaled(45.)); + } +} diff --git a/tests/libslic3r/test_preset_bundle_loading.cpp b/tests/libslic3r/test_preset_bundle_loading.cpp index 351535dd9d..844ccb6a8b 100644 --- a/tests/libslic3r/test_preset_bundle_loading.cpp +++ b/tests/libslic3r/test_preset_bundle_loading.cpp @@ -5,28 +5,14 @@ #include "libslic3r/PresetBundle.hpp" #include "libslic3r/AppConfig.hpp" +#include "test_utils.hpp" + using namespace Slic3r; namespace { namespace fs = boost::filesystem; -struct TempPresetDir { - fs::path path; - - TempPresetDir() - { - path = fs::temp_directory_path() / fs::unique_path("orcaslicer-preset-%%%%-%%%%-%%%%"); - fs::create_directories(path); - } - - ~TempPresetDir() - { - boost::system::error_code ec; - fs::remove_all(path, ec); - } -}; - void write_print_preset(const DynamicPrintConfig &default_config, const fs::path &file, const std::string &name, const std::string &inherits = {}) { DynamicPrintConfig config(default_config); @@ -82,17 +68,17 @@ struct RenameTestCollection : public PresetCollection TEST_CASE("Preset identity is canonicalized from load path", "[Preset][Identity]") { - TempPresetDir temp_dir; + ScopedTemporaryDir temp_dir; PresetBundle bundle; PresetsConfigSubstitutions substitutions; - write_print_preset(bundle.prints.default_preset().config, temp_dir.path / PRESET_PRINT_NAME / "User.json", "User"); - write_print_preset(bundle.prints.default_preset().config, temp_dir.path / PRESET_LOCAL_DIR / "bundle-1" / PRESET_PRINT_NAME / "LocalBundle.json", "LocalBundle"); - write_print_preset(bundle.prints.default_preset().config, temp_dir.path / PRESET_SUBSCRIBED_DIR / "remote-1" / PRESET_PRINT_NAME / "Subscribed.json", "Subscribed"); + write_print_preset(bundle.prints.default_preset().config, temp_dir.path() / PRESET_PRINT_NAME / "User.json", "User"); + write_print_preset(bundle.prints.default_preset().config, temp_dir.path() / PRESET_LOCAL_DIR / "bundle-1" / PRESET_PRINT_NAME / "LocalBundle.json", "LocalBundle"); + write_print_preset(bundle.prints.default_preset().config, temp_dir.path() / PRESET_SUBSCRIBED_DIR / "remote-1" / PRESET_PRINT_NAME / "Subscribed.json", "Subscribed"); - bundle.prints.load_presets(temp_dir.path.string(), PRESET_PRINT_NAME, substitutions, ForwardCompatibilitySubstitutionRule::Disable); - bundle.prints.load_presets((temp_dir.path / PRESET_LOCAL_DIR / "bundle-1").string(), PRESET_PRINT_NAME, substitutions, ForwardCompatibilitySubstitutionRule::Disable); - bundle.prints.load_presets((temp_dir.path / PRESET_SUBSCRIBED_DIR / "remote-1").string(), PRESET_PRINT_NAME, substitutions, ForwardCompatibilitySubstitutionRule::Disable); + bundle.prints.load_presets(temp_dir.path().string(), PRESET_PRINT_NAME, substitutions, ForwardCompatibilitySubstitutionRule::Disable); + bundle.prints.load_presets((temp_dir.path() / PRESET_LOCAL_DIR / "bundle-1").string(), PRESET_PRINT_NAME, substitutions, ForwardCompatibilitySubstitutionRule::Disable); + bundle.prints.load_presets((temp_dir.path() / PRESET_SUBSCRIBED_DIR / "remote-1").string(), PRESET_PRINT_NAME, substitutions, ForwardCompatibilitySubstitutionRule::Disable); const Preset *root_user = bundle.prints.find_preset("User"); REQUIRE(root_user != nullptr); @@ -112,14 +98,14 @@ TEST_CASE("Preset identity is canonicalized from load path", "[Preset][Identity] TEST_CASE("Legacy bundle import without bundle metadata stays in the user preset directory", "[Preset][Identity]") { - TempPresetDir temp_dir; + ScopedTemporaryDir temp_dir; PresetBundle bundle; PresetsConfigSubstitutions substitutions; std::vector result; int overwrite = 0; - std::string file = (temp_dir.path / "legacy-bundle" / "Imported.json").string(); - const fs::path user_root = temp_dir.path / "user"; + std::string file = (temp_dir.path() / "legacy-bundle" / "Imported.json").string(); + const fs::path user_root = temp_dir.path() / "user"; write_print_preset(bundle.prints.default_preset().config, file, "Imported"); fs::create_directories(user_root); @@ -252,7 +238,7 @@ TEST_CASE("find_preset2 auto-matches removed Generic vendor profiles to the libr TEST_CASE("Renamed parent is normalized into a loaded preset's inherits", "[Preset][Rename]") { - TempPresetDir temp_dir; + ScopedTemporaryDir temp_dir; RenameTestCollection coll; // Current parent, renamed from "Old Process". @@ -262,10 +248,10 @@ TEST_CASE("Renamed parent is normalized into a loaded preset's inherits", "[Pres // A user preset on disk that still inherits the OLD name. write_preset_with_inherits(coll.default_preset().config, - temp_dir.path / PRESET_PRINT_NAME / "Child.json", "Child", "Old Process"); + temp_dir.path() / PRESET_PRINT_NAME / "Child.json", "Child", "Old Process"); PresetsConfigSubstitutions substitutions; - coll.load_presets(temp_dir.path.string(), PRESET_PRINT_NAME, substitutions, + coll.load_presets(temp_dir.path().string(), PRESET_PRINT_NAME, substitutions, ForwardCompatibilitySubstitutionRule::Disable); const Preset *child = coll.find_preset("Child"); @@ -279,17 +265,17 @@ TEST_CASE("Renamed parent is normalized into a loaded preset's inherits", "[Pres TEST_CASE("Removed Generic parent is normalized into a loaded filament's inherits", "[Preset][Rename]") { - TempPresetDir temp_dir; + ScopedTemporaryDir temp_dir; PresetBundle bundle; add_inmemory_preset(bundle.filaments, "Generic PLA @System"); // A user filament that still inherits a removed " Generic PLA" profile. write_preset_with_inherits(bundle.filaments.default_preset().config, - temp_dir.path / PRESET_FILAMENT_NAME / "MyPLA.json", "MyPLA", "Voron Generic PLA"); + temp_dir.path() / PRESET_FILAMENT_NAME / "MyPLA.json", "MyPLA", "Voron Generic PLA"); PresetsConfigSubstitutions substitutions; - bundle.filaments.load_presets(temp_dir.path.string(), PRESET_FILAMENT_NAME, substitutions, + bundle.filaments.load_presets(temp_dir.path().string(), PRESET_FILAMENT_NAME, substitutions, ForwardCompatibilitySubstitutionRule::Disable); const Preset *child = bundle.filaments.find_preset("MyPLA"); @@ -488,3 +474,69 @@ TEST_CASE("Plugin capability override keys are scoped per preset type", "[Preset } } +namespace { + +// A standalone filament collection that exposes the protected library masking builder, so the Orca +// Filament Library scenario can be set up without the full system-profile load pipeline. +struct LibraryFilamentTestCollection : public PresetCollection +{ + LibraryFilamentTestCollection() + : PresetCollection(Preset::TYPE_FILAMENT, Preset::filament_options(), + static_cast(FullPrintConfig::defaults())) + {} + using PresetCollection::update_library_profile_excluded_from; +}; + +} // namespace + +// Orca: a filament in the Orca Filament Library that names its compatible printers has to hide the generic +// library filament sharing its alias, the same way a vendor owned filament does. Otherwise both are compatible +// with that printer and the plater combo box lists the shared alias twice. +TEST_CASE("A printer specific filament supersedes the generic library filament with the same alias", "[Preset][Bundle]") +{ + LibraryFilamentTestCollection filaments; + PresetCollection printers(Preset::TYPE_PRINTER, Preset::printer_options(), + static_cast(FullPrintConfig::defaults())); + // The masking keys off the vendor name, which VendorProfile's constructor does not derive from the id. + VendorProfile library(PresetBundle::ORCA_FILAMENT_LIBRARY); + VendorProfile vendor("Vendor"); + library.name = PresetBundle::ORCA_FILAMENT_LIBRARY; + vendor.name = "Vendor"; + + auto add_filament = [&filaments](const VendorProfile &owner, const std::string &name, std::vector compatible_printers) { + Preset &preset = add_inmemory_preset(filaments, name); + preset.alias = "Generic ABS"; + preset.vendor = &owner; + preset.config.option("compatible_printers", true)->values = std::move(compatible_printers); + }; + + add_filament(library, "Generic ABS @System", {}); + add_filament(library, "Generic ABS @Printer A", { "Printer A" }); + add_filament(vendor, "Generic ABS @Printer B", { "Printer B" }); + + filaments.update_library_profile_excluded_from(); + + const Preset *generic = filaments.find_preset("Generic ABS @System"); + REQUIRE(generic != nullptr); + CHECK(generic->m_excluded_from.count("Printer A") == 1); + CHECK(generic->m_excluded_from.count("Printer B") == 1); + CHECK(generic->m_excluded_from.size() == 2); + + // A printer specific profile names printers, so it is never the one being hidden - not even by itself. + const Preset *specific = filaments.find_preset("Generic ABS @Printer A"); + REQUIRE(specific != nullptr); + CHECK(specific->m_excluded_from.empty()); + + // ...and the generic profile really drops out of the compatible set on the printer it is hidden from. + add_inmemory_preset(printers, "Printer A"); + add_inmemory_preset(printers, "Printer C"); + const Preset *printer_a = printers.find_preset("Printer A"); + const Preset *printer_c = printers.find_preset("Printer C"); + REQUIRE(printer_a != nullptr); + REQUIRE(printer_c != nullptr); + + const PresetWithVendorProfile generic_lib(*generic, &library); + CHECK_FALSE(is_compatible_with_printer(generic_lib, PresetWithVendorProfile(*printer_a, nullptr))); + CHECK(is_compatible_with_printer(generic_lib, PresetWithVendorProfile(*printer_c, nullptr))); +} + diff --git a/tests/libslic3r/test_toolordering_nozzle_group.cpp b/tests/libslic3r/test_toolordering_nozzle_group.cpp index ae6aac4dbe..26e36c0dbf 100644 --- a/tests/libslic3r/test_toolordering_nozzle_group.cpp +++ b/tests/libslic3r/test_toolordering_nozzle_group.cpp @@ -8,6 +8,8 @@ #include "libslic3r/Print.hpp" #include "libslic3r/TriangleMesh.hpp" +#include "test_utils.hpp" + #include #include #include @@ -500,6 +502,52 @@ TEST_CASE("Re-applying an unchanged config after slicing keeps the result valid" REQUIRE(print.is_step_done(psSlicingFinished)); } +TEST_CASE("A degenerate process variant map on a custom multi-extruder printer slices to a stable result", "[Print][Regression]") +{ + // Non-BBL multi-extruder printers get machine-scope variant columns synthesized on preset + // load (extend_extruder_variant), but nothing ships process-scope print_extruder_id / + // print_extruder_variant: presets and 3mf project configs carry the length-1 defaults. The + // apply-time expansion must synthesize the process columns from extruder_variant_list; + // otherwise the failed per-extruder lookups collapse the per-extruder retract overrides + // during slicing and the post-slice re-apply invalidates every fresh result, forever. + DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); + config.set_num_extruders(5); + config.option("nozzle_diameter", true)->values = {0.4, 0.4, 0.4, 0.4, 0.4}; + // per-extruder machine values that a first-slot collapse would destroy + config.option("retract_before_wipe", true)->values = {100., 70., 70., 70., 100.}; + config.option("z_hop_types", true)->values = {zhtSlope, zhtNormal, zhtNormal, zhtNormal, zhtSlope}; + // filament presets carry the nullable override twins (all-nil = "no override"); they are what + // routes the machine values through apply_override in the in-slice override recompute + config.option("filament_retract_before_wipe", true)->values = + std::vector(5, ConfigOptionPercentsNullable::nil_value()); + config.option("filament_z_hop_types", true)->values = + std::vector(5, ConfigOptionEnumsGenericNullable::nil_value()); + config.option("filament_diameter", true)->values = std::vector(5, 1.75); + config.option("filament_colour", true)->values = {"#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#00FFFF"}; + config.option("filament_map", true)->values = {1, 2, 3, 4, 1}; + + Model model; + model.add_object("cube", "", make_cube(20, 20, 20))->add_instance()->set_offset(Vec3d(100., 100., 0.)); + + Print print; + print.apply(model, config); + print.process(); + REQUIRE(print.is_step_done(psSlicingFinished)); + + // BackgroundSlicingProcess reads the engine-computed maps back into the plate config after + // slicing; the next apply overlays that written-back state. + config.option("filament_map", true)->values = print.get_filament_maps(); + config.option("filament_volume_map", true)->values = print.get_filament_volume_maps(); + config.option("filament_nozzle_map", true)->values = print.get_filament_nozzle_maps(); + + auto status = print.apply(model, config); + REQUIRE(status == PrintBase::APPLY_STATUS_UNCHANGED); + REQUIRE(print.is_step_done(psSlicingFinished)); + // the per-extruder machine values must survive the in-slice override recompute + REQUIRE(print.config().retract_before_wipe.values == std::vector({100., 70., 70., 70., 100.})); + REQUIRE(print.config().z_hop_types.values == std::vector({zhtSlope, zhtNormal, zhtNormal, zhtNormal, zhtSlope})); +} + TEST_CASE("normalize_nozzle_map_per_layer makes per-filament assignments gap-free", "[MultiNozzle][H2C][Dynamic]") { SECTION("gaps inherit the last used nozzle, entries on used layers stay untouched") { @@ -662,10 +710,9 @@ TEST_CASE("Sequential selector prints publish a stitched result and cache the pl REQUIRE(print.config().filament_self_index.values.size() >= print.config().filament_map.values.size()); // Export must consume the cached plans and produce g-code without throwing. - boost::filesystem::path gcode_path = boost::filesystem::temp_directory_path() / "orca_seq_dynamic_publish_test.gcode"; - REQUIRE_NOTHROW(print.export_gcode(gcode_path.string(), nullptr, nullptr)); - REQUIRE(boost::filesystem::exists(gcode_path)); - boost::filesystem::remove(gcode_path); + ScopedTemporaryFile gcode(".gcode"); + REQUIRE_NOTHROW(print.export_gcode(gcode.string(), nullptr, nullptr)); + REQUIRE(boost::filesystem::exists(gcode.path())); } TEST_CASE("Per-variant expansion gives migrating filaments one slot per variant", "[PrintConfig][H2C][Dynamic]") diff --git a/tests/slic3rutils/plugin_test_utils.hpp b/tests/slic3rutils/plugin_test_utils.hpp index 52e503f6f4..d60b3441c8 100644 --- a/tests/slic3rutils/plugin_test_utils.hpp +++ b/tests/slic3rutils/plugin_test_utils.hpp @@ -6,6 +6,8 @@ #include +#include "test_utils.hpp" + namespace Slic3r { // Point data_dir() at a throwaway directory for the lifetime of a test and @@ -13,24 +15,20 @@ namespace Slic3r { // disposable tree and tests don't leak state into each other. struct ScopedDataDir { + ScopedTemporaryDir tmp; // owns the temp dir (create + recursive remove) + boost::filesystem::path dir; // = tmp.path(); kept as a member for callers std::string previous; - boost::filesystem::path dir; explicit ScopedDataDir(const std::string& tag) + : tmp("orca-" + tag), dir(tmp.path()), previous(data_dir()) { - namespace fs = boost::filesystem; - previous = data_dir(); - dir = fs::temp_directory_path() / fs::unique_path("orca-" + tag + "-%%%%-%%%%"); - fs::create_directories(dir); set_data_dir(dir.string()); } - ~ScopedDataDir() - { - set_data_dir(previous); - boost::system::error_code ec; - boost::filesystem::remove_all(dir, ec); - } + ~ScopedDataDir() { set_data_dir(previous); } // tmp removes the directory + + // The plugin manager scans {data_dir}/orca_plugins. + boost::filesystem::path plugins_dir() const { return dir / "orca_plugins"; } ScopedDataDir(const ScopedDataDir&) = delete; ScopedDataDir& operator=(const ScopedDataDir&) = delete; diff --git a/tests/slic3rutils/test_network_versions.cpp b/tests/slic3rutils/test_network_versions.cpp index efe8b5d831..349082a965 100644 --- a/tests/slic3rutils/test_network_versions.cpp +++ b/tests/slic3rutils/test_network_versions.cpp @@ -6,6 +6,8 @@ #include "libslic3r/Utils.hpp" #include "slic3r/Utils/bambu_networking.hpp" +#include "plugin_test_utils.hpp" + using namespace Slic3r; namespace fs = boost::filesystem; @@ -25,27 +27,16 @@ static const char* PLUGIN_EXT = ".so"; struct PluginFolderFixture { - fs::path root; - std::string previous_data_dir; + ScopedDataDir data{"netver"}; PluginFolderFixture() { - previous_data_dir = data_dir(); - root = fs::temp_directory_path() / fs::unique_path("orca-netver-%%%%%%%%"); - fs::create_directories(root / "plugins"); - set_data_dir(root.string()); - } - - ~PluginFolderFixture() - { - set_data_dir(previous_data_dir); - boost::system::error_code ec; - fs::remove_all(root, ec); + fs::create_directories(data.dir / "plugins"); } void add_plugin(const std::string& version) { - boost::nowide::ofstream f((root / "plugins" / (PLUGIN_PREFIX + version + PLUGIN_EXT)).string()); + boost::nowide::ofstream f((data.dir / "plugins" / (PLUGIN_PREFIX + version + PLUGIN_EXT)).string()); f << "stub"; } }; diff --git a/tests/slic3rutils/test_plugin_cloud_metadata.cpp b/tests/slic3rutils/test_plugin_cloud_metadata.cpp index ec8b61dea9..c34b596ee0 100644 --- a/tests/slic3rutils/test_plugin_cloud_metadata.cpp +++ b/tests/slic3rutils/test_plugin_cloud_metadata.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -48,6 +49,18 @@ const char* const CLOUD_PLUGIN_SOURCE = R"PY(# /// script # version = "1.0" # /// print('ok') + +import orca +class stubscript(orca.script.ScriptPluginCapabilityBase): + def get_name(self): + return "stubscript" + def execute(self): + return orca.ExecutionResult.success("Stub orca script.") + +@orca.plugin +class stubpackage(orca.base): + def register_capabilities(self): + orca.register_capability(stubscript) )PY"; } // namespace @@ -152,4 +165,31 @@ TEST_CASE("cloud metadata refresh preserves a plugin's stored config", "[PluginC reloaded.load(); REQUIRE(reloaded.has_config(id)); CHECK(reloaded.get_config(id)->config == configured); + + // A local package can remain after the cloud subscription disappears. The cloud identity is + // retained for diagnosis, but the orphaned state must suppress update availability until the + // plugin is returned by a later cloud refresh. + PluginDescriptor orphaned_record = cloud_record; + orphaned_record.cloud->orphaned = true; + orphaned_record.cloud->update_available = true; + manager.update_cloud_metadata({orphaned_record}); + + const PluginDescriptor orphaned = find_by_uuid(); + REQUIRE(orphaned.cloud.has_value()); + CHECK(orphaned.cloud->orphaned); + CHECK_FALSE(orphaned.has_error()); + CHECK(orphaned.get_update_status() == PluginUpdateStatus::Normal); + + // Orphaned is informational only: the local package must remain loadable and usable. + std::string load_error; + manager.load_plugin(uuid, /*skip_deps=*/true); + REQUIRE(manager.wait_for_plugin_load(uuid, std::chrono::seconds(120), load_error)); + INFO("load error: " << load_error); + CHECK(load_error.empty()); + CHECK(manager.is_plugin_loaded(uuid)); + CHECK(manager.unload_plugin(uuid)); + + // Seeing the plugin in a subsequent cloud response clears the orphaned marker. + manager.update_cloud_metadata({cloud_record}); + CHECK_FALSE(find_by_uuid().cloud->orphaned); } diff --git a/tests/slic3rutils/test_plugin_lifecycle.cpp b/tests/slic3rutils/test_plugin_lifecycle.cpp index c49471de28..63a4e6827b 100644 --- a/tests/slic3rutils/test_plugin_lifecycle.cpp +++ b/tests/slic3rutils/test_plugin_lifecycle.cpp @@ -6,6 +6,8 @@ #include #include +#include "plugin_test_utils.hpp" + #include #include @@ -25,32 +27,6 @@ namespace fs = boost::filesystem; namespace { -// Point data_dir() at a throwaway directory for the lifetime of a test and restore the previous -// value afterwards, so discovery scans a disposable {data_dir}/orca_plugins tree and tests don't -// leak state into each other. -struct ScopedDataDir -{ - std::string previous; - fs::path dir; - - explicit ScopedDataDir(const std::string& tag) - { - previous = data_dir(); - dir = fs::temp_directory_path() / fs::unique_path("orca-" + tag + "-%%%%-%%%%"); - fs::create_directories(dir); - set_data_dir(dir.string()); - } - - ~ScopedDataDir() - { - set_data_dir(previous); - boost::system::error_code ec; - fs::remove_all(dir, ec); - } - - fs::path plugins_dir() const { return dir / "orca_plugins"; } -}; - // Brings the plugin system up, and tears it down explicitly at the end of the test. // // Shutting the interpreter down here, rather than leaving it to PythonInterpreter's static diff --git a/tests/slic3rutils/test_slicing_pipeline_bindings.cpp b/tests/slic3rutils/test_slicing_pipeline_bindings.cpp index 8f00b6f31b..5e819c09e0 100644 --- a/tests/slic3rutils/test_slicing_pipeline_bindings.cpp +++ b/tests/slic3rutils/test_slicing_pipeline_bindings.cpp @@ -16,6 +16,8 @@ TEST_CASE("SlicingPipeline capability-type string maps round-trip", "[slicing_pi #include "libslic3r/Point.hpp" #include "libslic3r/ExPolygon.hpp" #include "libslic3r/Surface.hpp" + +#include "test_utils.hpp" #include "libslic3r/Layer.hpp" #include "libslic3r/ExtrusionEntity.hpp" #include "libslic3r/ExtrusionEntityCollection.hpp" @@ -142,7 +144,7 @@ TEST_CASE("orca.slicing psGCodePostProcess context: file edit in place + config import_orca_module(); py::gil_scoped_acquire gil; - const fs::path gpath = fs::temp_directory_path() / fs::unique_path("orca_pp_%%%%-%%%%.gcode"); + ScopedTemporaryFile gpath(".gcode"); { boost::nowide::ofstream ofs(gpath.string()); ofs << "; header\nG1 X0 Y0\n"; @@ -196,9 +198,7 @@ _pp_result = Stamp().execute(_pp_ctx) boost::nowide::ifstream ifs(gpath.string()); std::stringstream ss; ss << ifs.rdbuf(); contents = ss.str(); } - CHECK(contents.find("; stamped by File") != std::string::npos); - fs::remove(gpath); -} + CHECK(contents.find("; stamped by File") != std::string::npos);} // --------------------------------------------------------------------------- // Toolpath helpers for the raw-graph tests. diff --git a/tests/test_utils.hpp b/tests/test_utils.hpp index d928f2f41e..97e684fd6e 100644 --- a/tests/test_utils.hpp +++ b/tests/test_utils.hpp @@ -27,26 +27,47 @@ inline Slic3r::TriangleMesh load_model(const std::string &obj_filename) return mesh; } -// RAII holder for a unique temporary file path, removed when the guard goes out -// of scope so a failing assertion never leaks it. Uses the system temp dir with -// a unique name (parallel-safe, cross-platform). The file itself is created by -// whoever writes to path()/string(); this only reserves the name and cleans up. -class ScopedTemporaryFile +// --------------------------------------------------------------------------- +// Scoped temporary paths +// --------------------------------------------------------------------------- + +// Owns a unique path under the system temp dir, "-[]" +// (parallel-safe, cross-platform). Shared base for the two RAII temp guards below. +class ScopedTemporaryPath +{ +public: + const boost::filesystem::path &path() const { return m_path; } + std::string string() const { return m_path.string(); } + ScopedTemporaryPath(const ScopedTemporaryPath &) = delete; + ScopedTemporaryPath &operator=(const ScopedTemporaryPath &) = delete; + +protected: + ScopedTemporaryPath(const std::string &prefix, const std::string &extension) + : m_path(boost::filesystem::temp_directory_path() + / boost::filesystem::unique_path(prefix + "-%%%%-%%%%-%%%%" + extension)) + {} + ~ScopedTemporaryPath() = default; // non-virtual: never deleted through a base pointer + + boost::filesystem::path m_path; +}; + +// A temp file the caller creates by writing to path()/string(); the guard only +// reserves the name and removes the file on scope exit. +class ScopedTemporaryFile : public ScopedTemporaryPath { public: explicit ScopedTemporaryFile(const std::string &extension = ".tmp") - : m_path(boost::filesystem::temp_directory_path() - / boost::filesystem::unique_path("orca-%%%%-%%%%-%%%%" + extension)) - {} + : ScopedTemporaryPath("orca", extension) {} ~ScopedTemporaryFile() { boost::system::error_code ec; boost::filesystem::remove(m_path, ec); } - ScopedTemporaryFile(const ScopedTemporaryFile &) = delete; - ScopedTemporaryFile &operator=(const ScopedTemporaryFile &) = delete; +}; - const boost::filesystem::path &path() const { return m_path; } - std::string string() const { return m_path.string(); } - -private: - boost::filesystem::path m_path; +// A temp directory created on construction and removed recursively on scope exit. +class ScopedTemporaryDir : public ScopedTemporaryPath +{ +public: + explicit ScopedTemporaryDir(const std::string &prefix = "orca") + : ScopedTemporaryPath(prefix, "") { boost::filesystem::create_directories(m_path); } + ~ScopedTemporaryDir() { boost::system::error_code ec; boost::filesystem::remove_all(m_path, ec); } }; // --------------------------------------------------------------------------- @@ -66,7 +87,7 @@ inline std::string debug_artifact_path(const std::string &name) boost::filesystem::path dir = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("orca-test-artifacts-%%%%-%%%%"); boost::filesystem::create_directories(dir); - std::printf("Debug test artifacts will be written to %s\n", dir.string().c_str()); + std::fprintf(stderr, "Debug test artifacts will be written to %s\n", dir.string().c_str()); return dir; }(); boost::filesystem::path full = root / name; @@ -75,57 +96,52 @@ inline std::string debug_artifact_path(const std::string &name) } // Dump a mesh as OBJ. -inline void write_debug_obj(const std::string &name, const Slic3r::TriangleMesh &mesh) +inline void write_debug_obj([[maybe_unused]] const std::string &name, + [[maybe_unused]] const Slic3r::TriangleMesh &mesh) { #ifndef NDEBUG mesh.WriteOBJFile(debug_artifact_path(name).c_str()); -#else - (void) name; (void) mesh; #endif } -inline void write_debug_obj(const std::string &name, const indexed_triangle_set &its) +inline void write_debug_obj([[maybe_unused]] const std::string &name, + [[maybe_unused]] const indexed_triangle_set &its) { #ifndef NDEBUG its_write_obj(its, debug_artifact_path(name).c_str()); -#else - (void) name; (void) its; #endif } // Dump a mesh as ASCII STL. -inline void write_debug_stl(const std::string &name, const Slic3r::TriangleMesh &mesh) +inline void write_debug_stl([[maybe_unused]] const std::string &name, + [[maybe_unused]] const Slic3r::TriangleMesh &mesh) { #ifndef NDEBUG mesh.write_ascii(debug_artifact_path(name).c_str()); -#else - (void) name; (void) mesh; #endif } // Draw an SVG artifact through a callback that receives the open SVG. Second // overload takes a BoundingBox when the drawing needs one. template -inline void write_debug_svg(const std::string &name, Draw &&draw) +inline void write_debug_svg([[maybe_unused]] const std::string &name, [[maybe_unused]] Draw &&draw) { #ifndef NDEBUG Slic3r::SVG svg(debug_artifact_path(name)); draw(svg); svg.Close(); -#else - (void) name; (void) draw; #endif } template -inline void write_debug_svg(const std::string &name, const Slic3r::BoundingBox &bbox, Draw &&draw) +inline void write_debug_svg([[maybe_unused]] const std::string &name, + [[maybe_unused]] const Slic3r::BoundingBox &bbox, + [[maybe_unused]] Draw &&draw) { #ifndef NDEBUG Slic3r::SVG svg(debug_artifact_path(name), bbox); draw(svg); svg.Close(); -#else - (void) name; (void) bbox; (void) draw; #endif } @@ -133,13 +149,11 @@ inline void write_debug_svg(const std::string &name, const Slic3r::BoundingBox & // artifact. operator<< is resolved by ADL at the call site, so this header needn't // include the producer's headers. template -inline void write_debug_stream(const std::string &name, Produce &&produce) +inline void write_debug_stream([[maybe_unused]] const std::string &name, [[maybe_unused]] Produce &&produce) { #ifndef NDEBUG std::ofstream out(debug_artifact_path(name), std::ios::out | std::ios::binary); out << produce(); -#else - (void) name; (void) produce; #endif } From f6f68573b63c44a456cf78ea617903c37b657aa8 Mon Sep 17 00:00:00 2001 From: Ian Chua Date: Fri, 14 Aug 2026 14:48:57 +0800 Subject: [PATCH 06/51] fix: add resources folder to the allowed roots as readonly --- src/slic3r/plugin/PluginAuditManager.cpp | 178 ++++++++++++++++++++--- src/slic3r/plugin/PluginAuditManager.hpp | 52 ++++++- tests/slic3rutils/plugin_test_utils.hpp | 20 +++ tests/slic3rutils/test_plugin_audit.cpp | 146 +++++++++++++++++++ 4 files changed, 365 insertions(+), 31 deletions(-) diff --git a/src/slic3r/plugin/PluginAuditManager.cpp b/src/slic3r/plugin/PluginAuditManager.cpp index 023e55bd22..4d69a4f761 100644 --- a/src/slic3r/plugin/PluginAuditManager.cpp +++ b/src/slic3r/plugin/PluginAuditManager.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -111,6 +112,22 @@ static AuditEventCategory event_category(const std::string& event_name) return it == audit_event_categories.end() ? AuditEventCategory::None : it->second; } +// True for the categories whose targets are filesystem paths, as opposed to a network +// address or a process command line -- the deny-path and allowed-root checks only make sense +// against a path. +static bool is_fs_category(AuditEventCategory category) +{ + switch (category) { + case AuditEventCategory::FsRead: + case AuditEventCategory::FsReadWrite: + case AuditEventCategory::FsCreate: + case AuditEventCategory::FsDelete: + return true; + default: + return false; + } +} + // --------------------------------------------------------------------------- // Path safety // --------------------------------------------------------------------------- @@ -179,7 +196,7 @@ bool is_inside_allowed_root(const boost::filesystem::path& candidate, const boos thread_local std::string PluginAuditManager::m_current_plugin_key = ""; thread_local std::string PluginAuditManager::m_current_capability_name = ""; -thread_local std::vector PluginAuditManager::m_scoped_allowed_roots; +thread_local std::vector PluginAuditManager::m_scoped_allowed_roots; thread_local bool PluginAuditManager::m_audit_denial_pending = false; thread_local bool PluginAuditManager::m_has_last_violation = false; thread_local AuditViolation PluginAuditManager::m_last_violation; @@ -224,23 +241,24 @@ std::string PluginAuditManager::current_capability() const { return m_current_ca void PluginAuditManager::clear_current_capability() { m_current_capability_name.clear(); } -void PluginAuditManager::add_global_allowed_root(const boost::filesystem::path& root) +void PluginAuditManager::add_global_allowed_root(const boost::filesystem::path& root, bool allow_write) { if (root.empty()) return; std::lock_guard lock(m_mutex); - m_global_allowed_roots.push_back(root); - BOOST_LOG_TRIVIAL(info) << "[AUDIT] Global allowed root: " << root.string(); + m_global_allowed_roots.push_back({root, allow_write}); + BOOST_LOG_TRIVIAL(info) << "[AUDIT] Global allowed root: " << root.string() << " allow_write=" << allow_write; } -void PluginAuditManager::add_scoped_allowed_root(const boost::filesystem::path& root) +void PluginAuditManager::add_scoped_allowed_root(const boost::filesystem::path& root, bool allow_write) { if (root.empty()) return; - m_scoped_allowed_roots.push_back(root); - BOOST_LOG_TRIVIAL(info) << "[AUDIT] Scoped allowed root for plugin " << current_plugin() << ": " << root.string(); + m_scoped_allowed_roots.push_back({root, allow_write}); + BOOST_LOG_TRIVIAL(info) << "[AUDIT] Scoped allowed root for plugin " << current_plugin() << ": " << root.string() + << " allow_write=" << allow_write; } // --------------------------------------------------------------------------- @@ -293,6 +311,67 @@ bool PluginAuditManager::is_denied_filename(const boost::filesystem::path& candi return false; } +// --------------------------------------------------------------------------- +// Denied path keywords +// --------------------------------------------------------------------------- + +void PluginAuditManager::add_denied_path_keyword(const std::string& keyword) +{ + if (keyword.empty()) + return; + + std::string lower = keyword; + std::transform(lower.begin(), lower.end(), lower.begin(), [](unsigned char c) { return std::tolower(c); }); + + std::lock_guard lock(m_mutex); + m_denied_path_keywords.push_back(lower); + BOOST_LOG_TRIVIAL(info) << "[AUDIT] Denied path keyword: " << lower; +} + +std::vector PluginAuditManager::default_denied_path_keywords() +{ + // Broad, categorical rules on top of the exact-name is_denied_filename registry: a plugin + // must never be able to reach a secret, a certificate, or a configuration file just because + // it happens to live inside an otherwise-allowed root (e.g. the bundled TLS client cert at + // resources_dir()/cert/..., which would become reachable the moment resources_dir() is + // granted as a read-only allowed root). + return {"secret", "cert", "conf"}; +} + +bool PluginAuditManager::is_denied_path_keyword(const boost::filesystem::path& candidate) const +{ + namespace fs = boost::filesystem; + + boost::system::error_code ec; + fs::path canon = fs::weakly_canonical(candidate, ec); + if (ec) { + canon = fs::absolute(candidate, ec).lexically_normal(); + if (ec) + canon = candidate; + } + + std::lock_guard lock(m_mutex); + if (m_denied_path_keywords.empty()) + return false; + + for (const auto& component : canon) { + std::string name = component.string(); + if (name.empty()) + continue; + std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) { return std::tolower(c); }); + for (const auto& keyword : m_denied_path_keywords) { + if (name.find(keyword) != std::string::npos) + return true; + } + } + return false; +} + +bool PluginAuditManager::is_denied_path(const boost::filesystem::path& candidate) const +{ + return is_denied_filename(candidate) || is_denied_path_keyword(candidate); +} + // --------------------------------------------------------------------------- // Policy checks // --------------------------------------------------------------------------- @@ -306,14 +385,20 @@ AuditDecision PluginAuditManager::check_path_access(const boost::filesystem::pat if (plugin_key.empty()) return {true, ""}; // not running inside a plugin context - // Denied filenames are checked before the allowed roots. The app config and the cloud - // refresh token live directly inside data_dir(), which is a global allowed root, so a deny - // placed any lower would be unreachable. + // Denied filenames/keywords are checked before the allowed roots. The app config and the + // cloud refresh token live directly inside data_dir(), which is a global allowed root, and + // the bundled TLS client cert lives inside resources_dir(), a read-only global allowed + // root, so a deny placed any lower would be unreachable. if (is_denied_filename(path)) { BOOST_LOG_TRIVIAL(warning) << "[AUDIT] block path=" << path.string() << " is_write=" << is_write << " plugin=" << plugin_key << " reason=denied filename"; return {false, "denied filename"}; } + if (is_denied_path_keyword(path)) { + BOOST_LOG_TRIVIAL(warning) << "[AUDIT] block path=" << path.string() << " is_write=" << is_write + << " plugin=" << plugin_key << " reason=denied path keyword"; + return {false, "denied path keyword"}; + } namespace fs = boost::filesystem; fs::path candidate = path; @@ -326,8 +411,11 @@ AuditDecision PluginAuditManager::check_path_access(const boost::filesystem::pat candidate = absolute_candidate; } + // A root that doesn't allow writes only matches a read-shaped request; a write/create/ + // delete-shaped one falls through to "outside allowed root" for that root even though the + // path is physically inside it. for (const auto& root : m_scoped_allowed_roots) { - if (is_inside_allowed_root(candidate, root)) { + if ((!is_write || root.allow_write) && is_inside_allowed_root(candidate, root.path)) { return {true, ""}; } } @@ -335,7 +423,7 @@ AuditDecision PluginAuditManager::check_path_access(const boost::filesystem::pat { std::lock_guard lock(m_mutex); for (const auto& root : m_global_allowed_roots) { - if (is_inside_allowed_root(candidate, root)) { + if ((!is_write || root.allow_write) && is_inside_allowed_root(candidate, root.path)) { return {true, ""}; } } @@ -799,6 +887,27 @@ int PluginAuditManager::audit_hook(const char* event, PyObject* args, void* user return 0; } + // the open function can take in different flags that determine if it is a read or readwrite. + const AuditEventCategory event_type = + event_name == "open" ? PluginAuditDetail::open_category(args) : event_category(event_name); + if (event_type == AuditEventCategory::None) + return 0; + + const bool fs_category = is_fs_category(event_type); + const std::vector targets = PluginAuditDetail::audit_targets(event_name, event_type, args); + + // A denied path (secrets, certificates, config files -- see is_denied_path) is an + // unconditional block: checked before the ancestor-cascade check below, so a cascade + // approval recorded for an unrelated action can never launder access to one, and before + // the allowed-root shortcut further down, so an allowed root (e.g. the read-only resources + // folder) cannot make a denied path underneath it reachable. + if (fs_category) { + for (const auto& target : targets) { + if (mgr->is_denied_path(boost::filesystem::path(target))) + return PluginAuditDetail::report_denied(*mgr, event_name, {false, "denied path"}); + } + } + PluginDescriptor plugin_descriptor; PluginManager::instance().try_get_plugin_descriptor(mgr->current_plugin(), plugin_descriptor); @@ -809,11 +918,20 @@ int PluginAuditManager::audit_hook(const char* event, PyObject* args, void* user if (mgr->has_approved_ancestor(mgr->current_plugin(), call_site_ids)) return 0; - // the open function can take in different flags that determine if it is a read or readwrite. - const AuditEventCategory event_type = - event_name == "open" ? PluginAuditDetail::open_category(args) : event_category(event_name); - if (event_type == AuditEventCategory::None) - return 0; + // A filesystem target that resolves entirely inside a pre-determined allowed root -- the + // plugin system's own data_dir() tree (which holds each plugin's storage folder and the + // installed/system profile cache), the read-only bundled resources folder, or a per-call + // scoped root such as the current G-code folder -- is part of the plugin system's normal + // workflow and does not need a prompt. + if (fs_category && !targets.empty()) { + const bool is_write = event_type != AuditEventCategory::FsRead; + const bool all_inside_allowed_root = + std::all_of(targets.begin(), targets.end(), [&](const std::string& target) { + return mgr->check_path_access(boost::filesystem::path(target), is_write).allowed; + }); + if (all_inside_allowed_root) + return 0; + } PluginInstallState state; const bool have_install_state = PluginManager::instance().get_install_state(mgr->current_plugin(), state); @@ -823,8 +941,7 @@ int PluginAuditManager::audit_hook(const char* event, PyObject* args, void* user const std::string plugin_name = state.plugin_name.empty() ? mgr->current_plugin() : state.plugin_name; - const std::vector targets = PluginAuditDetail::audit_targets(event_name, event_type, args); - std::vector* permission_list = PluginAuditDetail::permission_list_for(event_type, state.permissions); + std::vector* permission_list = PluginAuditDetail::permission_list_for(event_type, state.permissions); return PluginAuditDetail::decide_audited_event(*mgr, state, mgr->current_plugin(), plugin_name, event_name, event_type, targets, permission_list, call_site_ids); @@ -832,12 +949,20 @@ int PluginAuditManager::audit_hook(const char* event, PyObject* args, void* user void PluginAuditManager::install_hook() { - // data_dir() is the only globally-allowed root during plugin execution. - // The executable directory and resources directory are intentionally NOT allowed - // here: plugins must not access outside data_dir() (G-code plugins additionally get - // the temp G-code folder via a scoped root). + // data_dir() is the primary globally-allowed root during plugin execution: read+write. It + // covers the plugin system's own workflow needs -- each plugin's storage folder + // (data_dir()/orca_plugins) and the installed/system profile cache (data_dir()/system) -- + // without a separate, narrower grant for either (G-code plugins additionally get the temp + // G-code folder via a scoped root, see SlicingPipelinePluginCapabilityTrampoline). add_global_allowed_root(data_dir()); + // resources_dir() holds the app's bundled, shared assets (installed system profiles, the + // bundled TLS client cert, web assets). Plugins may read from it -- e.g. inspecting bundled + // profiles -- but must never write into the shared, potentially multi-user app install, so + // it is granted read-only. The bundled cert itself stays unreachable regardless, via the + // "cert" denied-path keyword seeded below. + add_global_allowed_root(resources_dir(), /*allow_write=*/false); + // The user's app config and cloud credentials live directly inside data_dir(), so the // root just granted would otherwise expose them to any plugin. Deny them by name. // @@ -850,6 +975,13 @@ void PluginAuditManager::install_hook() for (const auto& name : default_denied_filenames()) add_denied_filename(name); + // Categorical denies on top of the exact-name list above: no path a plugin can reach may + // contain a "secret", "cert"(ificate), or "conf"(ig) path component, regardless of which + // allowed root it happens to sit inside. default_denied_path_keywords() is the single + // source of this list; the tests seed from it too. + for (const auto& keyword : default_denied_path_keywords()) + add_denied_path_keyword(keyword); + if (PySys_AddAuditHook(audit_hook, this) < 0) { BOOST_LOG_TRIVIAL(error) << "[AUDIT] Failed to install CPython audit hook"; return; diff --git a/src/slic3r/plugin/PluginAuditManager.hpp b/src/slic3r/plugin/PluginAuditManager.hpp index 3b86014d42..d6751a57fd 100644 --- a/src/slic3r/plugin/PluginAuditManager.hpp +++ b/src/slic3r/plugin/PluginAuditManager.hpp @@ -24,6 +24,14 @@ struct AuditViolation { std::string reason; }; +// A filesystem root a plugin may access while an audit context is active. allow_write is +// false for a root that only grants reads (e.g. the bundled, shared resources folder) -- +// a write-shaped event never matches such a root, even though a read-shaped one does. +struct AllowedRoot { + boost::filesystem::path path; + bool allow_write = true; +}; + // The set of CPython audit events PluginAuditManager recognizes, grouped by the kind of // operation they represent. None means the event isn't one audit_hook() acts on at all. enum class AuditEventCategory { @@ -65,8 +73,11 @@ public: void clear_current_capability(); // --- allowed-roots registry --- - void add_global_allowed_root(const boost::filesystem::path& root); - void add_scoped_allowed_root(const boost::filesystem::path& root); + // allow_write = false registers a read-only root: a read-shaped event inside it is allowed, + // but a write/create/delete-shaped event is not, so it falls through to the normal + // prompt-or-deny path instead. + void add_global_allowed_root(const boost::filesystem::path& root, bool allow_write = true); + void add_scoped_allowed_root(const boost::filesystem::path& root, bool allow_write = true); // --- denied-filenames registry --- // Filenames a plugin may never touch, in any directory, regardless of the enclosing allowed @@ -89,10 +100,34 @@ public: // 8.3 short name is out of scope (see the design doc). This blocks direct access only. bool is_denied_filename(const boost::filesystem::path& candidate) const; + // --- denied-path-keyword registry --- + // Keywords that categorically deny a path if ANY of its components (directory or file + // name), not just the base name, contains one case-insensitively -- e.g. a "secrets" + // subfolder, a "certificates" folder, or a "conf"/"config" file anywhere the plugin can + // otherwise reach, including inside an allowed root. This is intentionally broader and + // fuzzier than the exact-name is_denied_filename registry: it exists to categorically rule + // out whole classes of sensitive paths (secrets, certificates, config) rather than name + // specific known files, at the cost of over-blocking an unrelated name that happens to + // contain the keyword -- the fail-safe direction, same rationale as is_denied_filename. + void add_denied_path_keyword(const std::string& keyword); + + // The list install_hook() seeds into the keyword registry. Exposed so tests seed the exact + // same set without a live interpreter. + static std::vector default_denied_path_keywords(); + + // True when any component of candidate's (canonicalized) path contains a registered + // keyword, case-insensitively. + bool is_denied_path_keyword(const boost::filesystem::path& candidate) const; + + // is_denied_filename(candidate) || is_denied_path_keyword(candidate). Convenience for + // call sites that only need to know whether a path is categorically off-limits, not which + // specific rule fired. + bool is_denied_path(const boost::filesystem::path& candidate) const; + // --- policy checks --- - // Shared core for every audited filesystem event. The deny list is consulted above the - // allowed roots, so a denied filename is blocked even when the file sits inside data_dir(), - // which is itself a global allowed root. + // Shared core for every audited filesystem event. The deny checks are consulted above the + // allowed roots, so a denied path is blocked even when it sits inside an allowed root (e.g. + // data_dir(), which is a global allowed root). AuditDecision check_path_access(const boost::filesystem::path& candidate, bool is_write); AuditDecision check_open(const std::string& path, const std::string& mode); @@ -130,15 +165,16 @@ private: static thread_local std::string m_current_plugin_key; static thread_local std::string m_current_capability_name; - static thread_local std::vector m_scoped_allowed_roots; + static thread_local std::vector m_scoped_allowed_roots; static thread_local bool m_audit_denial_pending; static thread_local bool m_has_last_violation; static thread_local AuditViolation m_last_violation; // mutable: is_denied_filename() and has_approved_ancestor() are const queries that must lock. mutable std::mutex m_mutex; - std::vector m_global_allowed_roots; + std::vector m_global_allowed_roots; std::vector m_denied_filenames; + std::vector m_denied_path_keywords; std::unordered_map> m_approved_call_sites; // plugin_key -> call-site ids }; @@ -160,7 +196,7 @@ public: private: std::string m_previous_id; std::string m_previous_capability; - std::vector m_previous_scoped_roots; + std::vector m_previous_scoped_roots; }; } // namespace Slic3r diff --git a/tests/slic3rutils/plugin_test_utils.hpp b/tests/slic3rutils/plugin_test_utils.hpp index d60b3441c8..cbdcf1ff95 100644 --- a/tests/slic3rutils/plugin_test_utils.hpp +++ b/tests/slic3rutils/plugin_test_utils.hpp @@ -34,4 +34,24 @@ struct ScopedDataDir ScopedDataDir& operator=(const ScopedDataDir&) = delete; }; +// Point resources_dir() at a throwaway directory for the lifetime of a test and restore the +// previous value afterwards, mirroring ScopedDataDir. +struct ScopedResourcesDir +{ + ScopedTemporaryDir tmp; + boost::filesystem::path dir; + std::string previous; + + explicit ScopedResourcesDir(const std::string& tag) + : tmp("orca-" + tag), dir(tmp.path()), previous(resources_dir()) + { + set_resources_dir(dir.string()); + } + + ~ScopedResourcesDir() { set_resources_dir(previous); } + + ScopedResourcesDir(const ScopedResourcesDir&) = delete; + ScopedResourcesDir& operator=(const ScopedResourcesDir&) = delete; +}; + } // namespace Slic3r diff --git a/tests/slic3rutils/test_plugin_audit.cpp b/tests/slic3rutils/test_plugin_audit.cpp index 20fc2b86e7..71ce692671 100644 --- a/tests/slic3rutils/test_plugin_audit.cpp +++ b/tests/slic3rutils/test_plugin_audit.cpp @@ -27,6 +27,16 @@ void seed_denied_names() mgr.add_denied_filename(name); } +// Seed the keyword registry with the same list install_hook() uses. Same rationale as +// seed_denied_names(): a process-singleton registry, seeded from the single shared source so +// production and tests cannot drift apart. +void seed_denied_keywords() +{ + PluginAuditManager& mgr = PluginAuditManager::instance(); + for (const auto& keyword : PluginAuditManager::default_denied_path_keywords()) + mgr.add_denied_path_keyword(keyword); +} + } // namespace TEST_CASE("Plugin audit denies app config and token filenames anywhere", "[audit]") @@ -190,3 +200,139 @@ TEST_CASE("Plugin audit does not constrain non-plugin code", "[audit]") CHECK(mgr.check_open(conf.string(), "w").allowed); CHECK(mgr.check_open(conf.string(), "r").allowed); } + +TEST_CASE("Plugin audit denies secret/certificate/config-like paths by keyword", "[audit]") +{ + seed_denied_keywords(); + const PluginAuditManager& mgr = PluginAuditManager::instance(); + + SECTION("a 'secrets' directory component is denied") + { + CHECK(mgr.is_denied_path_keyword(fs::path("/plugin/secrets/api_key.json"))); + CHECK(mgr.is_denied_path_keyword(fs::path("/plugin/secret/token.txt"))); + } + + SECTION("a 'certificate(s)' directory component is denied") + { + CHECK(mgr.is_denied_path_keyword(fs::path("/resources/cert/slicer_base64.cer"))); + CHECK(mgr.is_denied_path_keyword(fs::path("/resources/certificates/ca.pem"))); + } + + SECTION("a 'conf'/'config' directory or file component is denied") + { + CHECK(mgr.is_denied_path_keyword(fs::path("/plugin/conf/settings.json"))); + CHECK(mgr.is_denied_path_keyword(fs::path("/plugin/config/settings.json"))); + CHECK(mgr.is_denied_path_keyword(fs::path("/plugin/plugin.conf"))); + } + + SECTION("matching is case-insensitive") + { + CHECK(mgr.is_denied_path_keyword(fs::path("/plugin/SECRETS/token.txt"))); + CHECK(mgr.is_denied_path_keyword(fs::path("/resources/CertBundle/ca.pem"))); + CHECK(mgr.is_denied_path_keyword(fs::path("/plugin/CONFIG.JSON"))); + } + + SECTION("matching is not limited to the base name -- any ancestor component counts") + { + CHECK(mgr.is_denied_path_keyword(fs::path("/data/secrets/nested/deep/file.txt"))); + } + + SECTION("an unrelated path is not denied") + { + CHECK_FALSE(mgr.is_denied_path_keyword(fs::path("/plugin/output/model.gcode"))); + CHECK_FALSE(mgr.is_denied_path_keyword(fs::path("/plugin/storage/state.json"))); + } + + SECTION("an empty path is not denied") + { + CHECK_FALSE(mgr.is_denied_path_keyword(fs::path())); + } +} + +TEST_CASE("Plugin audit is_denied_path combines the filename and keyword registries", "[audit]") +{ + seed_denied_names(); + seed_denied_keywords(); + const PluginAuditManager& mgr = PluginAuditManager::instance(); + + SECTION("a filename-registry match is denied") + { + CHECK(mgr.is_denied_path(fs::path(SLIC3R_APP_KEY ".conf"))); + } + + SECTION("a keyword-registry match is denied") + { + CHECK(mgr.is_denied_path(fs::path("/plugin/secrets/token.txt"))); + } + + SECTION("a path matching neither registry is not denied") + { + CHECK_FALSE(mgr.is_denied_path(fs::path("/plugin/output/model.gcode"))); + } +} + +TEST_CASE("Plugin audit a read-only allowed root blocks writes but not reads", "[audit]") +{ + ScopedDataDir data_dir_guard("plugin-audit-readonly"); + ScopedResourcesDir resources_dir_guard("plugin-audit-readonly-resources"); + seed_denied_names(); + seed_denied_keywords(); + + PluginAuditManager& mgr = PluginAuditManager::instance(); + mgr.add_global_allowed_root(resources_dir(), /*allow_write=*/false); + + ScopedPluginAuditContext ctx("test_plugin", ""); + + const fs::path readonly_file = fs::path(resources_dir()) / "profiles" / "vendor.json"; + + SECTION("a read inside the read-only root is allowed") + { + CHECK(mgr.check_open(readonly_file.string(), "r").allowed); + } + + SECTION("a write inside the read-only root is blocked") + { + AuditDecision decision = mgr.check_open(readonly_file.string(), "w"); + CHECK_FALSE(decision.allowed); + CHECK(decision.reason == "outside allowed root"); + } + + SECTION("a create inside the read-only root is blocked") + { + AuditDecision decision = mgr.check_path_access(readonly_file, /*is_write=*/true); + CHECK_FALSE(decision.allowed); + } + + SECTION("the bundled cert underneath the read-only root is denied even for reads") + { + const fs::path cert = fs::path(resources_dir()) / "cert" / "slicer_base64.cer"; + AuditDecision decision = mgr.check_open(cert.string(), "r"); + CHECK_FALSE(decision.allowed); + CHECK(decision.reason == "denied path keyword"); + } +} + +TEST_CASE("Plugin audit a scoped root can also be registered read-only", "[audit]") +{ + ScopedDataDir data_dir_guard("plugin-audit-scoped-readonly"); + seed_denied_names(); + seed_denied_keywords(); + + PluginAuditManager& mgr = PluginAuditManager::instance(); + + const fs::path readonly_dir = fs::path(data_dir()) / "readonly_scope"; + fs::create_directories(readonly_dir); + + ScopedPluginAuditContext ctx("test_plugin", ""); + mgr.add_scoped_allowed_root(readonly_dir, /*allow_write=*/false); + + SECTION("a read inside the scoped read-only root is allowed") + { + CHECK(mgr.check_open((readonly_dir / "vendor.json").string(), "r").allowed); + } + + SECTION("a write inside the scoped read-only root is blocked") + { + CHECK_FALSE(mgr.check_open((readonly_dir / "vendor.json").string(), "w").allowed); + } +} From 83a00843a01fac0cbd2e083fd32549bf87ea4b50 Mon Sep 17 00:00:00 2001 From: Ian Chua Date: Wed, 19 Aug 2026 14:13:56 +0800 Subject: [PATCH 07/51] fix: revoke plugin permissions on install/update --- src/slic3r/plugin/PluginManager.cpp | 26 ++++++++++++++++++++++++++ src/slic3r/plugin/PluginManager.hpp | 2 ++ 2 files changed, 28 insertions(+) diff --git a/src/slic3r/plugin/PluginManager.cpp b/src/slic3r/plugin/PluginManager.cpp index d84f629112..16acfe0eee 100644 --- a/src/slic3r/plugin/PluginManager.cpp +++ b/src/slic3r/plugin/PluginManager.cpp @@ -1145,6 +1145,26 @@ void PluginManager::mark_plugin_install_state_disabled(const std::string& plugin plugin->descriptor.enabled = false; } +void PluginManager::revoke_plugin_permissions(const std::string& plugin_key) +{ + std::lock_guard state_lock(m_install_state_mutex); + + PluginDescriptor descriptor; + if (!try_get_plugin_descriptor(plugin_key, descriptor) || descriptor.plugin_root.empty()) + return; + + const boost::filesystem::path root(descriptor.plugin_root); + PluginInstallState state; + if (!read_install_state(root, state)) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": Failed to read install state for " << plugin_key; + return; + } + + state.permissions = {}; + if (!write_install_state(root, state)) + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": Failed to revoke permissions for " << plugin_key; +} + // ── Callbacks ─────────────────────────────────────────────────────────────────────────────── void PluginManager::subscribe_on_load_callback(PluginLifecycleCompleteFn fn) @@ -1364,6 +1384,11 @@ bool PluginManager::install_plugin(const boost::filesystem::path& filepath, Plug return false; } + // Every successful install may have replaced executable plugin code. Revoke any permissions + // associated with the previous package so the newly installed version must request them again. + if (!plugin_descriptor.plugin_key.empty()) + revoke_plugin_permissions(plugin_descriptor.plugin_key); + if (!plugin_descriptor.plugin_key.empty()) clear_plugin_error(plugin_descriptor.plugin_key); @@ -1751,6 +1776,7 @@ bool PluginManager::update_cloud_plugin(const std::string& plugin_key, std::stri } clear_plugin_error(plugin_key); + return true; } diff --git a/src/slic3r/plugin/PluginManager.hpp b/src/slic3r/plugin/PluginManager.hpp index 26a02c09ec..f23c552e25 100644 --- a/src/slic3r/plugin/PluginManager.hpp +++ b/src/slic3r/plugin/PluginManager.hpp @@ -254,6 +254,8 @@ private: // Writes the sidecar for a loaded plugin (enabled=true plus the current per-capability flags). void write_loaded_plugin_install_state(const std::string& plugin_key); void mark_plugin_install_state_disabled(const std::string& plugin_key); + // Revoke permissions after a package replacement so the new package must request them again. + void revoke_plugin_permissions(const std::string& plugin_key); bool finalize_cloud_plugin_removal(const PluginDescriptor& plugin, bool keep_local, std::string& error); bool delete_installed_plugin_package(const PluginDescriptor& plugin, std::string& error); From 1e392e4437eef5271275b2e842312de7db43f98a Mon Sep 17 00:00:00 2001 From: Ian Chua Date: Tue, 25 Aug 2026 14:38:51 +0800 Subject: [PATCH 08/51] fix: remove audit scope from plugin pages --- .../pluginTypes/pages/PagesPluginCapabilityTrampoline.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapabilityTrampoline.hpp b/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapabilityTrampoline.hpp index 3fb476c228..f6e13c981b 100644 --- a/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapabilityTrampoline.hpp +++ b/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapabilityTrampoline.hpp @@ -16,7 +16,6 @@ public: std::string get_icon() override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE, std::string, @@ -27,7 +26,6 @@ public: std::string get_ui() override { ORCA_PY_OVERRIDE_AUDITED( - ::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE_PURE, std::string, @@ -42,7 +40,7 @@ public: if (!gil) throw std::runtime_error("Python interpreter is shutting down"); - ORCA_PY_AUDIT_SCOPE(::Slic3r::PluginAuditManager::AuditMode::Loading); + ORCA_PY_AUDIT_SCOPE(); pybind11::function override = pybind11::get_override(static_cast(this), "on_message"); if (!override) From 36740ffdd8106834959830b58c15e4ed7cc55685 Mon Sep 17 00:00:00 2001 From: Kris Austin Date: Mon, 31 Aug 2026 08:55:42 -0500 Subject: [PATCH 09/51] build: clear 53 warnings - discarded values and i18n markers (#15421) build: clear 53 unused value warnings 49 of them are deliberate i18n markers. L(s) expands to s, so L("Main Extruder"); is a string literal as a statement and its value is discarded. The strings have to stay, because the real values come from printers/*.json at runtime and xgettext cannot scan those. Each block is now a static const char *const markers[], which uses the values rather than discarding them. Extraction is unchanged: the xgettext invocation from scripts/run_gettext.bat gives 76 msgids over the two marker files before and after, with identical msgid and msgctxt sets. The other 4 are statements with no effect. AMSItem.cpp:117 and :174 construct and drop a wxColour(255, 255, 255); AMS_TRAY_DEFAULT_COL is that colour, and the line above already assigns it. UpgradePanel.cpp:865 reads a member and drops it. wgtDeviceNozzleSelect.cpp:269 writes if (item; auto ptr = m_nozzle_rack.lock()), which puts the null check in the init-statement position where its value is discarded, so the check never runs, and sGetNozzlePosId then dereferences item. Nothing reaches that today, because the only sender of the event sets itself as the event object and the dynamic_cast always succeeds. The check now runs. --- src/slic3r/GUI/DeviceCore/DevConfigUtil.cpp | 39 ++++++++++--------- .../GUI/DeviceTab/wgtDeviceNozzleSelect.cpp | 2 +- src/slic3r/GUI/UpgradePanel.cpp | 1 - src/slic3r/GUI/Widgets/AMSItem.cpp | 2 - src/slic3r/GUI/Widgets/FanControl.cpp | 18 ++++++--- 5 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/slic3r/GUI/DeviceCore/DevConfigUtil.cpp b/src/slic3r/GUI/DeviceCore/DevConfigUtil.cpp index b86d3cde98..25008cad29 100644 --- a/src/slic3r/GUI/DeviceCore/DevConfigUtil.cpp +++ b/src/slic3r/GUI/DeviceCore/DevConfigUtil.cpp @@ -16,24 +16,27 @@ namespace Slic3r // This block is never executed at runtime. static void _toolhead_translation_markers() { - // Dynamic toolhead display names from JSON config — xgettext cannot scan these - L("Main Extruder"); L("Main extruder"); L("main extruder"); - L("Auxiliary Extruder"); L("Auxiliary extruder"); L("auxiliary extruder"); - L("Left Extruder"); L("Left extruder"); L("left extruder"); - L("Right Extruder"); L("Right extruder"); L("right extruder"); - L("Main Nozzle"); L("Main nozzle"); L("main nozzle"); - L("Auxiliary Nozzle"); L("Auxiliary nozzle"); L("auxiliary nozzle"); - L("Left Nozzle"); L("Left nozzle"); L("left nozzle"); - L("Right Nozzle"); L("Right nozzle"); L("right nozzle"); - L("Main Hotend"); L("Main hotend"); L("main hotend"); - L("Auxiliary Hotend"); L("Auxiliary hotend"); L("auxiliary hotend"); - L("Left Hotend"); L("Left hotend"); L("left hotend"); - L("Right Hotend"); L("Right hotend"); L("right hotend"); - // standalone position words (short_name=true runtime results) - L("main"); L("auxiliary"); - L("Main"); L("Auxiliary"); - L("left"); L("right"); - L("Left"); L("Right"); + // Possible runtime values of tool_head_display_names, marked for extraction. + static const char *const markers[] = { + L("Main Extruder"), L("Main extruder"), L("main extruder"), + L("Auxiliary Extruder"), L("Auxiliary extruder"), L("auxiliary extruder"), + L("Left Extruder"), L("Left extruder"), L("left extruder"), + L("Right Extruder"), L("Right extruder"), L("right extruder"), + L("Main Nozzle"), L("Main nozzle"), L("main nozzle"), + L("Auxiliary Nozzle"), L("Auxiliary nozzle"), L("auxiliary nozzle"), + L("Left Nozzle"), L("Left nozzle"), L("left nozzle"), + L("Right Nozzle"), L("Right nozzle"), L("right nozzle"), + L("Main Hotend"), L("Main hotend"), L("main hotend"), + L("Auxiliary Hotend"), L("Auxiliary hotend"), L("auxiliary hotend"), + L("Left Hotend"), L("Left hotend"), L("left hotend"), + L("Right Hotend"), L("Right hotend"), L("right hotend"), + // standalone position words (short_name=true runtime results) + L("main"), L("auxiliary"), + L("Main"), L("Auxiliary"), + L("left"), L("right"), + L("Left"), L("Right"), + }; + (void) markers; } std::string DevPrinterConfigUtil::m_resource_file_path = ""; diff --git a/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleSelect.cpp b/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleSelect.cpp index c383815f8c..4dc072d721 100644 --- a/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleSelect.cpp +++ b/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleSelect.cpp @@ -266,7 +266,7 @@ void wgtDeviceNozzleRackSelect::OnNozzleItemSelected(wxCommandEvent &evt) } auto *item = dynamic_cast(evt.GetEventObject()); - if (item; auto ptr = m_nozzle_rack.lock()) { + if (auto ptr = m_nozzle_rack.lock(); item && ptr) { int to_select_pos_id = sGetNozzlePosId(item, m_toolhead_nozzle_l, m_toolhead_nozzle_r); if (to_select_pos_id > -1 && to_select_pos_id != GetSelectedNozzlePosID()) { SetSelectedNozzle(ptr->GetNozzleSystem()->GetNozzleByPosId(to_select_pos_id)); diff --git a/src/slic3r/GUI/UpgradePanel.cpp b/src/slic3r/GUI/UpgradePanel.cpp index 96b9c1b481..d31fde8613 100644 --- a/src/slic3r/GUI/UpgradePanel.cpp +++ b/src/slic3r/GUI/UpgradePanel.cpp @@ -862,7 +862,6 @@ void MachineInfoPanel::update_ams_ext(MachineObject *obj) if (new_extra_ams_ver != obj->new_ver_list.end()) has_new_version = true; - extra_ams_it->second.sw_new_ver; if (has_new_version) { m_extra_ams_panel->m_ams_new_version_img->Show(); ver_text = new_extra_ams_ver->second.sw_ver; diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index f99e5f49fd..9d5ec9c1c1 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -114,7 +114,6 @@ bool AMSinfo::parse_ams_info(MachineObject *obj, DevAms *ams, bool remain_flag, info.ctype = 0; info.material_colour = AMS_TRAY_DEFAULT_COL; info.material_state = AMSCanType::AMS_CAN_TYPE_THIRDBRAND; - wxColour(255, 255, 255); } if (it->second->is_tray_info_ready() && obj->cali_version >= 0) { @@ -171,7 +170,6 @@ void AMSinfo::parse_ext_info(MachineObject* obj, DevAmsTray tray) { info.filament_id = ""; info.ctype = 0; info.material_colour = AMS_TRAY_DEFAULT_COL; - wxColour(255, 255, 255); } info.material_state = AMSCanType::AMS_CAN_TYPE_VIRTUAL; if (tray.is_tray_info_ready() && obj->cali_version >= 0) { diff --git a/src/slic3r/GUI/Widgets/FanControl.cpp b/src/slic3r/GUI/Widgets/FanControl.cpp index 057baca430..f10553814e 100644 --- a/src/slic3r/GUI/Widgets/FanControl.cpp +++ b/src/slic3r/GUI/Widgets/FanControl.cpp @@ -1014,8 +1014,12 @@ void FanControlPopupNew::init_names(MachineObject* obj) { if (obj) { const std::string& special_cooling_text = DevPrinterConfigUtil::get_fan_text(obj->printer_type, "special_cooling_text"); if (!special_cooling_text.empty()) { - L("Cooling mode is suitable for printing PLA/PETG/TPU materials."); //some potential text, add i18n flags - L("Cooling mode is suitable for printing PLA/PETG/TPU materials and filters the chamber air."); + // Possible runtime values of special_cooling_text, marked for extraction. + static const char *const markers[] = { + L("Cooling mode is suitable for printing PLA/PETG/TPU materials."), + L("Cooling mode is suitable for printing PLA/PETG/TPU materials and filters the chamber air."), + }; + (void) markers; label_text[AIR_DUCT::AIR_DUCT_COOLING_FILT] = _L(special_cooling_text); } } @@ -1028,9 +1032,13 @@ wxString FanControlPopupNew::get_fan_func_name(int mode, int submode, AIR_FUN fu const std::string& func_text = DevPrinterConfigUtil::get_fan_text(m_obj->printer_type, mode, (int)func, submode); if (!func_text.empty()) { - L_CONTEXT("Right(Aux)", "air_duct"); - L_CONTEXT("Right(Filter)", "air_duct"); - L_CONTEXT("Left(Aux)", "air_duct"); + // Possible runtime values of func_text, marked for extraction. + static const char *const markers[] = { + L_CONTEXT("Right(Aux)", "air_duct"), + L_CONTEXT("Right(Filter)", "air_duct"), + L_CONTEXT("Left(Aux)", "air_duct"), + }; + (void) markers; return _L_CONTEXT(func_text, "air_duct"); } } From fcf6f0a3a54ba28b31e814103eaaa35dea4a7394 Mon Sep 17 00:00:00 2001 From: Kris Austin Date: Mon, 31 Aug 2026 14:36:52 -0500 Subject: [PATCH 10/51] build: clear 54 warnings - dead private fields (#15423) build: clear 54 dead private fields 54 of the 161 -Wunused-private-field warnings, across 31 files. These are the ones needing no judgment. Each member is declared once and appears nowhere else in src/, counting the .mm and .c sources as well as .cpp and .hpp, so nothing writes them and nothing reads them. Every removal is a whole line, and no declaration shares a line with another member. The remaining 107 are left alone. Those members are mentioned elsewhere, usually assigned and never read, where the fix might be deleting the member or might be restoring a read that went missing. --- src/libslic3r/GCodeWriter.hpp | 1 - src/slic3r/GUI/AMSDryControl.hpp | 1 - src/slic3r/GUI/AboutDialog.hpp | 1 - src/slic3r/GUI/BBLTopbar.hpp | 1 - src/slic3r/GUI/CreatePresetsDialog.hpp | 2 -- src/slic3r/GUI/DeviceTab/uiAMSBestPositionPopup.hpp | 1 - src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRackUpdate.h | 2 -- src/slic3r/GUI/GCodeViewer.hpp | 1 - src/slic3r/GUI/GLToolbar.hpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 1 - src/slic3r/GUI/IMSlider.hpp | 5 ----- src/slic3r/GUI/MediaFilePanel.h | 1 - src/slic3r/GUI/Monitor.hpp | 4 ---- src/slic3r/GUI/MultiMachineManagerPage.hpp | 1 - src/slic3r/GUI/ObjColorDialog.hpp | 1 - src/slic3r/GUI/PartSkipDialog.hpp | 1 - src/slic3r/GUI/PhysicalPrinterDialog.hpp | 1 - src/slic3r/GUI/Project.hpp | 1 - src/slic3r/GUI/RecenterDialog.hpp | 2 -- src/slic3r/GUI/SelectMachinePop.hpp | 2 -- src/slic3r/GUI/SendMultiMachinePage.hpp | 1 - src/slic3r/GUI/SendToPrinter.hpp | 2 -- src/slic3r/GUI/SkipPartCanvas.hpp | 1 - src/slic3r/GUI/SyncAmsInfoDialog.hpp | 3 --- src/slic3r/GUI/Tab.hpp | 2 -- src/slic3r/GUI/ThermalPreconditioningDialog.hpp | 1 - src/slic3r/GUI/WebGuideDialog.hpp | 1 - src/slic3r/GUI/WebViewDialog.hpp | 4 ---- src/slic3r/GUI/Widgets/AMSItem.hpp | 6 ------ src/slic3r/GUI/Widgets/FanControl.hpp | 1 - src/slic3r/GUI/Widgets/MultiNozzleSync.hpp | 1 - 31 files changed, 54 deletions(-) diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index fcb63c3e96..8247ab757a 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -165,7 +165,6 @@ public: //BBS - unsigned int m_last_additional_fan_speed; int m_last_bed_temperature; bool m_last_bed_temperature_reached; double m_lifted; diff --git a/src/slic3r/GUI/AMSDryControl.hpp b/src/slic3r/GUI/AMSDryControl.hpp index a7500b5b03..46699650d6 100644 --- a/src/slic3r/GUI/AMSDryControl.hpp +++ b/src/slic3r/GUI/AMSDryControl.hpp @@ -55,7 +55,6 @@ private: Label* m_text_label; wxStaticBitmap* m_icon_bitmap; - int m_target_size; std::string m_icon_name; ScalableBitmap m_icon; }; diff --git a/src/slic3r/GUI/AboutDialog.hpp b/src/slic3r/GUI/AboutDialog.hpp index 8dc72d15a3..e96c74ba08 100644 --- a/src/slic3r/GUI/AboutDialog.hpp +++ b/src/slic3r/GUI/AboutDialog.hpp @@ -60,7 +60,6 @@ class AboutDialog : public DPIDialog wxHtmlWindow* m_html; wxStaticBitmap* m_logo; int m_copy_rights_btn_id { wxID_ANY }; - int m_copy_version_btn_id { wxID_ANY }; public: AboutDialog(); diff --git a/src/slic3r/GUI/BBLTopbar.hpp b/src/slic3r/GUI/BBLTopbar.hpp index 465126944b..e60a95f64f 100644 --- a/src/slic3r/GUI/BBLTopbar.hpp +++ b/src/slic3r/GUI/BBLTopbar.hpp @@ -93,7 +93,6 @@ private: CenteredTitle* m_title_ctrl { nullptr }; wxString m_titleText; - wxAuiToolBarItem* m_account_item; wxAuiToolBarItem* m_model_store_item; //wxAuiToolBarItem *m_publish_item; diff --git a/src/slic3r/GUI/CreatePresetsDialog.hpp b/src/slic3r/GUI/CreatePresetsDialog.hpp index 678f4d40fd..701779b1bf 100644 --- a/src/slic3r/GUI/CreatePresetsDialog.hpp +++ b/src/slic3r/GUI/CreatePresetsDialog.hpp @@ -74,12 +74,10 @@ private: std::unordered_set m_system_filament_types_set; std::set m_visible_printers; CreateType m_create_type; - Button * m_button_create = nullptr; Button * m_button_cancel = nullptr; ComboBox * m_filament_vendor_combobox = nullptr; ::CheckBox * m_can_not_find_vendor_checkbox = nullptr; ComboBox * m_filament_type_combobox = nullptr; - ComboBox * m_exist_vendor_combobox = nullptr; ComboBox * m_filament_preset_combobox = nullptr; TextInput * m_filament_custom_vendor_input = nullptr; wxGridSizer * m_filament_presets_sizer = nullptr; diff --git a/src/slic3r/GUI/DeviceTab/uiAMSBestPositionPopup.hpp b/src/slic3r/GUI/DeviceTab/uiAMSBestPositionPopup.hpp index 18dd3c4301..be8f957c94 100644 --- a/src/slic3r/GUI/DeviceTab/uiAMSBestPositionPopup.hpp +++ b/src/slic3r/GUI/DeviceTab/uiAMSBestPositionPopup.hpp @@ -199,7 +199,6 @@ private: void OnRefreshButton(wxCommandEvent& event); private: - int saveTimes{0}; wxBoxSizer* mainSizer{nullptr}; wxPanel* textPanel{nullptr}; wxBoxSizer* textSizer{nullptr}; diff --git a/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRackUpdate.h b/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRackUpdate.h index 8275638831..06b950cd7e 100644 --- a/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRackUpdate.h +++ b/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRackUpdate.h @@ -122,7 +122,6 @@ private: private: int m_ext_nozzle_id = -1; int m_rack_nozzle_id = -1; - bool m_isRefreshFinish = false; bool findNozzleImage = false; NozzleStatus m_nozzle_status = NOZZLE_STATUS_DC; @@ -154,7 +153,6 @@ private: Label* m_diameter_label; Label* m_flowtype_label; Label* m_type_label; - ScalableButton* m_error_button{ nullptr }; Label* m_sn_label; Label* m_version_label; diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index a19f7bb9ae..5ba748775c 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -72,7 +72,6 @@ public: float m_model_z_offset{ 0.5f }; bool m_visible{ true }; bool m_is_dark = false; - bool m_fixed_screen_size{ false }; float m_scale_factor{ 1.0f }; #if ENABLE_ACTUAL_SPEED_DEBUG ActualSpeedImguiWidget m_actual_speed_imgui_widget; diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp index 85413edc66..c4bc88045e 100644 --- a/src/slic3r/GUI/GLToolbar.hpp +++ b/src/slic3r/GUI/GLToolbar.hpp @@ -327,7 +327,6 @@ private: GLTexture m_icons_texture; bool m_icons_texture_dirty; mutable GLTexture m_images_texture; - mutable bool m_images_texture_dirty; BackgroundTexture m_background_texture; GLTexture m_arrow_texture; Layout m_layout; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index f42d327a0e..57a6cc1981 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -86,7 +86,6 @@ private: boost::thread m_thread; // Mutex and condition variable to synchronize m_thread with the UI thread. std::mutex m_mutex; - int m_generate_count; // This map holds all translated description texts, so they can be easily referenced during layout calculations // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. diff --git a/src/slic3r/GUI/IMSlider.hpp b/src/slic3r/GUI/IMSlider.hpp index bd2399e990..45e4d6ccb8 100644 --- a/src/slic3r/GUI/IMSlider.hpp +++ b/src/slic3r/GUI/IMSlider.hpp @@ -176,7 +176,6 @@ private: // Use those values to disable selection of active extruders bool m_is_dark = false; - bool is_osx{false}; int m_min_value; int m_max_value; int m_lower_value; @@ -201,10 +200,6 @@ private: void *m_one_layer_on_hover_id; void *m_one_layer_off_id; void *m_one_layer_off_hover_id; - void* m_one_layer_on_light_id; - void* m_one_layer_on_hover_light_id; - void* m_one_layer_off_light_id; - void* m_one_layer_off_hover_light_id; void* m_one_layer_on_dark_id; void* m_one_layer_on_hover_dark_id; void* m_one_layer_off_dark_id; diff --git a/src/slic3r/GUI/MediaFilePanel.h b/src/slic3r/GUI/MediaFilePanel.h index 72fbc96a13..36696d2225 100644 --- a/src/slic3r/GUI/MediaFilePanel.h +++ b/src/slic3r/GUI/MediaFilePanel.h @@ -61,7 +61,6 @@ private: ::Button *m_button_year = nullptr; ::Button *m_button_month = nullptr; ::Button *m_button_all = nullptr; - ::Label *m_switch_label = nullptr; ::StaticBox * m_type_panel = nullptr; ::Button * m_button_video = nullptr; diff --git a/src/slic3r/GUI/Monitor.hpp b/src/slic3r/GUI/Monitor.hpp index fe115a351a..13688d6526 100644 --- a/src/slic3r/GUI/Monitor.hpp +++ b/src/slic3r/GUI/Monitor.hpp @@ -86,11 +86,8 @@ private: /* side tools */ SideTools* m_side_tools{nullptr}; - wxStaticBitmap* m_bitmap_printer_type; wxStaticBitmap* m_bitmap_arrow; - wxStaticText* m_staticText_printer_name; wxStaticBitmap* m_bitmap_wifi_signal; - wxBoxSizer * m_side_tools_sizer; SelectMachinePopup m_select_machine; /* images */ @@ -101,7 +98,6 @@ private: wxBitmap m_printer_img; wxBitmap m_arrow_img; - int last_wifi_signal = -1; int last_status; bool m_initialized { false }; bool update_flag{false}; diff --git a/src/slic3r/GUI/MultiMachineManagerPage.hpp b/src/slic3r/GUI/MultiMachineManagerPage.hpp index 7bb12ffc75..2576e36f12 100644 --- a/src/slic3r/GUI/MultiMachineManagerPage.hpp +++ b/src/slic3r/GUI/MultiMachineManagerPage.hpp @@ -88,7 +88,6 @@ private: Button* m_task_name{ nullptr }; Button* m_status{ nullptr }; Button* m_action{ nullptr }; - Button* m_stop_all_botton{nullptr}; // tip when no device wxStaticText* m_tip_text{ nullptr }; diff --git a/src/slic3r/GUI/ObjColorDialog.hpp b/src/slic3r/GUI/ObjColorDialog.hpp index 1ad74cdccd..19ed1dcb24 100644 --- a/src/slic3r/GUI/ObjColorDialog.hpp +++ b/src/slic3r/GUI/ObjColorDialog.hpp @@ -79,7 +79,6 @@ private: std::vector m_row_col_boxsizer_list; std::vector m_result_icon_list; int m_last_cluster_num{-1}; - const int m_combox_width{50}; int m_combox_icon_width; int m_combox_icon_height; wxButton * m_image_button = nullptr; diff --git a/src/slic3r/GUI/PartSkipDialog.hpp b/src/slic3r/GUI/PartSkipDialog.hpp index 95eba9f24d..b95681dcde 100644 --- a/src/slic3r/GUI/PartSkipDialog.hpp +++ b/src/slic3r/GUI/PartSkipDialog.hpp @@ -128,7 +128,6 @@ private: bool is_drag_mode(); boost::shared_ptr m_file_sys; - bool m_file_sys_result{false}; std::string m_timestamp; std::string m_tmp_path; std::vector m_local_paths; diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.hpp b/src/slic3r/GUI/PhysicalPrinterDialog.hpp index 0ba2cad54f..c32da334be 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.hpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.hpp @@ -33,7 +33,6 @@ class PhysicalPrinterDialog : public DPIDialog Button* m_printhost_test_btn {nullptr}; Button* m_printhost_logout_btn {nullptr}; Button* m_printhost_cafile_browse_btn {nullptr}; - Button* m_printhost_client_cert_browse_btn {nullptr}; Button* m_printhost_port_browse_btn {nullptr}; RoundedRectangle* m_input_area {nullptr}; diff --git a/src/slic3r/GUI/Project.hpp b/src/slic3r/GUI/Project.hpp index a41f76ba7e..a590212cb7 100644 --- a/src/slic3r/GUI/Project.hpp +++ b/src/slic3r/GUI/Project.hpp @@ -63,7 +63,6 @@ class ProjectPanel : public wxPanel { private: std::atomic m_web_init_completed{false}; - bool m_reload_already = {false}; std::shared_ptr> m_reload_cancel_token{std::make_shared>(false)}; std::unique_ptr m_reload_task; diff --git a/src/slic3r/GUI/RecenterDialog.hpp b/src/slic3r/GUI/RecenterDialog.hpp index 1e48e7990b..cd7511d3f5 100644 --- a/src/slic3r/GUI/RecenterDialog.hpp +++ b/src/slic3r/GUI/RecenterDialog.hpp @@ -10,8 +10,6 @@ namespace Slic3r { namespace GUI { class RecenterDialog : public DPIDialog { private: - wxStaticText* m_staticText_hint; - wxStaticBitmap* m_bitmap_home; ScalableBitmap m_home_bmp; wxString hint1; wxString hint2; diff --git a/src/slic3r/GUI/SelectMachinePop.hpp b/src/slic3r/GUI/SelectMachinePop.hpp index 757cb08ed5..764ffd6af5 100644 --- a/src/slic3r/GUI/SelectMachinePop.hpp +++ b/src/slic3r/GUI/SelectMachinePop.hpp @@ -181,8 +181,6 @@ private: PinCodePanel* m_panel_direct_connection{nullptr}; wxWindow* m_placeholder_panel{nullptr}; HyperLink* m_hyperlink{nullptr}; // ORCA - Label* m_ping_code_text{nullptr}; - wxStaticBitmap* m_img_ping_code{nullptr}; wxBoxSizer * m_sizer_body{nullptr}; wxBoxSizer * m_sizer_my_devices{nullptr}; wxBoxSizer * m_sizer_other_devices{nullptr}; diff --git a/src/slic3r/GUI/SendMultiMachinePage.hpp b/src/slic3r/GUI/SendMultiMachinePage.hpp index a531e01262..7d77849bf3 100644 --- a/src/slic3r/GUI/SendMultiMachinePage.hpp +++ b/src/slic3r/GUI/SendMultiMachinePage.hpp @@ -149,7 +149,6 @@ private: ScalableBitmap* print_time{ nullptr }; wxStaticBitmap* weightimg{ nullptr }; ScalableBitmap* print_weight{ nullptr }; - wxBoxSizer* m_thumbnail_sizer{ nullptr }; ThumbnailPanel* m_thumbnail_panel{nullptr}; wxPanel* m_panel_image{ nullptr }; wxBoxSizer* m_image_sizer{ nullptr }; diff --git a/src/slic3r/GUI/SendToPrinter.hpp b/src/slic3r/GUI/SendToPrinter.hpp index 87948b28c3..93215c4e06 100644 --- a/src/slic3r/GUI/SendToPrinter.hpp +++ b/src/slic3r/GUI/SendToPrinter.hpp @@ -62,7 +62,6 @@ private: bool m_is_in_sending_mode{ false }; bool m_is_rename_mode{ false }; bool enable_prepare_mode{ true }; - bool m_need_adaptation_screen{ false }; bool m_export_3mf_cancel{ false }; bool m_is_canceled{ false }; bool m_tcp_try_connect{true}; @@ -81,7 +80,6 @@ private: wxStaticBitmap* m_staticbitmap{ nullptr }; ThumbnailPanel* m_thumbnailPanel{ nullptr }; ComboBox* m_comboBox_printer{ nullptr }; - ComboBox* m_comboBox_bed{ nullptr }; Button* m_rename_button{ nullptr }; Button* m_button_refresh{ nullptr }; Button* m_button_ensure{ nullptr }; diff --git a/src/slic3r/GUI/SkipPartCanvas.hpp b/src/slic3r/GUI/SkipPartCanvas.hpp index a9c8f1fec7..d70ad3718f 100644 --- a/src/slic3r/GUI/SkipPartCanvas.hpp +++ b/src/slic3r/GUI/SkipPartCanvas.hpp @@ -87,7 +87,6 @@ private: std::unordered_map < uint32_t, std::vector>> parts_triangles_; std::unordered_map < uint32_t, std::vector>> pick_parts_; std::unordered_map parts_state_; - bool gl_inited_{false}; int zoom_percent_{100}; wxPoint offset_{0,0}; wxPoint drag_start_offset_{0,0}; diff --git a/src/slic3r/GUI/SyncAmsInfoDialog.hpp b/src/slic3r/GUI/SyncAmsInfoDialog.hpp index 248ca4032c..b0868f8c58 100644 --- a/src/slic3r/GUI/SyncAmsInfoDialog.hpp +++ b/src/slic3r/GUI/SyncAmsInfoDialog.hpp @@ -307,8 +307,6 @@ private: // wxBoxSizer * m_plate_combox_sizer = nullptr; wxBoxSizer * m_mode_combox_sizer = nullptr; //wxStaticText * m_printer_title = nullptr; - wxStaticText * m_printer_device_name = nullptr; - wxStaticText * m_printer_is_map_title = nullptr; CapsuleButton * m_colormap_btn = nullptr; CapsuleButton * m_override_btn = nullptr; @@ -326,7 +324,6 @@ private: bool m_check_dirty_fialment = true; bool m_expand_more_settings = true; - bool m_image_is_top = false; const int LEFT_THUMBNAIL_SIZE_WIDTH = 100; const int RIGHT_THUMBNAIL_SIZE_WIDTH = 300; diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index c6041ba1ea..5069b76417 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -626,8 +626,6 @@ private: bool m_rebuild_kinematics_page = false; void update_input_shaper_menu(GCodeFlavor flavor); - ogStaticText* m_fff_print_host_upload_description_line {nullptr}; - ogStaticText* m_sla_print_host_upload_description_line {nullptr}; std::vector m_pages_fff; std::vector m_pages_sla; diff --git a/src/slic3r/GUI/ThermalPreconditioningDialog.hpp b/src/slic3r/GUI/ThermalPreconditioningDialog.hpp index d13a1d19f5..57cda90b18 100644 --- a/src/slic3r/GUI/ThermalPreconditioningDialog.hpp +++ b/src/slic3r/GUI/ThermalPreconditioningDialog.hpp @@ -31,7 +31,6 @@ private: wxStaticText *m_remaining_time_label; wxStaticText *m_explanation_label; wxButton *m_ok_button; - wxStaticBitmap *m_title_bitmap; DECLARE_EVENT_TABLE() }; diff --git a/src/slic3r/GUI/WebGuideDialog.hpp b/src/slic3r/GUI/WebGuideDialog.hpp index b9592d03fe..c4cfc8bf6d 100644 --- a/src/slic3r/GUI/WebGuideDialog.hpp +++ b/src/slic3r/GUI/WebGuideDialog.hpp @@ -112,7 +112,6 @@ private: AppConfig m_appconfig_new; wxWebView *m_browser; - wxButton * m_TestBtn; wxString m_SectionName; diff --git a/src/slic3r/GUI/WebViewDialog.hpp b/src/slic3r/GUI/WebViewDialog.hpp index 23b3c711a1..123025ef85 100644 --- a/src/slic3r/GUI/WebViewDialog.hpp +++ b/src/slic3r/GUI/WebViewDialog.hpp @@ -125,10 +125,6 @@ private: wxMenuItem* m_edit_undo; wxMenuItem* m_edit_redo; wxMenuItem* m_edit_mode; - wxMenuItem* m_scroll_line_up; - wxMenuItem* m_scroll_line_down; - wxMenuItem* m_scroll_page_up; - wxMenuItem* m_scroll_page_down; wxMenuItem* m_script_string; wxMenuItem* m_script_integer; wxMenuItem* m_script_double; diff --git a/src/slic3r/GUI/Widgets/AMSItem.hpp b/src/slic3r/GUI/Widgets/AMSItem.hpp index d7dc26a741..c43c71f580 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.hpp +++ b/src/slic3r/GUI/Widgets/AMSItem.hpp @@ -684,7 +684,6 @@ public: private: int m_nozzle_num = {1}; - AMSRoadShowMode m_single_ext_rode_mode = {AMSRoadShowMode::AMS_ROAD_MODE_FOUR}; AMSRoadShowMode m_left_rode_mode = {AMSRoadShowMode::AMS_ROAD_MODE_FOUR}; AMSRoadShowMode m_right_rode_mode = {AMSRoadShowMode::AMS_ROAD_MODE_FOUR}; bool m_selected = {false}; @@ -693,7 +692,6 @@ private: int m_right_road_length = {-1}; int m_passroad_width = {6}; double m_radius = {4}; - AMSPassRoadType m_pass_road_type = {AMSPassRoadType::AMS_ROAD_TYPE_NONE}; AMSPassRoadSTEP m_pass_road_left_step = {AMSPassRoadSTEP::AMS_ROAD_STEP_NONE}; AMSPassRoadSTEP m_pass_road_right_step = {AMSPassRoadSTEP::AMS_ROAD_STEP_NONE}; @@ -866,11 +864,7 @@ private: AMSinfo m_info; wxBoxSizer * sizer_can = {nullptr}; wxGridSizer* sizer_can_extra = { nullptr }; - wxBoxSizer * sizer_humidity = { nullptr }; wxBoxSizer * sizer_item = { nullptr }; - wxBoxSizer * sizer_can_middle = {nullptr}; - wxBoxSizer * sizer_can_left = {nullptr}; - wxBoxSizer * sizer_can_right = {nullptr}; AMSExtImage* m_ext_image = { nullptr }; //the ext image upon the ext ams AMSExtText* m_ext_text = { nullptr }; //the ext text upon the ext ams }; diff --git a/src/slic3r/GUI/Widgets/FanControl.hpp b/src/slic3r/GUI/Widgets/FanControl.hpp index fc29d22000..b13ce19d41 100644 --- a/src/slic3r/GUI/Widgets/FanControl.hpp +++ b/src/slic3r/GUI/Widgets/FanControl.hpp @@ -109,7 +109,6 @@ public: void decrease_fan_speeds(); private: int m_current_speeds; - int m_target_speed; int m_min_speeds; int m_max_speeds; ScalableBitmap m_bitmap_add; diff --git a/src/slic3r/GUI/Widgets/MultiNozzleSync.hpp b/src/slic3r/GUI/Widgets/MultiNozzleSync.hpp index 3af524c2fc..3baea061dc 100644 --- a/src/slic3r/GUI/Widgets/MultiNozzleSync.hpp +++ b/src/slic3r/GUI/Widgets/MultiNozzleSync.hpp @@ -204,7 +204,6 @@ private: Label* m_caution; wxTimer* m_refresh_timer {nullptr}; - size_t m_rack_event_token; Button* m_cancel_btn; Button* m_confirm_btn; }; From ca903faa56bcfe429ef45806d962d6e15ec7c2d9 Mon Sep 17 00:00:00 2001 From: Leo Lobato Date: Mon, 31 Aug 2026 21:36:55 +0200 Subject: [PATCH 11/51] Fix uninitialized first_layer_time on CLI-sliced 3MF (#13429) PartPlate::store_to_3mf_structure read first_layer_time from the indirect cali_bboxes_data struct, which the GUI populates at Plater.cpp:10600 but the CLI never writes to. The result was uninitialized memory leaking into slice_info.config Read directly from get_slice_result()->initial_layer_time, which is populated by GCodeProcessor::finalize() in both code paths and matches the pattern already used a few lines above for gcode_prediction. Also default-initialize PlateBBoxData::first_layer_time to 0.0f as a defense against any other consumer reading it without an explicit write. --- src/libslic3r/GCode/ThumbnailData.hpp | 2 +- src/slic3r/GUI/PartPlate.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/GCode/ThumbnailData.hpp b/src/libslic3r/GCode/ThumbnailData.hpp index 82563d64f2..bc37ad40c4 100644 --- a/src/libslic3r/GCode/ThumbnailData.hpp +++ b/src/libslic3r/GCode/ThumbnailData.hpp @@ -78,7 +78,7 @@ struct PlateBBoxData int first_extruder = 0; float nozzle_diameter = 0.4; std::string bed_type; - float first_layer_time; + float first_layer_time = 0.0f; // version 1: use view type ColorPrint (filament color) // version 2: use view type FilamentId (filament id) int version = 2; diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 7bb3bec12b..59a857816e 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -6470,7 +6470,7 @@ int PartPlateList::store_to_3mf_structure(PlateDataPtrs& plate_data_list, bool w plate_data_item->filament_change_sequence = m_plate_list[i]->m_gcode_result->filament_change_sequence; plate_data_item->nozzle_change_sequence = m_plate_list[i]->m_gcode_result->nozzle_change_sequence; plate_data_item->optimal_assignment = m_plate_list[i]->m_gcode_result->optimal_assignment; - plate_data_item->first_layer_time = std::to_string(m_plate_list[i]->cali_bboxes_data.first_layer_time); + plate_data_item->first_layer_time = std::to_string(m_plate_list[i]->get_slice_result()->initial_layer_time); Print *print = nullptr; m_plate_list[i]->get_print((PrintBase **) &print, nullptr, nullptr); if (print) { From 5436e422b98ccde9148c8be4413935aef8c3b54e Mon Sep 17 00:00:00 2001 From: Kris Austin Date: Mon, 31 Aug 2026 14:59:58 -0500 Subject: [PATCH 12/51] ci: build macOS with 3 parallel jobs instead of 1 (#15393) --- .github/workflows/build_deps.yml | 2 +- .github/workflows/build_orca.yml | 4 ++-- build_release_macos.sh | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build_deps.yml b/.github/workflows/build_deps.yml index 4e01051073..f9e5c57c34 100644 --- a/.github/workflows/build_deps.yml +++ b/.github/workflows/build_deps.yml @@ -151,7 +151,7 @@ jobs: if [ -z "${{ vars.SELF_HOSTED }}" ]; then brew install automake texinfo libtool pkgconf yasm nasm fi - ./build_release_macos.sh -dx ${{ !vars.SELF_HOSTED && '-1' || '' }} -a ${{ inputs.arch }} -t 10.15 + ./build_release_macos.sh -dx ${{ !vars.SELF_HOSTED && '-j 3' || '' }} -a ${{ inputs.arch }} -t 10.15 (cd "${{ github.workspace }}/deps/build/${{ inputs.arch }}" && \ find . -mindepth 1 -maxdepth 1 ! -name 'OrcaSlicer_dep' -exec rm -rf {} +) diff --git a/.github/workflows/build_orca.yml b/.github/workflows/build_orca.yml index e8dcef0b05..c73524d6f0 100644 --- a/.github/workflows/build_orca.yml +++ b/.github/workflows/build_orca.yml @@ -145,7 +145,7 @@ jobs: env: ORCA_TESTS_BUILD_ONLY: ${{ inputs.arch == 'arm64' && '1' || '' }} run: | - ./build_release_macos.sh -s -n -x ${{ !vars.SELF_HOSTED && '-1' || '' }} -a ${{ inputs.arch }} -t 10.15 ${{ inputs.arch == 'arm64' && '-T' || '' }} + ./build_release_macos.sh -s -n -x ${{ !vars.SELF_HOSTED && '-j 3' || '' }} -a ${{ inputs.arch }} -t 10.15 ${{ inputs.arch == 'arm64' && '-T' || '' }} - name: Pack unit tests mac if: runner.os == 'macOS' && !inputs.macos-combine-only && inputs.arch == 'arm64' @@ -204,7 +204,7 @@ jobs: if: runner.os == 'macOS' && inputs.macos-combine-only working-directory: ${{ github.workspace }} run: | - ./build_release_macos.sh -u -x ${{ !vars.SELF_HOSTED && '-1' || '' }} -a universal -t 10.15 + ./build_release_macos.sh -u -x ${{ !vars.SELF_HOSTED && '-j 3' || '' }} -a universal -t 10.15 # Thanks to RaySajuuk, it's working now - name: Sign app and notary diff --git a/build_release_macos.sh b/build_release_macos.sh index 2fd7b26cd8..b1de5df2e4 100755 --- a/build_release_macos.sh +++ b/build_release_macos.sh @@ -4,7 +4,7 @@ set -e set -o pipefail SECONDS=0 -while getopts ":dpa:snt:xbc:i:1Tuh" opt; do +while getopts ":dpa:snt:xbc:i:j:Tuh" opt; do case "${opt}" in d ) export BUILD_TARGET="deps" @@ -38,8 +38,8 @@ while getopts ":dpa:snt:xbc:i:1Tuh" opt; do i ) export CMAKE_IGNORE_PREFIX_PATH="${CMAKE_IGNORE_PREFIX_PATH:+$CMAKE_IGNORE_PREFIX_PATH;}$OPTARG" ;; - 1 ) - export CMAKE_BUILD_PARALLEL_LEVEL=1 + j ) + export CMAKE_BUILD_PARALLEL_LEVEL="$OPTARG" ;; T ) export BUILD_TESTS="1" @@ -58,7 +58,7 @@ while getopts ":dpa:snt:xbc:i:1Tuh" opt; do echo " -b: Build without reconfiguring CMake" echo " -c: Set CMake build configuration, default is Release" echo " -i: Add a prefix to ignore during CMake dependency discovery (repeatable), defaults to /opt/local:/usr/local:/opt/homebrew" - echo " -1: Use single job for building" + echo " -j: Set the number of parallel build jobs (CMAKE_BUILD_PARALLEL_LEVEL)" echo " -T: Build and run tests (set ORCA_TESTS_BUILD_ONLY=1 to build without running)" exit 0 ;; From 9933cab59f7e266af2453ce82a0bbff4e23f23fa Mon Sep 17 00:00:00 2001 From: Kris Austin Date: Mon, 31 Aug 2026 20:19:58 -0500 Subject: [PATCH 13/51] build: drop the pkg-config requirement from the Windows build (#15469) The FFmpeg camera view port made pkg-config a required build tool on Windows. Windows does not ship one, so every Windows developer has to install it before the build will configure: Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE) Call Stack (most recent call first): CMakeLists.txt:480 (find_package) Nothing on Windows needs it. FFmpeg there is a prebuilt zip unpacked into the deps prefix, whose DLLs the top level CMakeLists already names by exact soname. The version is fixed before configure runs, so find_library against that prefix does the job, as on macOS. Also drops the CI step that installed pkg-config, gated on !SELF_HOSTED so it never ran on self-hosted runners, and re-comments the if(WIN32) block that #15234 uncommented only for that find_package. --- .github/workflows/build_orca.yml | 7 ------- CMakeLists.txt | 5 ++--- src/slic3r/CMakeLists.txt | 12 ++++++++++++ 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build_orca.yml b/.github/workflows/build_orca.yml index c73524d6f0..a9efaa7561 100644 --- a/.github/workflows/build_orca.yml +++ b/.github/workflows/build_orca.yml @@ -385,13 +385,6 @@ jobs: dir "C:/Program Files (x86)/Windows Kits/10/Include" choco install nsis - - name: Install pkg-config - # FFmpeg is discovered via pkg-config (pkg_check_modules LIBAV in - # src/slic3r/CMakeLists.txt); the Windows runners don't ship it. - if: runner.os == 'Windows' && !vars.SELF_HOSTED - run: | - choco install pkgconfiglite -y - - name: Build slicer Win if: runner.os == 'Windows' working-directory: ${{ github.workspace }} diff --git a/CMakeLists.txt b/CMakeLists.txt index c912cdd08f..4f5ccbeb44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -476,8 +476,7 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) # WIN10SDK_PATH is used to point CMake to the WIN10 SDK installation directory. # We pick it from environment if it is not defined in another way # ORCA: Removed Netfabb STL fixing service support in favor of CGAL. -if(WIN32) - find_package(PkgConfig REQUIRED) +# if(WIN32) # if(NOT DEFINED WIN10SDK_PATH) # if(DEFINED ENV{WIN10SDK_PATH}) # set(WIN10SDK_PATH "$ENV{WIN10SDK_PATH}") @@ -513,7 +512,7 @@ if(WIN32) # else() # message("Building without Win10 Netfabb STL fixing service support") # endif() -endif() +# endif() if (APPLE) message("OS X SDK Path: ${CMAKE_OSX_SYSROOT}") diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index e11b5153ae..140b1cec39 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -915,6 +915,18 @@ if (APPLE) endif () target_link_libraries(libslic3r_gui ${LIBAVCODEC_LIBRARY} ${LIBSWSCALE_LIBRARY} ${LIBAVUTIL_LIBRARY}) target_include_directories(libslic3r_gui SYSTEM PRIVATE ${CMAKE_PREFIX_PATH}/include) +elseif (WIN32) + # Prebuilt shared FFmpeg from the deps install. Windows has no pkg-config, + # so resolve the import libraries out of the deps prefix directly; the DLLs + # are copied next to the executable by the top level CMakeLists. + find_library(LIBAVCODEC_LIBRARY NAMES avcodec PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH) + find_library(LIBSWSCALE_LIBRARY NAMES swscale PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH) + find_library(LIBAVUTIL_LIBRARY NAMES avutil PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH) + if (NOT LIBAVCODEC_LIBRARY OR NOT LIBSWSCALE_LIBRARY OR NOT LIBAVUTIL_LIBRARY) + message(FATAL_ERROR "FFmpeg (avcodec/swscale/avutil) not found under ${CMAKE_PREFIX_PATH}/lib. Rebuild the deps.") + endif () + target_link_libraries(libslic3r_gui ${LIBAVCODEC_LIBRARY} ${LIBSWSCALE_LIBRARY} ${LIBAVUTIL_LIBRARY}) + target_include_directories(libslic3r_gui SYSTEM PRIVATE ${CMAKE_PREFIX_PATH}/include) else () pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET libavcodec From 7eaff76cecd1412182efbd0106dcbc41f4e8de43 Mon Sep 17 00:00:00 2001 From: Kris Austin Date: Tue, 1 Sep 2026 08:30:45 -0500 Subject: [PATCH 14/51] build: use clang-cl for Windows CI builds (faster slicing and faster builds) (#15428) * ci: build the Windows x64 dependencies and slicer with clang-cl Passes -l -x from the Windows jobs, using the clang-cl and Ninja options added in #15373. Ninja runs each dependency's build step as a plain command, so the jobs set up a VC environment for OpenSSL's nmake. arm64 stays on MSVC for now. The deps cache key gains the compiler, so windows-x64 becomes windows-x64-clang and windows-arm64 becomes windows-arm64-msvc. * deps: select OpenSSL's ARM64 target from DEPS_ARCH CMAKE_GENERATOR_PLATFORM is only set by -A, which Ninja never receives, so the Ninja build selected the x64 target on ARM64. DEPS_ARCH is derived from CMAKE_SYSTEM_PROCESSOR and is already independent of the generator. * ci: build the Windows ARM64 dependencies and slicer with clang-cl Three dependencies need handling first. libpng and OpenCV each build an ARM SIMD path that does not compile with clang-cl, so those paths are off; PNG already had the same opt-out for Apple ARM. OCCT is built with cl, since clang-cl cannot emit one of its large generated files and there is no option to turn that off. All three are gated to Windows ARM64 with clang. --- .github/workflows/build_all.yml | 5 +++-- .github/workflows/build_check_cache.yml | 13 +++++++++---- .github/workflows/build_deps.yml | 20 ++++++++++++++++++-- .github/workflows/build_orca.yml | 17 ++++++++++++++++- deps/OCCT/OCCT.cmake | 8 ++++++++ deps/OpenCV/OpenCV.cmake | 8 ++++++++ deps/OpenSSL/OpenSSL.cmake | 2 +- deps/PNG/PNG.cmake | 4 ++++ 8 files changed, 67 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build_all.yml b/.github/workflows/build_all.yml index 3de2a9184b..fe4f10e81b 100644 --- a/.github/workflows/build_all.yml +++ b/.github/workflows/build_all.yml @@ -81,14 +81,15 @@ jobs: # SELF_HOSTED skips arm64 (the self-hosted Windows server is x64-only). matrix: include: ${{ fromJSON(vars.SELF_HOSTED - && '[{"arch":"x64","os":"orca-win-server"}]' - || '[{"arch":"x64","os":"windows-latest"},{"arch":"arm64","os":"windows-11-arm"}]') }} + && '[{"arch":"x64","os":"orca-win-server","compiler":"clang"}]' + || '[{"arch":"x64","os":"windows-latest","compiler":"clang"},{"arch":"arm64","os":"windows-11-arm","compiler":"clang"}]') }} # Don't run scheduled builds on forks: if: ${{ !cancelled() && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }} uses: ./.github/workflows/build_check_cache.yml with: os: ${{ matrix.os }} arch: ${{ matrix.arch }} + compiler: ${{ matrix.compiler }} build-deps-only: ${{ inputs.build-deps-only || false }} force-build: ${{ github.event_name == 'schedule' }} secrets: inherit diff --git a/.github/workflows/build_check_cache.yml b/.github/workflows/build_check_cache.yml index b5c5b28b95..91ea51ac60 100644 --- a/.github/workflows/build_check_cache.yml +++ b/.github/workflows/build_check_cache.yml @@ -9,6 +9,10 @@ on: arch: required: false type: string + compiler: + required: false + type: string + default: msvc build-deps-only: required: false type: boolean @@ -33,10 +37,10 @@ jobs: - name: set outputs id: set_outputs env: - # Keep macOS/Windows cache keys architecture-specific. amd64 Linux passes - # no arch (key stays 'linux-clang', preserving the existing cache); - # aarch64 gets its own 'linux-clang-aarch64' key. - cache-os: ${{ runner.os == 'macOS' && format('macos-{0}', inputs.arch) || (runner.os == 'Windows' && format('windows-{0}', inputs.arch) || format('linux-clang{0}', inputs.arch && format('-{0}', inputs.arch) || '')) }} + # Anything that changes how the tree is built belongs in the key, or a job + # restores one it cannot use. Linux amd64 passes no arch deliberately, so + # 'linux-clang' keeps the cache it already has. + cache-os: ${{ runner.os == 'macOS' && format('macos-{0}', inputs.arch) || (runner.os == 'Windows' && format('windows-{0}-{1}', inputs.arch, inputs.compiler) || format('linux-clang{0}', inputs.arch && format('-{0}', inputs.arch) || '')) }} # ARM64 builds use the build-arm64 tree (see build_release_vs.bat); x64/other use build. dep-folder-name: ${{ runner.os == 'macOS' && format('/{0}', inputs.arch) || (runner.os == 'Windows' && inputs.arch == 'arm64') && '-arm64/OrcaSlicer_dep' || '/OrcaSlicer_dep' }} output-cmd: ${{ runner.os == 'Windows' && '$env:GITHUB_OUTPUT' || '"$GITHUB_OUTPUT"'}} @@ -62,6 +66,7 @@ jobs: valid-cache: ${{ needs.check_cache.outputs.valid-cache == 'true' }} os: ${{ inputs.os }} arch: ${{ inputs.arch }} + compiler: ${{ inputs.compiler }} build-deps-only: ${{ inputs.build-deps-only }} force-build: ${{ inputs.force-build }} secrets: inherit diff --git a/.github/workflows/build_deps.yml b/.github/workflows/build_deps.yml index f9e5c57c34..f7082a8a06 100644 --- a/.github/workflows/build_deps.yml +++ b/.github/workflows/build_deps.yml @@ -16,6 +16,10 @@ on: arch: required: false type: string + compiler: + required: false + type: string + default: msvc build-deps-only: required: false type: boolean @@ -135,11 +139,22 @@ jobs: choco install strawberryperl } $arch = "${{ inputs.arch }}" + # -l selects clang-cl and -x Ninja; together they build the deps with clang. + $clang = "${{ inputs.compiler }}" -eq "clang" + $flags = if ($clang) { "-l", "-x" } else { @() } + if ($clang) { + # OpenSSL builds with nmake, which needs a VC environment. + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + $vs = & $vswhere -latest -property installationPath + $devArch = if ($arch -eq "arm64") { "arm64" } else { "amd64" } + Import-Module "$vs\Common7\Tools\Microsoft.VisualStudio.DevShell.dll" + Enter-VsDevShell -VsInstallPath $vs -SkipAutomaticLocation -DevCmdArguments "-arch=$devArch" + } if ($arch -eq "arm64") { - .\build_release_vs.bat deps arm64 + .\build_release_vs.bat deps arm64 @flags .\build_release_vs.bat pack arm64 } else { - .\build_release_vs.bat deps + .\build_release_vs.bat deps @flags .\build_release_vs.bat pack } shell: pwsh @@ -204,4 +219,5 @@ jobs: cache-path: ${{ inputs.cache-path }} os: ${{ inputs.os }} arch: ${{ inputs.arch }} + compiler: ${{ inputs.compiler }} secrets: inherit diff --git a/.github/workflows/build_orca.yml b/.github/workflows/build_orca.yml index a9efaa7561..8e1e28db13 100644 --- a/.github/workflows/build_orca.yml +++ b/.github/workflows/build_orca.yml @@ -13,6 +13,10 @@ on: arch: required: false type: string + compiler: + required: false + type: string + default: msvc macos-combine-only: required: false type: boolean @@ -395,7 +399,18 @@ jobs: # "tests" builds the unit tests too; the unit_tests_windows_* jobs run them. run: | $arch = "${{ inputs.arch }}" - if ($arch -eq "arm64") { .\build_release_vs.bat slicer arm64 tests } else { .\build_release_vs.bat slicer tests } + # -l selects clang-cl and -x Ninja; together they build the slicer with clang. + $clang = "${{ inputs.compiler }}" -eq "clang" + $flags = if ($clang) { "-l", "-x" } else { @() } + if ($clang) { + # Build against the same VC toolchain and SDK as the dependencies. + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + $vs = & $vswhere -latest -property installationPath + $devArch = if ($arch -eq "arm64") { "arm64" } else { "amd64" } + Import-Module "$vs\Common7\Tools\Microsoft.VisualStudio.DevShell.dll" + Enter-VsDevShell -VsInstallPath $vs -SkipAutomaticLocation -DevCmdArguments "-arch=$devArch" + } + if ($arch -eq "arm64") { .\build_release_vs.bat slicer arm64 @flags tests } else { .\build_release_vs.bat slicer @flags tests } shell: pwsh - name: Build system preset cache (Windows) diff --git a/deps/OCCT/OCCT.cmake b/deps/OCCT/OCCT.cmake index b4cd9facd2..62bfcf8e76 100644 --- a/deps/OCCT/OCCT.cmake +++ b/deps/OCCT/OCCT.cmake @@ -1,3 +1,10 @@ +# clang-cl cannot emit IGESAppli_GeneralModule.cxx on ARM64 +# (llvm/llvm-project#62081). cl and clang-cl share an ABI. +set(_occt_compiler_args "") +if ("${DEPS_ARCH}" STREQUAL "arm64" AND CMAKE_CXX_COMPILER_ID STREQUAL Clang) + set(_occt_compiler_args -DCMAKE_C_COMPILER:STRING=cl -DCMAKE_CXX_COMPILER:STRING=cl) +endif () + if(WIN32) set(library_build_type "Shared") else() @@ -31,6 +38,7 @@ orcaslicer_add_cmake_project(OCCT -DBUILD_MODULE_ModelingAlgorithms=OFF -DBUILD_MODULE_ModelingData=OFF -DBUILD_MODULE_Visualization=OFF + ${_occt_compiler_args} ) # add_dependencies(dep_OCCT ${FREETYPE_PKG}) diff --git a/deps/OpenCV/OpenCV.cmake b/deps/OpenCV/OpenCV.cmake index d8c7cbac3b..0290b3f47a 100644 --- a/deps/OpenCV/OpenCV.cmake +++ b/deps/OpenCV/OpenCV.cmake @@ -10,6 +10,13 @@ else () set(_options "") endif () +# carotene is OpenCV's ARM NEON HAL. It uses M_PI without _USE_MATH_DEFINES +# and does not compile with clang-cl. +set(_disable_carotene "") +if ("${DEPS_ARCH}" STREQUAL "arm64" AND CMAKE_CXX_COMPILER_ID STREQUAL Clang) + set(_disable_carotene "-DWITH_CAROTENE=OFF") +endif () + if (IN_GIT_REPO) set(OpenCV_DIRECTORY_FLAG --directory ${BINARY_DIR_REL}/dep_OpenCV-prefix/src/dep_OpenCV) endif () @@ -83,5 +90,6 @@ orcaslicer_add_cmake_project(OpenCV -DWITH_PROTOBUF=OFF -DWITH_WIN32UI=OFF -DHAVE_WIN32UI=FALSE + ${_disable_carotene} ) diff --git a/deps/OpenSSL/OpenSSL.cmake b/deps/OpenSSL/OpenSSL.cmake index ddeb680052..2fb4b51757 100644 --- a/deps/OpenSSL/OpenSSL.cmake +++ b/deps/OpenSSL/OpenSSL.cmake @@ -6,7 +6,7 @@ if(DEFINED OPENSSL_ARCH) set(_cross_arch ${OPENSSL_ARCH}) else() if(WIN32) - if("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "ARM64") + if("${DEPS_ARCH}" STREQUAL "arm64") set(_cross_arch "VC-WIN64-ARM") else() set(_cross_arch "VC-WIN64A") diff --git a/deps/PNG/PNG.cmake b/deps/PNG/PNG.cmake index 332fdfe274..a73e96a0c9 100644 --- a/deps/PNG/PNG.cmake +++ b/deps/PNG/PNG.cmake @@ -1,6 +1,10 @@ if (APPLE) # Only disable NEON extension for Apple ARM builds, leave it enabled for Raspberry PI. set(_disable_neon_extension "-DPNG_ARM_NEON=off") +elseif ("${DEPS_ARCH}" STREQUAL "arm64" AND CMAKE_CXX_COMPILER_ID STREQUAL Clang) + # libpng's CMake ignores PNG_ARM_NEON on Windows ARM64 and skips the NEON + # sources, but pngpriv.h enables NEON anyway. + set(_disable_neon_extension "-DCMAKE_C_FLAGS=/DWIN32 /D_WINDOWS /DPNG_ARM_NEON_OPT=0") else () set(_disable_neon_extension "") endif () From 96e85b1db56ae9932ea0df47f94485bb16148fd4 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Tue, 1 Sep 2026 19:21:38 +0200 Subject: [PATCH 15/51] Fix build with disabled precompiled headers (#15484) Fix broken build with disabled PCH --- src/libslic3r/Format/OBJ.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libslic3r/Format/OBJ.cpp b/src/libslic3r/Format/OBJ.cpp index e066925a98..10abe8e4de 100644 --- a/src/libslic3r/Format/OBJ.cpp +++ b/src/libslic3r/Format/OBJ.cpp @@ -10,6 +10,7 @@ #include #include +#include #ifdef _WIN32 #define DIR_SEPARATOR '\\' From ec06c8788d2cc5b9efb21a7a6fa45b531418570a Mon Sep 17 00:00:00 2001 From: ndrwrbgs <10776890+ndrwrbgs@users.noreply.github.com> Date: Tue, 1 Sep 2026 12:55:16 -0500 Subject: [PATCH 16/51] Minor display text fixes (#15454) * Minor display text fixes * Update in translations --------- Co-authored-by: Ian Bassi --- localization/i18n/OrcaSlicer.pot | 6 +++--- localization/i18n/ca/OrcaSlicer_ca.po | 6 +++--- localization/i18n/cs/OrcaSlicer_cs.po | 6 +++--- localization/i18n/de/OrcaSlicer_de.po | 6 +++--- localization/i18n/en/OrcaSlicer_en.po | 6 +++--- localization/i18n/es/OrcaSlicer_es.po | 6 +++--- localization/i18n/eu/OrcaSlicer_eu.po | 6 +++--- localization/i18n/fr/OrcaSlicer_fr.po | 6 +++--- localization/i18n/hu/OrcaSlicer_hu.po | 6 +++--- localization/i18n/it/OrcaSlicer_it.po | 6 +++--- localization/i18n/ja/OrcaSlicer_ja.po | 6 +++--- localization/i18n/ko/OrcaSlicer_ko.po | 6 +++--- localization/i18n/lt/OrcaSlicer_lt.po | 6 +++--- localization/i18n/nl/OrcaSlicer_nl.po | 6 +++--- localization/i18n/pl/OrcaSlicer_pl.po | 6 +++--- localization/i18n/pt_BR/OrcaSlicer_pt_BR.po | 6 +++--- localization/i18n/ru/OrcaSlicer_ru.po | 6 +++--- localization/i18n/sv/OrcaSlicer_sv.po | 6 +++--- localization/i18n/th/OrcaSlicer_th.po | 6 +++--- localization/i18n/tr/OrcaSlicer_tr.po | 6 +++--- localization/i18n/uk/OrcaSlicer_uk.po | 6 +++--- localization/i18n/vi/OrcaSlicer_vi.po | 6 +++--- localization/i18n/zh_CN/OrcaSlicer_zh_CN.po | 6 +++--- localization/i18n/zh_TW/OrcaSlicer_zh_TW.po | 6 +++--- src/slic3r/GUI/ConfigManipulation.cpp | 6 +++--- 25 files changed, 75 insertions(+), 75 deletions(-) diff --git a/localization/i18n/OrcaSlicer.pot b/localization/i18n/OrcaSlicer.pot index 6ec0ecd9cf..b183df098b 100644 --- a/localization/i18n/OrcaSlicer.pot +++ b/localization/i18n/OrcaSlicer.pot @@ -4497,7 +4497,7 @@ msgid "" "The value will be reset to 0." msgstr "" -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "" msgid "" @@ -4528,13 +4528,13 @@ msgid "" msgstr "" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" diff --git a/localization/i18n/ca/OrcaSlicer_ca.po b/localization/i18n/ca/OrcaSlicer_ca.po index b7eb022c0d..d78487b947 100644 --- a/localization/i18n/ca/OrcaSlicer_ca.po +++ b/localization/i18n/ca/OrcaSlicer_ca.po @@ -4893,7 +4893,7 @@ msgstr "" "\n" "El valor es restablirà a 0." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "La paret addicional alternativa no funciona bé quan assegurar el gruix de la closca vertical està establert a Tot." msgid "" @@ -4939,7 +4939,7 @@ msgstr "" "NO - Mantenir l'alçada de la capa de suport independent" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height ha de ser més petit que layer_height.\n" @@ -4947,7 +4947,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "La profunditat de bloqueig ha de ser menor que la profunditat de la pell.\n" diff --git a/localization/i18n/cs/OrcaSlicer_cs.po b/localization/i18n/cs/OrcaSlicer_cs.po index b521a8073b..7eeb1072c0 100644 --- a/localization/i18n/cs/OrcaSlicer_cs.po +++ b/localization/i18n/cs/OrcaSlicer_cs.po @@ -4851,7 +4851,7 @@ msgstr "" "\n" "Hodnota bude nastavena na 0." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "Střídavá přídavná stěna nefunguje správně, pokud je zajištění tloušťky svislé stěny nastaveno na Vše." msgid "" @@ -4897,7 +4897,7 @@ msgstr "" "NE – Ponechat nezávislou výšku podpůrné vrstvy" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height musí být menší než layer_height.\n" @@ -4905,7 +4905,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "Hloubka zamčení musí být menší než hloubka krycí vrstvy.\n" diff --git a/localization/i18n/de/OrcaSlicer_de.po b/localization/i18n/de/OrcaSlicer_de.po index 436966457a..92143b907b 100644 --- a/localization/i18n/de/OrcaSlicer_de.po +++ b/localization/i18n/de/OrcaSlicer_de.po @@ -4757,7 +4757,7 @@ msgstr "" "\n" "Der Wert wird auf 0 zurückgesetzt." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "Der alternative zusätzliche Wandmodus funktioniert nicht gut, wenn die vertikale Wanddicke auf Alle eingestellt ist." msgid "" @@ -4803,7 +4803,7 @@ msgstr "" "NEIN - unabhängige Stütz-Schichthöhen beibehalten" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height muss kleiner als layer_height sein.\n" @@ -4811,7 +4811,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "Die Verriegelungstiefe sollte kleiner als die Hauttiefe sein.\n" diff --git a/localization/i18n/en/OrcaSlicer_en.po b/localization/i18n/en/OrcaSlicer_en.po index 88fb455959..eb0a7d774c 100644 --- a/localization/i18n/en/OrcaSlicer_en.po +++ b/localization/i18n/en/OrcaSlicer_en.po @@ -4493,7 +4493,7 @@ msgid "" "The value will be reset to 0." msgstr "" -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "" msgid "" @@ -4524,13 +4524,13 @@ msgid "" msgstr "" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" diff --git a/localization/i18n/es/OrcaSlicer_es.po b/localization/i18n/es/OrcaSlicer_es.po index 9c5127e50a..23294fddbd 100644 --- a/localization/i18n/es/OrcaSlicer_es.po +++ b/localization/i18n/es/OrcaSlicer_es.po @@ -4629,7 +4629,7 @@ msgstr "" "\n" "El valor se restablecerá a 0." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "Perímetro adicional alternado no funciona bien cuando \"Garantizar el grosor vertical de las cubiertas\" se establece en Todos." msgid "" @@ -4675,7 +4675,7 @@ msgstr "" "NO - Mantener la altura de capa de soportes independiente" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height debe ser menor que layer_height.\n" @@ -4683,7 +4683,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "La profundidad de bloqueo debe ser menor que la profundidad de piel.\n" diff --git a/localization/i18n/eu/OrcaSlicer_eu.po b/localization/i18n/eu/OrcaSlicer_eu.po index 03e6d6685d..a5a49e8325 100644 --- a/localization/i18n/eu/OrcaSlicer_eu.po +++ b/localization/i18n/eu/OrcaSlicer_eu.po @@ -4670,7 +4670,7 @@ msgstr "" "\n" "Balioa 0ra berrezarriko da." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "Horma gehigarri txandakatuak ez du ondo funtzionatzen \"Bermatu oskolaren lodiera bertikala\" Guztiak gisa ezarrita dagoenean." msgid "" @@ -4716,7 +4716,7 @@ msgstr "" "NO - 'Euskarrien Geruza-Altuera Independentea' mantendu" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height txigiagoa izan behar da layer_height baino.\n" @@ -4724,7 +4724,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "Blokeo-sakonera gainazalaren sakonera baino txikiagoa izan behar da.\n" diff --git a/localization/i18n/fr/OrcaSlicer_fr.po b/localization/i18n/fr/OrcaSlicer_fr.po index fc58381106..c9bd7f22ef 100644 --- a/localization/i18n/fr/OrcaSlicer_fr.po +++ b/localization/i18n/fr/OrcaSlicer_fr.po @@ -4707,7 +4707,7 @@ msgstr "" "\n" "La valeur sera remise à 0." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "La paroi supplémentaire alternée ne fonctionne pas bien lorsque le paramètre Assurer l’épaisseur de la coque verticale est réglée sur Tous." msgid "" @@ -4753,7 +4753,7 @@ msgstr "" "NON - Conserver la hauteur de la couche de support indépendante" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height doit être inférieur à la hauteur de couche.\n" @@ -4761,7 +4761,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "La profondeur de verrouillage doit être inférieure à la profondeur de la peau.\n" diff --git a/localization/i18n/hu/OrcaSlicer_hu.po b/localization/i18n/hu/OrcaSlicer_hu.po index 9f8a849884..9d966bf80a 100644 --- a/localization/i18n/hu/OrcaSlicer_hu.po +++ b/localization/i18n/hu/OrcaSlicer_hu.po @@ -4803,7 +4803,7 @@ msgstr "" "\n" "Az érték 0-ra áll vissza." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "A váltakozó extra fal nem működik jól, ha a függőleges héjvastagság biztosítása \"Mind\" értékre van állítva." msgid "" @@ -4849,7 +4849,7 @@ msgstr "" "NEM - Független támasz rétegmagasság megtartása" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "A seam_slope_start_height értékének kisebbnek kell lennie, mint a layer_height.\n" @@ -4857,7 +4857,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "A rögzítési mélységnek kisebbnek kell lennie, mint a felületi réteg mélysége.\n" diff --git a/localization/i18n/it/OrcaSlicer_it.po b/localization/i18n/it/OrcaSlicer_it.po index bc36e08d25..6190d2ab44 100644 --- a/localization/i18n/it/OrcaSlicer_it.po +++ b/localization/i18n/it/OrcaSlicer_it.po @@ -4805,7 +4805,7 @@ msgstr "" "\n" "Il valore verrà reimpostato a 0." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "Parete aggiuntiva alternativa non funziona bene quando \"Garantisci spessore verticale del guscio\" è impostato su Tutto." msgid "" @@ -4851,7 +4851,7 @@ msgstr "" "NO - Mantieni Altezza strato di supporto indipendente" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height deve essere inferiore a layer_height.\n" @@ -4859,7 +4859,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "La profondità di intersezione deve essere inferiore alla profondità della pelle.\n" diff --git a/localization/i18n/ja/OrcaSlicer_ja.po b/localization/i18n/ja/OrcaSlicer_ja.po index 1b70ddbf67..327e3df661 100644 --- a/localization/i18n/ja/OrcaSlicer_ja.po +++ b/localization/i18n/ja/OrcaSlicer_ja.po @@ -4818,7 +4818,7 @@ msgstr "" "\n" "値は0にリセットされます。" -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "垂直シェル厚さを「すべて」に設定すると、交互追加壁が適切に機能しません。" msgid "" @@ -4864,7 +4864,7 @@ msgstr "" "いいえ - 「独立サポート積層ピッチ」を有効にする" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_heightはlayer_heightより小さくする必要があります。\n" @@ -4872,7 +4872,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "ロック深さはスキン深さより小さくする必要があります。\n" diff --git a/localization/i18n/ko/OrcaSlicer_ko.po b/localization/i18n/ko/OrcaSlicer_ko.po index 767674e525..e8dfca968f 100644 --- a/localization/i18n/ko/OrcaSlicer_ko.po +++ b/localization/i18n/ko/OrcaSlicer_ko.po @@ -4829,7 +4829,7 @@ msgstr "" "\n" "값이 0으로 재설정됩니다." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "세로 쉘 두께가 모두로 설정된 경우 대체 여분의 벽이 제대로 작동하지 않습니다." msgid "" @@ -4875,7 +4875,7 @@ msgstr "" "아니요 - 독립적 서포트 레이어 높이 유지" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "심_경사_시작_높이는 레이어_높이보다 작아야 합니다.\n" @@ -4883,7 +4883,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "잠금 깊이는 스킨 깊이보다 작아야 합니다.\n" diff --git a/localization/i18n/lt/OrcaSlicer_lt.po b/localization/i18n/lt/OrcaSlicer_lt.po index ad5edffc9a..8fd32bdd26 100644 --- a/localization/i18n/lt/OrcaSlicer_lt.po +++ b/localization/i18n/lt/OrcaSlicer_lt.po @@ -4792,7 +4792,7 @@ msgstr "" "\n" "Reikšmė bus atstatyta į 0." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "Alternatyvi papildoma sienelė veikia prastai, kai vertikalaus apvalkalo storio užtikrinimas nustatytas į „Visi“." msgid "" @@ -4838,7 +4838,7 @@ msgstr "" "NE – palikti nepriklausomą atramų sluoksnio aukštį" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "„seam_slope_start_height“ turi būti mažesnis už „layer_height“\n" @@ -4846,7 +4846,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "Fiksavimo gylis turėtų būti mažesnis už išorinio sluoksnio gylį.\n" diff --git a/localization/i18n/nl/OrcaSlicer_nl.po b/localization/i18n/nl/OrcaSlicer_nl.po index 28ad63d455..96c22fcc8b 100644 --- a/localization/i18n/nl/OrcaSlicer_nl.po +++ b/localization/i18n/nl/OrcaSlicer_nl.po @@ -5217,7 +5217,7 @@ msgstr "" "De waarde wordt teruggezet naar 0." # AI Translated -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "Afwisselende extra wand werkt niet goed wanneer 'verticale wanddikte waarborgen' op Alles is ingesteld." # AI Translated @@ -5265,7 +5265,7 @@ msgstr "" # AI Translated msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height moet kleiner zijn dan layer_height.\n" @@ -5274,7 +5274,7 @@ msgstr "" # AI Translated #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "De vergrendeldiepte moet kleiner zijn dan de huiddiepte.\n" diff --git a/localization/i18n/pl/OrcaSlicer_pl.po b/localization/i18n/pl/OrcaSlicer_pl.po index e8acc62a9b..4a21d38a27 100644 --- a/localization/i18n/pl/OrcaSlicer_pl.po +++ b/localization/i18n/pl/OrcaSlicer_pl.po @@ -4907,7 +4907,7 @@ msgstr "" "\n" "Wartość zostanie zresetowana do 0." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "Alternatywna dodatkowa ściana działa tylko wtedy, gdy jest wyłączona opcja „zapewnij stałą grubość pionowej powłoki”." msgid "" @@ -4953,7 +4953,7 @@ msgstr "" "NIE - Zachowaj Niezależną wysokość warstwy podpory" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height musi być mniejsza niż wysokość warstwy.\n" @@ -4962,7 +4962,7 @@ msgstr "" # AI Translated #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "Głębokość blokady powinna być mniejsza niż głębokość skóry.\n" diff --git a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po index 1b39d4a159..931d3d510b 100644 --- a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po +++ b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po @@ -4641,7 +4641,7 @@ msgstr "" "\n" "O valor será redefinido para 0." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "A parede extra alternada não funciona bem quando a espessura vertical da casca está definida para Todos." msgid "" @@ -4687,7 +4687,7 @@ msgstr "" "NÃO — Manter a Altura da Camada de Suporte Independente" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height precisa ser menor que layer_height.\n" @@ -4695,7 +4695,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "A profundidade do travamento deve ser menor que a profundidade da textura.\n" diff --git a/localization/i18n/ru/OrcaSlicer_ru.po b/localization/i18n/ru/OrcaSlicer_ru.po index 2372471707..eb24ebc759 100644 --- a/localization/i18n/ru/OrcaSlicer_ru.po +++ b/localization/i18n/ru/OrcaSlicer_ru.po @@ -4780,7 +4780,7 @@ msgstr "" "\n" "Значение будет сброшено до 0." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "Чередующаяся дополнительная стенка не работает, если для «Сохранение толщины вертикальной оболочки» установлено значение «Все»." msgid "" @@ -4833,7 +4833,7 @@ msgstr "" "Нет – отключить черновую башню" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "Начальная высота не должна превышать высоту слоя.\n" @@ -4841,7 +4841,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "Перекрытие должно быть меньше внутренней оболочки.\n" diff --git a/localization/i18n/sv/OrcaSlicer_sv.po b/localization/i18n/sv/OrcaSlicer_sv.po index 432000f96d..52972e241a 100644 --- a/localization/i18n/sv/OrcaSlicer_sv.po +++ b/localization/i18n/sv/OrcaSlicer_sv.po @@ -5279,7 +5279,7 @@ msgstr "" "Värdet kommer att återställas till 0." # AI Translated -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "Alternerande extra vägg fungerar inte bra när säkerställ vertikal skaltjocklek är inställt på Alla." # AI Translated @@ -5327,7 +5327,7 @@ msgstr "" # AI Translated msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height måste vara mindre än layer_height.\n" @@ -5336,7 +5336,7 @@ msgstr "" # AI Translated #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "Låsdjupet bör vara mindre än ytskiktets djup.\n" diff --git a/localization/i18n/th/OrcaSlicer_th.po b/localization/i18n/th/OrcaSlicer_th.po index a0c0079125..4c4ac2d25f 100644 --- a/localization/i18n/th/OrcaSlicer_th.po +++ b/localization/i18n/th/OrcaSlicer_th.po @@ -4785,7 +4785,7 @@ msgstr "" "\n" "ค่าจะถูกรีเซ็ตเป็น 0" -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "ผนังเสริมสำรองทำงานได้ไม่ดีเมื่อตั้งค่าความหนาของเปลือกแนวตั้งเป็นทั้งหมด" msgid "" @@ -4831,7 +4831,7 @@ msgstr "" "ไม่ - รักษาความสูงของชั้นรองรับที่เป็นอิสระ" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height ต้องเล็กกว่า layer_height\n" @@ -4839,7 +4839,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "ความลึกของล็อคควรน้อยกว่าความลึกของผิวหนัง\n" diff --git a/localization/i18n/tr/OrcaSlicer_tr.po b/localization/i18n/tr/OrcaSlicer_tr.po index c3deff8bd8..833706ad70 100644 --- a/localization/i18n/tr/OrcaSlicer_tr.po +++ b/localization/i18n/tr/OrcaSlicer_tr.po @@ -4847,7 +4847,7 @@ msgstr "" "\n" "Değer 0'a sıfırlanacaktır." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "Alternatif ekstra duvar, dikey kabuk kalınlığının Tümü olarak ayarlandığından emin olunduğunda iyi çalışmaz." msgid "" @@ -4893,7 +4893,7 @@ msgstr "" "HAYIR - Bağımsız Destek Katmanı Yüksekliğini Koruyun" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height, layer_height değerinden küçük olmalıdır.\n" @@ -4901,7 +4901,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "Kilit derinliği cilt derinliğinden daha küçük olmalıdır.\n" diff --git a/localization/i18n/uk/OrcaSlicer_uk.po b/localization/i18n/uk/OrcaSlicer_uk.po index 9f57b6b71a..df06c01684 100644 --- a/localization/i18n/uk/OrcaSlicer_uk.po +++ b/localization/i18n/uk/OrcaSlicer_uk.po @@ -4781,7 +4781,7 @@ msgstr "" "\n" "Значення буде скинуто на 0." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "Чергування додаткової стінки не працює добре, якщо для параметра \"Забезпечити товщину вертикальної оболонки\" встановлено значення \"Всі\"." msgid "" @@ -4827,7 +4827,7 @@ msgstr "" "НІ - Залишити незалежну висоту шарів підтримки" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height має бути менше висоти шару.\n" @@ -4836,7 +4836,7 @@ msgstr "" # AI Translated #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "Глибина зчеплення має бути меншою за глибину оболонки.\n" diff --git a/localization/i18n/vi/OrcaSlicer_vi.po b/localization/i18n/vi/OrcaSlicer_vi.po index 00a9a558ba..e78fc51687 100644 --- a/localization/i18n/vi/OrcaSlicer_vi.po +++ b/localization/i18n/vi/OrcaSlicer_vi.po @@ -5040,7 +5040,7 @@ msgstr "" "\n" "Giá trị sẽ được đặt lại về 0." -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "Luân phiên wall phụ không hoạt động tốt khi đảm bảo độ dày shell dọc được đặt thành Tất cả." msgid "" @@ -5086,7 +5086,7 @@ msgstr "" "NO - Giữ chiều cao lớp support độc lập" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height cần nhỏ hơn layer_height.\n" @@ -5094,7 +5094,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "Độ sâu khóa phải nhỏ hơn độ sâu skin.\n" diff --git a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po index 133e0815a4..d2f07d19ae 100644 --- a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po +++ b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po @@ -4641,7 +4641,7 @@ msgstr "" "\n" "这个数值将被重置为0。" -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "“交替添加额外”与“确保垂直外壳厚度”的”全部“选项不兼容。" msgid "" @@ -4687,7 +4687,7 @@ msgstr "" "否 - 选择保留支撑独立层高" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height需要小于layer_height。\n" @@ -4695,7 +4695,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "锁定深度应小于表皮深度。\n" diff --git a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po index cf6a2519c3..456092deb5 100644 --- a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po +++ b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po @@ -4758,7 +4758,7 @@ msgstr "" "\n" "該值將會重設為 0。" -msgid "Alternate extra wall does't work well when ensure vertical shell thickness is set to All." +msgid "Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All." msgstr "當確保垂直外殼厚度設為『全部』時,交錯額外牆壁效果不佳。" msgid "" @@ -4815,7 +4815,7 @@ msgstr "" "否 - 選擇保留獨立支撐層高" msgid "" -"seam_slope_start_height need to be smaller than layer_height.\n" +"seam_slope_start_height needs to be smaller than layer_height.\n" "Reset to 0." msgstr "" "seam_slope_start_height 必須小於 layer_height。\n" @@ -4824,7 +4824,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"Lock depth should smaller than skin depth.\n" +"Lock depth should be smaller than skin depth.\n" "Reset to 50% of skin depth." msgstr "" "鎖定深度應小於表皮深度。\n" diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index d15164ef63..09b7fcfad4 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -453,7 +453,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con if (config->opt_bool("alternate_extra_wall") && (config->opt_enum("ensure_vertical_shell_thickness") == evstAll)) { - wxString msg_text = _(L("Alternate extra wall does't work well when ensure vertical shell thickness is set to All.")); + wxString msg_text = _(L("Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All.")); if (is_global_config) msg_text += "\n\n" + _(L("Change these settings automatically?\n" @@ -642,7 +642,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con if (config->opt_enum("seam_slope_type") != SeamScarfType::None && config->get_abs_value("seam_slope_start_height") >= layer_height) { - const wxString msg_text = _(L("seam_slope_start_height need to be smaller than layer_height.\nReset to 0.")); + const wxString msg_text = _(L("seam_slope_start_height needs to be smaller than layer_height.\nReset to 0.")); MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK); DynamicPrintConfig new_conf = *config; is_msg_dlg_already_exist = true; @@ -656,7 +656,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con float skin_depth = config->opt_float("skin_infill_depth"); if (config->opt_float("infill_lock_depth") > skin_depth) { // xgettext:no-c-format, no-boost-format - const wxString msg_text = _(L("Lock depth should smaller than skin depth.\nReset to 50% of skin depth.")); + const wxString msg_text = _(L("Lock depth should be smaller than skin depth.\nReset to 50% of skin depth.")); MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK); DynamicPrintConfig new_conf = *config; is_msg_dlg_already_exist = true; From 21aa07b9cc757331584fd5d6d00183e9cf7021bc Mon Sep 17 00:00:00 2001 From: Kris Austin Date: Tue, 1 Sep 2026 13:02:19 -0500 Subject: [PATCH 17/51] build: add build_win.bat, a Windows build script for deps, slicer and toolchain setup (#15436) * build: add build_win.bat, a Windows build script for deps, slicer and toolchain setup build_release_vs.bat takes no options: what it builds is decided by editing it. This adds build_win.bat alongside it, with short and long options, a grouped help message, a dry-run mode that prints every command instead of running it, and one option per thing a developer actually varies - the configuration, the architecture, the compiler, the generator, the Visual Studio release, how much gets rebuilt, and where the dependency tree lives. It works from any directory, needs no developer command prompt in either generator mode, and keeps CMake ahead of Strawberry Perl on PATH so a build does not depend on how the user ordered their environment. scripts/test_build_win.ps1 covers it with table-driven cases that run the script under --dry-run and assert on the commands it prints, so nothing is configured or built. The Windows build jobs wait on that suite. Based on the script from OrcaSlicer#11097. Co-authored-by: Ocraftyone <24759591+Ocraftyone@users.noreply.github.com> * build: report what build_win.bat produced and what to do next Every successful run now ends with a block naming what it built and the commands to carry on with. Those commands repeat the flags that reproduce the run, so a rebuild after a clang-cl Ninja build is not silently an MSVC one. A failure gets a framed block naming the command that failed and a retry scoped to the stage that failed, so a slicer error does not suggest discarding an untouched dependency tree. Installing is now opt-in behind -i. The install tree is a second full copy of the build that exists mainly so the release can be zipped from it, while the build tree is already runnable, with the DLLs beside the binary and resources symlinked rather than copied. Configuring against a dependency tree that was never built now names it instead of failing several hundred lines into CMake's package resolution. scripts/test_build_win.ps1 covers all of it, and gains -Name so one case can be run without the full pass. * build: let the test options stand alone, and say which build things apply to --run-tests named two things to do and then did neither without -s, so `build_win.bat -lx --run-tests` answered "Nothing to do". Both test options now imply the slicer build they cannot happen without, unless another action was already named, so -d --tests is still a dependency build. --install-vs has turned on --install-deps the same way all along. That makes them actions, so they move to the group that says so. -i goes the other way, to the step toggles beside --no-configure and --no-gettext, since it does not stand alone and adds a step rather than describing what kind of build to make. An example shows the tests run with toolchain flags, because flags pick which build gets tested and a bare --run-tests would build and test a default tree the developer never asked for. Two help lines named defaults that were not the defaults. --build-dir said "instead of build/" and --deps-dir said "instead of deps/", but trees are named for the configuration, compiler and architecture, so build/ is only the default for a release x64 MSVC build, and deps/ is the source directory rather than a tree anything is built in. The hint for a missing dependency tree now carries the flags that reproduce the run. It said "Build them with -d", which after a clang build points at the MSVC tree, so following it left you no better off. Every other suggestion the script makes already repeats them. -k counted on the developer to read taskkill invocations as progress. It now names each image and how many processes it is about to stop, which is what explains the pause, and skips the ones that are not running instead of printing taskkill's "not found" as though something had gone wrong. No image can stop the rest. The environment example set SLIC3R_ASAN, which -a already does, teaching the long way round to a flag the script owns. It now sets options that have no flag. The note under it said "Use these for a value containing spaces. Ampersands are not supported", which named neither what "these" were an alternative to nor where ampersands were a problem. The test harness gains a NotExists field, because output cannot show what a run did not create, and two cases needed to prove exactly that. --------- Co-authored-by: Ocraftyone <24759591+Ocraftyone@users.noreply.github.com> Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> --- .gitattributes | 5 + .github/workflows/build_all.yml | 21 +- .gitignore | 1 + build_win.bat | 1268 +++++++++++++++++++++++++++++++ scripts/test_build_win.ps1 | 847 +++++++++++++++++++++ 5 files changed, 2141 insertions(+), 1 deletion(-) create mode 100644 build_win.bat create mode 100644 scripts/test_build_win.ps1 diff --git a/.gitattributes b/.gitattributes index 441bdfe1eb..472a0b2d1f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,3 +5,8 @@ # with CRLF line endings: it fails on the first line. Windows checkouts default # to core.autocrlf=true, so keep these LF whatever the platform. *.sh text eol=lf + +# Batch files are read by cmd.exe, which tracks a byte offset into the file to +# resume after `call :label`. With LF endings that offset can land wrong and the +# label lookup fails, so keep these CRLF whatever the platform. +*.bat text eol=crlf diff --git a/.github/workflows/build_all.yml b/.github/workflows/build_all.yml index fe4f10e81b..d991bedca6 100644 --- a/.github/workflows/build_all.yml +++ b/.github/workflows/build_all.yml @@ -33,6 +33,8 @@ on: - 'build_linux.sh' - 'build_release_vs.bat' - 'build_release_vs2022.bat' + - 'build_win.bat' + - 'scripts/test_build_win.ps1' - 'build_release_macos.sh' - 'scripts/build_preset_cache.*' - 'scripts/flatpak/**' @@ -56,6 +58,22 @@ concurrency: jobs: + # build_win.bat ships a test suite. Run it before the Windows builds. + check_build_script: + name: Windows build script tests + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v7 + with: + lfs: 'false' + + # Windows PowerShell rather than pwsh: the suite drives build_win.bat + # through cmd, and the two differ in how they quote native arguments. + - name: Run the build script test suite + shell: powershell + run: .\scripts\test_build_win.ps1 + build_linux: strategy: fail-fast: false @@ -83,8 +101,9 @@ jobs: include: ${{ fromJSON(vars.SELF_HOSTED && '[{"arch":"x64","os":"orca-win-server","compiler":"clang"}]' || '[{"arch":"x64","os":"windows-latest","compiler":"clang"},{"arch":"arm64","os":"windows-11-arm","compiler":"clang"}]') }} + needs: check_build_script # Don't run scheduled builds on forks: - if: ${{ !cancelled() && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }} + if: ${{ !cancelled() && needs.check_build_script.result == 'success' && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }} uses: ./.github/workflows/build_check_cache.yml with: os: ${{ matrix.os }} diff --git a/.gitignore b/.gitignore index cdcd1c90b4..e36d0dfa49 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ Build Build.bat /build*/ +/out/ CMakeLists.txt.user CMakeUserPresets.json **/CMakeLists.txt.autosave diff --git a/build_win.bat b/build_win.bat new file mode 100644 index 0000000000..926468687b --- /dev/null +++ b/build_win.bat @@ -0,0 +1,1268 @@ +@echo off + +REM OrcaSlicer build script for Windows. Run with -h for the options. + +REM =========================================================================== +REM Script setup +REM =========================================================================== + +setlocal enableDelayedExpansion + +REM A manually set errorlevel shadows the real one, and cmd then stops +REM updating it after each command. Clear it, inside the scope above so +REM the caller keeps whatever it had. +set errorlevel= + +REM Everything here is relative to the repository root: deps/, build/ and +REM the 7z in tools/. Work from there whatever directory this was called +REM from. setlocal above restores the caller directory on exit. +cd /d "%~dp0" +set "WP=%CD%" +set "script_name=%~nx0" + +set argdefn=0 + +REM Both macros stop on a non-zero errorlevel; error_check also says so. +REM +REM error_check jumps to :die rather than calling exit /b where it stands. +REM Every use of it is inside a parenthesised block, and an exit /b there +REM ends the script but leaves the process exit code at zero, so a failed +REM build reported success. goto unwinds the block first. +set "repeat_error=if not ^!errorlevel^! == 0 exit /b ^!errorlevel^!" +set "error_check=if not ^!errorlevel^! == 0 (set rc=^!errorlevel^!& goto :die)" + +set VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" + +REM =========================================================================== +REM Command line options +REM =========================================================================== + +call :add_section "Actions" +call :add_arg build_deps bool d deps "Download and build the dependencies, needed before -s" +call :add_arg build_slicer bool s slicer "Build OrcaSlicer" +call :add_arg build_tests bool "" tests "Build the unit tests" +call :add_arg run_tests bool "" run-tests "Build the unit tests and run them" +call :add_arg pack_deps bool p pack "Bundle the built dependencies into a zip file" +call :add_arg install_deps bool u install-deps "Install or update CMake, Perl and Git with WinGet" +call :add_arg install_vs string "" install-vs "Also install Visual Studio: buildtools or ide" +call :add_arg kill_jobs bool k kill-jobs "Kill any running build and compiler processes" +call :add_arg print_help bool h help "Print this help message" + +call :add_section "Build configuration" +call :add_arg config string "" config "release, debug, relwithdebinfo or minsizerel (default: release)" +call :add_arg target_arch string "" arch "x64 or arm64 (default: the host architecture)" +call :add_arg slicer_asan bool a asan "Build the slicer with ASAN enabled" + +call :add_section "Toolchain" +call :add_arg use_clang_cl bool l clang-cl "Use clang-cl as the compiler" +call :add_arg use_msvc bool "" msvc "Use cl as the compiler (default)" +call :add_arg use_ninja bool x ninja "Use the Ninja Multi-Config generator" +call :add_arg use_msbuild bool "" msbuild "Use the Visual Studio generator (default)" +call :add_arg vs_version string "" vs "Visual Studio release: 2019, 2022 or 2026 (default: autodetect)" +call :add_arg clang_path string "" clang-path "Path to clang-cl.exe, requires -x (default: the one from Visual Studio)" + +call :add_section "How much gets rebuilt" +call :add_arg slicer_target string "" slicer-target "Build one slicer target instead of all, e.g. libslic3r" +call :add_arg deps_target string t deps-target "Build one dependency instead of all, e.g. dep_Boost" +call :add_arg no_configure bool "" no-configure "Build the existing tree without configuring" +call :add_arg no_gettext bool "" no-gettext "Skip regenerating the translations" +call :add_arg install_slicer bool i install "Install into the build tree's OrcaSlicer folder" +call :add_arg jobs string j jobs "Limit the build to N parallel jobs" +call :add_arg clean bool c clean "Remove the trees this run builds, deps with -d, slicer with -s" + +call :add_section "Paths and extra arguments" +call :add_arg deps_dir string "" deps-dir "Dependency tree to build in or use, instead of the one named for this build" +call :add_arg slicer_dir string "" build-dir "Slicer build directory, instead of the one named for this build" +call :add_arg deps_args rawstring "" deps-args "Extra arguments for the deps configure, quoted" +call :add_arg slicer_args rawstring "" slicer-args "Extra arguments for the slicer configure, quoted" + +call :add_section "Diagnostics" +call :add_arg verbose bool v verbose "Show the compiler command lines" +call :add_arg dry_run bool D dry-run "Print the commands instead of running them" + +REM =========================================================================== +REM Lookup tables +REM =========================================================================== + +REM Known build configurations: the CMake build type, the directory to build +REM in, and the dependency tree to build against. Adding one means adding all +REM three entries in its group. The name is matched case-insensitively because +REM batch variable names are, so --config Debug finds cfg_type_debug. +REM +REM Release, RelWithDebInfo and MinSizeRel all link the /MD dependencies, so +REM they share one tree rather than each paying for its own. Debug needs /MDd +REM and cannot. deps/CMakeLists.txt makes the same split: only Debug turns on +REM DEP_DEBUG, while RelWithDebInfo just adds debug info to a release build. +set "cfg_type_release=Release" +set "cfg_dir_release=build" +set "cfg_dep_release=build" + +set "cfg_type_debug=Debug" +set "cfg_dir_debug=build-dbg" +set "cfg_dep_debug=build-dbg" + +set "cfg_type_relwithdebinfo=RelWithDebInfo" +set "cfg_dir_relwithdebinfo=build-dbginfo" +set "cfg_dep_relwithdebinfo=build" + +set "cfg_type_minsizerel=MinSizeRel" +set "cfg_dir_minsizerel=build-minsize" +set "cfg_dep_minsizerel=build" + +set "cfg_default=release" + +REM Known Visual Studio releases: the generator name, the suffix in the +REM WinGet id, and the major version vswhere and msbuild report. Adding a +REM release means adding all three entries in its group. +set "vs_gen_2019=Visual Studio 16 2019" +set "vs_winget_2019=.2019" +set "vs_year_16=2019" + +set "vs_gen_2022=Visual Studio 17 2022" +set "vs_winget_2022=.2022" +set "vs_year_17=2022" + +REM 2026 is the unversioned WinGet id: there is no Microsoft.VisualStudio.2026. +set "vs_gen_2026=Visual Studio 18 2026" +set "vs_winget_2026=" +set "vs_year_18=2026" + +set "vs_default=2026" + +REM What --install-vs asks WinGet for. +set "vs_edition_buildtools=BuildTools" +set "vs_edition_ide=Community" + +REM =========================================================================== +REM Command line handling +REM =========================================================================== + +call :handle_args %* +%error_check% + +if "%debugscript%" == "ON" ( + set /A range_end = %argdefn% - 1 + for /L %%i in (0, 1, !range_end!) do ( + call :echo_var !argdefs[%%i].VARIABLE_NAME! + ) +) + +if "%~1" == "" ( + set print_help=ON + goto :before_print_help +) + +set "all_args=%*" +if "%all_args:"=%" == "" ( + set print_help=ON +) + +:before_print_help + +if "%print_help%" == "ON" ( + call :print_help_msg + exit /b 0 +) + +REM Say so before the first + line scrolls past. +if "%dry_run%" == "ON" echo Dry run: printing commands without running them. + +if "%kill_jobs%" == "ON" ( + echo Stopping build processes. + call :kill_image MSBuild.exe + call :kill_image ninja.exe + call :kill_image cl.exe + call :kill_image clang-cl.exe + exit /b 0 +) + +REM Neither test option can happen without building the slicer, so asking for +REM one asks for that, unless another action was already named. +if "%build_deps%%build_slicer%%pack_deps%%install_deps%%install_vs%" == "" ( + if "%build_tests%" == "ON" set "build_slicer=ON" + if "%run_tests%" == "ON" set "build_slicer=ON" +) + +REM Options like --config or -j only shape a build. Without one of the actions +REM there is nothing for them to shape, so say so rather than resolving a whole +REM build and reporting it took no time. The block above may have added one. +if "%build_deps%%build_slicer%%pack_deps%%install_deps%%install_vs%" == "" ( + echo Nothing to do. Pick an action: -d, -s, -p or -u. Run -h for the full list. + exit /b 1 +) + +REM =========================================================================== +REM Visual Studio and target architecture +REM =========================================================================== + +REM Asking for Visual Studio is asking to install prerequisites. Resolve the +REM edition here rather than testing whether the name is defined: `if defined` +REM stops at the first space, so "ide " would pass and then expand to nothing. +set "vs_edition=" +if not "%install_vs%" == "" ( + set "install_deps=ON" + set "vs_edition=!vs_edition_%install_vs%!" + if "!vs_edition!" == "" ( + echo Unknown Visual Studio edition "%install_vs%". Known editions: buildtools, ide. + exit /b 1 + ) +) +REM Autodetection overwrites vs_version, so snapshot whether it was pinned. +set "vs_pinned=%vs_version%" + +if not "%vs_version%" == "" if "%use_ninja%" == "ON" ( + echo --vs and --ninja select different generators. + exit /b 1 +) +REM install(TARGETS OrcaSlicer) carries no OPTIONAL, so installing a tree +REM whose executable was never built fails. Say so before the build starts. +if "%build_slicer%" == "ON" if "%install_slicer%" == "ON" if not "%slicer_target%" == "" if /I not "%slicer_target%" == "OrcaSlicer" ( + echo --install needs the executable, but --slicer-target names "%slicer_target%". + exit /b 1 +) +if not "%vs_version%" == "" if "!vs_gen_%vs_version%!" == "" ( + echo Unknown Visual Studio release "%vs_version%". Known releases: 2019, 2022, 2026. + exit /b 1 +) + +call :autodetect_vs +%error_check% + +REM autodetect leaves this empty when it finds nothing usable. +if "%vs_version%" == "" set "vs_version=%vs_default%" + +REM Default to the host CPU. PROCESSOR_ARCHITEW6432 covers a 32-bit shell on +REM a 64-bit OS, where PROCESSOR_ARCHITECTURE reads x86. +set arch=x64 +if /I "%PROCESSOR_ARCHITECTURE%" == "ARM64" set arch=ARM64 +if /I "%PROCESSOR_ARCHITEW6432%" == "ARM64" set arch=ARM64 +if not "%target_arch%" == "" ( + if /I "%target_arch%" == "arm64" ( + set arch=ARM64 + ) else ( + if /I "%target_arch%" == "x64" ( + set arch=x64 + ) else ( + echo Unknown architecture "%target_arch%". Expected x64 or arm64. + exit /b 1 + ) + ) +) + +REM =========================================================================== +REM Installing prerequisites +REM =========================================================================== + +if "%install_deps%" == "ON" ( + where winget >nul 2>nul + if not !errorlevel! == 0 ( + echo WinGet was not found + exit /b 1 + ) + REM Keep going after one failure so the rest still get installed, then + REM name the ones that did not rather than claiming they all did. + set "install_failed=" + set "winget_args=-e --source=winget" + if not "%install_vs%" == "" ( + set "vs_year=!vs_winget_%vs_version%!" + set "ide_component_flag=" + if /I "%install_vs%" == "ide" set "ide_component_flag=Microsoft.VisualStudio.Component.VC.CoreIde" + REM Two components: the clang-cl compiler itself, and the MSBuild + REM toolset that lets the Visual Studio generator drive it. One + REM install covers both x64 and ARM64. + set "clang_cl_flag=" + if "%use_clang_cl%" == "ON" set "clang_cl_flag=Microsoft.VisualStudio.Component.VC.Llvm.Clang Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset" + REM The x64 tools build the host tooling either way; targeting ARM64 + REM needs its own toolset on top of them. + set "arm64_tools_flag=" + if /I "%arch%" == "ARM64" set "arm64_tools_flag=Microsoft.VisualStudio.Component.VC.Tools.ARM64" + call :print_and_run winget install !winget_args! --id=Microsoft.VisualStudio!vs_year!.!vs_edition! --force --custom "--add !ide_component_flag! Microsoft.VisualStudio.Component.VC.Tools.x86.x64 !arm64_tools_flag! Microsoft.VisualStudio.Component.VC.CMake.Project Microsoft.VisualStudio.Component.Windows11SDK.22621 !clang_cl_flag!" + call :note_failed "Visual Studio" !errorlevel! + ) + + REM CMake 4 dropped pre-3.5 policy support and ships incomplete ASM_ARMASM + REM linker modules, which breaks Boost.Context on ARM64. CI pins the same way. + set "cmake_version_flag=" + if /I "%arch%" == "ARM64" set "cmake_version_flag=--version 3.31.8" + call :print_and_run winget install !winget_args! --id=Kitware.CMake !cmake_version_flag! + call :note_failed CMake !errorlevel! + call :print_and_run winget install !winget_args! --id=StrawberryPerl.StrawberryPerl + call :note_failed Perl !errorlevel! + call :print_and_run winget install !winget_args! --id=Git.Git + call :note_failed Git !errorlevel! + + if defined install_failed ( + set "die_reason=Failed to install:!install_failed!" + set rc=1 + goto :die + ) + + REM Flags to repeat back in the deferred build command. + set "next_flags=" + if "%use_clang_cl%" == "ON" set "next_flags=!next_flags! -l" + if "%use_ninja%" == "ON" set "next_flags=!next_flags! -x" + if not "%target_arch%" == "" set "next_flags=!next_flags! --arch %target_arch%" + + REM Name the build that was deferred, not a fuller one. + set "next_actions=" + if "%build_deps%" == "ON" set "next_actions=!next_actions!d" + if "%build_slicer%" == "ON" set "next_actions=!next_actions!s" + if "%pack_deps%" == "ON" set "next_actions=!next_actions!p" + if "!next_actions!" == "" set "next_actions=ds" + + echo. + echo ------------------------------------------------------------- + REM A dry run installed nothing, so do not report that it did. + if "%dry_run%" == "ON" ( + echo Dry run: nothing was installed. + ) else ( + echo Installed the prerequisites. + ) + echo. + echo Next + REM The new PATH cannot reach this shell, so the build runs in the next one. + echo Restart this shell so the new PATH takes effect, then + echo build_win.bat -!next_actions!!next_flags! + echo ------------------------------------------------------------- + exit /b 0 +) + +REM =========================================================================== +REM Resolving the build +REM =========================================================================== + +REM A value ending in a backslash escapes the closing quote when it is +REM spliced into a command line: -B "D:\tree\" reaches cmake as D:\tree" +REM and swallows the argument after it. No path here needs one. +call :trim_slash deps_dir +call :trim_slash slicer_dir +call :trim_slash clang_path + +REM Naming a specific clang-cl is naming clang-cl. Doing it before the +REM conflict check below means --clang-path with --msvc is caught there. +if not "%clang_path%" == "" set "use_clang_cl=ON" +if not "%clang_path%" == "" if not exist "%clang_path%" ( + echo No clang-cl at "%clang_path%". + exit /b 1 +) +REM A trailing backslash matches directories only, and a directory would +REM otherwise reach CMake as the compiler. +if not "%clang_path%" == "" if exist "%clang_path%\" ( + echo "%clang_path%" is a directory. Name clang-cl.exe itself. + exit /b 1 +) + +REM Naming a default explicitly is fine; naming both sides is not. +if "%use_clang_cl%" == "ON" if "%use_msvc%" == "ON" ( + echo --clang-cl and --msvc select different compilers. + exit /b 1 +) +if "%use_ninja%" == "ON" if "%use_msbuild%" == "ON" ( + echo --ninja and --msbuild select different generators. + exit /b 1 +) + +set "generator=!vs_gen_%vs_version%!" +if "%use_ninja%" == "ON" ( + set "generator=Ninja Multi-Config" + call :setup_dev_env + %error_check% + set "using_ninja=ON" +) + +if "%using_ninja%" == "ON" ( + if "%use_clang_cl%" == "ON" ( + REM Bare, so it resolves from the PATH the dev shell just set up, which + REM is the clang shipped with Visual Studio. --clang-path names another. + set "clang_exe=clang-cl.exe" + if not "%clang_path%" == "" set "clang_exe="%clang_path%"" + set "gen_args=-DCMAKE_C_COMPILER=!clang_exe! -DCMAKE_CXX_COMPILER=!clang_exe!" + ) +) else ( + set "gen_args=-A !arch!" + if "%use_clang_cl%" == "ON" ( + set "gen_args=!gen_args! -T ClangCL" + ) +) + +if not "%clang_path%" == "" if not "%using_ninja%" == "ON" ( + echo --clang-path needs the Ninja generator; add -x. The Visual Studio + echo generator builds clang-cl through its own ClangCL toolset. + exit /b 1 +) + +REM Ninja prints [123/456] by default, which says nothing about how far +REM along it is or how long is left. %p is a percentage, %w and %W are +REM elapsed and remaining, but those two arrived in ninja 1.12 and an +REM unknown placeholder is fatal rather than a warning, so an older ninja +REM would abort the build instead of degrading. Ask which one is on PATH. +REM Keep %p first inside the brackets: VS Code reads the first digits% +REM it finds there to drive its progress bar. +if "%using_ninja%" == "ON" if not defined NINJA_STATUS ( + set "nj_major=0" + set "nj_minor=0" + for /f "tokens=1,2 delims=." %%a in ('ninja --version 2^>nul') do ( + set "nj_major=%%a" + set "nj_minor=%%b" + ) + set "NINJA_STATUS=[%%s/%%t %%p :: %%e] " + if !nj_major! GTR 1 set "NINJA_STATUS=[%%f/%%t %%p :: %%w / %%W] " + if !nj_major! EQU 1 if !nj_minor! GEQ 12 set "NINJA_STATUS=[%%f/%%t %%p :: %%w / %%W] " +) +if "%verbose%" == "ON" if defined NINJA_STATUS echo Ninja progress format: !NINJA_STATUS! + +if "%deps_target%" == "" ( + set "deps_target=deps" +) + +REM Only the builds need CMake. -p zips an existing tree with 7z. +if "%build_deps%%build_slicer%" == "" goto :cmake_ready + +cmake --version >nul 2>nul +if not !errorlevel! == 0 ( + echo CMake was not found. Have you installed the system dependencies? + exit /b 1 +) + +REM Strawberry Perl ships a c/bin full of GNU tools, and the top-level +REM CMakeLists refuses to configure when it precedes CMake on PATH. Put a +REM real CMake first, skipping any hit from Strawberry's own cmake.exe, or +REM this pins exactly the order it is meant to undo. The findstr needle +REM must not end in a backslash, which escapes the quote and matches nothing. +set "cmake_bin=" +for /f "delims=" %%i in ('where cmake 2^>nul') do ( + if not defined cmake_bin ( + echo %%~dpi| findstr /i /c:"\Strawberry\c\bin" >nul || set "cmake_bin=%%~dpi" + ) +) +if defined cmake_bin set "PATH=%cmake_bin%;%PATH%" +:cmake_ready + +if "%config%" == "" set "config=%cfg_default%" + +REM Judge what the lookup returned rather than whether the name is defined. +REM "release " passed `if defined` and then expanded to nothing, leaving an +REM empty build directory for --clean to remove. +set "build_type=!cfg_type_%config%!" +set "tree_name=!cfg_dir_%config%!" +set "dep_name=!cfg_dep_%config%!" +set "bad_config=" +if "!build_type!" == "" set "bad_config=ON" +if "!tree_name!" == "" set "bad_config=ON" +if "!dep_name!" == "" set "bad_config=ON" +if defined bad_config ( + echo Unknown configuration "%config%". Known configurations: release, debug, relwithdebinfo, minsizerel. + exit /b 1 +) + +REM A tree is only good for the configuration, compiler and architecture it +REM was made with. Change one underneath it and CMake resets its cache and +REM carries on, leaving ExternalProject stamps from the old toolchain and +REM sub-builds that fail scattershot on things that build fine from scratch. +REM So name the tree for all three. MSVC x64 keeps the historical names. +if "%use_clang_cl%" == "ON" set "tree_name=!tree_name!-clang" +if /I "%arch%" == "ARM64" set "tree_name=!tree_name!-arm64" +if "%use_clang_cl%" == "ON" set "dep_name=!dep_name!-clang" +if /I "%arch%" == "ARM64" set "dep_name=!dep_name!-arm64" + +set "build_dir=!tree_name!" +if not "%slicer_dir%" == "" set "build_dir=%slicer_dir%" + +REM Resolve it once. --build-dir may arrive absolute, relative, or with +REM forward slashes, and anything that prints the directory has to show a +REM real path rather than one glued onto the repository root. +for %%p in ("!build_dir!") do set "build_full=%%~fp" +echo Configuration: %build_type%, %arch% + +set "SIG_FLAG=" +if defined ORCA_UPDATER_SIG_KEY set "SIG_FLAG=-DORCA_UPDATER_SIG_KEY=%ORCA_UPDATER_SIG_KEY%" + +set "TESTS_FLAG=-DBUILD_TESTS=OFF" +if "%build_tests%" == "ON" set "TESTS_FLAG=-DBUILD_TESTS=ON" +if "%run_tests%" == "ON" set "TESTS_FLAG=-DBUILD_TESTS=ON" + +set "SLICER_TARGET_FLAG=" +if not "%slicer_target%" == "" set "SLICER_TARGET_FLAG=--target %slicer_target%" + +set "DEP_TREE=deps/!dep_name!" +set "DEP_TREE_PACK=%WP%\deps\!dep_name!" +set "DEP_TREE_FLAG=" +if not "%deps_dir%" == "" ( + set "DEP_TREE=%deps_dir%" + set "DEP_TREE_PACK=%deps_dir%" + set "DEP_TREE_FLAG=-DDEP_BUILD_DIR="%deps_dir%"" +) + +REM CMakeLists derives DEP_BUILD_DIR from the build directory NAME, which is +REM wrong whenever the build tree and the dependency tree are named +REM differently, as they are for every configuration that shares the release +REM dependencies. Name it outright once the two stop matching. +if "!DEP_TREE_FLAG!" == "" if not "%build_dir%" == "!dep_name!" ( + set "DEP_TREE_FLAG=-DDEP_BUILD_DIR="%WP%\deps\!dep_name!"" +) + +set "VERBOSE_FLAG=" +if "%verbose%" == "ON" set "VERBOSE_FLAG=--verbose" + +REM The two generators count differently. +REM +REM Ninja counts compilers, so -j is exact. The deps superbuild reads +REM CMAKE_BUILD_PARALLEL_LEVEL for the sub-builds it drives. +REM +REM MSBuild turns -j into /m, which counts projects, not compilers: /MP still +REM runs one cl per core inside each one, so -j 1 would not give one +REM compiler. CL_MPCount sets the /MP degree instead, and MSBuild reads +REM properties from the environment, so nested deps builds inherit it. /m +REM stays at its default of one project at a time. +set "JOBS_FLAG=" +if "%jobs%" == "" goto :jobs_ready +echo %jobs%| findstr /r /c:"^[1-9][0-9]*$" >nul +if errorlevel 1 ( + echo Invalid --jobs value "%jobs%". Expected a positive integer. + exit /b 1 +) +if "%using_ninja%" == "ON" ( + set "JOBS_FLAG=-j %jobs%" + set "CMAKE_BUILD_PARALLEL_LEVEL=%jobs%" +) else ( + set "CL_MPCount=%jobs%" +) +echo Parallel jobs: %jobs% +:jobs_ready + +REM The flags that reproduce this run, for the commands the summary suggests. +REM Kept in three parts because they are not all relevant everywhere: a deps +REM retry has no use for --build-dir, and the bundle line names its own tree. +set "recall_tc=" +if "%use_clang_cl%" == "ON" set "recall_tc=!recall_tc! -l" +if "%using_ninja%" == "ON" set "recall_tc=!recall_tc! -x" +if /I not "%config%" == "%cfg_default%" set "recall_tc=!recall_tc! --config %config%" +if not "%target_arch%" == "" set "recall_tc=!recall_tc! --arch %target_arch%" +if not "%vs_pinned%" == "" set "recall_tc=!recall_tc! --vs %vs_pinned%" +if not "%clang_path%" == "" set "recall_tc=!recall_tc! --clang-path "%clang_path%"" + +set "recall_i=" +if "%install_slicer%" == "ON" set "recall_i= -i" +set "recall_dd=" +if not "%deps_dir%" == "" set "recall_dd= --deps-dir "%deps_dir%"" +set "recall_bd=" +if not "%slicer_dir%" == "" set "recall_bd= --build-dir "%slicer_dir%"" +set "recall=!recall_tc!!recall_i!!recall_dd!!recall_bd!" + +REM =========================================================================== +REM Running the build +REM =========================================================================== + +REM CMake 4 refuses a pre-3.5 policy version; several deps still ask for one. +set CMAKE_POLICY_VERSION_MINIMUM=3.5 + +set _START_TIME=%TIME% + +if "%build_deps%" == "ON" ( + REM Which stage is running, so a failure can name it and suggest a + REM retry scoped to it rather than to the whole run. + set "stage=d" + echo Building the dependencies... + + if "%clean%" == "ON" ( + call :clean_tree "!DEP_TREE!" + %error_check% + ) + + if not "%no_configure%" == "ON" ( + call :print_and_run cmake -S deps -B "!DEP_TREE!" -G "%generator%" %gen_args% -DCMAKE_BUILD_TYPE=%build_type% !deps_args! %ORCA_DEPS_CMAKE_ARGS% + %error_check% + ) + + call :print_and_run cmake --build "!DEP_TREE!" --config %build_type% --target %deps_target% %JOBS_FLAG% %VERBOSE_FLAG% + %error_check% +) + +if "%pack_deps%" == "ON" ( + set "stage=p" + setlocal ENABLEDELAYEDEXPANSION + call :print_and_run cd /d "!DEP_TREE_PACK!" + %error_check% + REM date /t prints in the machine locale and its field order varies by + REM region, which is how the inherited parse produced YYYYDDMM. Ask for + REM an unambiguous stamp instead. powershell.exe lives under + REM System32\WindowsPowerShell rather than System32, so a trimmed PATH + REM cannot find it and the stamp comes back empty. + set "ps=%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" + set "build_date=" + for /f %%d in ('!ps! -NoProfile -Command "Get-Date -Format yyyyMMdd"') do set "build_date=%%d" + if "!build_date!" == "" ( + set "die_reason=Could not read the date from !ps!." + set rc=1 + goto :die + ) + + REM A bundle is only good for what built it, so it carries the same parts + REM as the dependency tree. Release x64 on cl keeps the plain name. + set "dep_flavour=!cfg_dep_%config%!" + set "dep_flavour=!dep_flavour:build=!" + set "dep_variant=%arch%" + if "%use_clang_cl%" == "ON" set "dep_variant=!dep_variant!-clang" + set "dep_variant=!dep_variant!!dep_flavour!" + echo Packing the dependencies: OrcaSlicer_dep_win-!dep_variant!_!build_date!.zip + + REM tools\7z.exe loads its codecs from a 7z.dll, and the repo does not + REM carry one, so it can only archive on a machine that has 7-Zip + REM installed. Windows has shipped bsdtar in System32 since 10 1803 and + REM it writes an ordinary deflate zip, so fall back to that rather than + REM failing on a machine that has everything it needs. + set "zipper=" + if exist "%WP%\tools\7z.dll" set "zipper=%WP%/tools/7z.exe a" + if not defined zipper if exist "%SystemRoot%\System32\tar.exe" set "zipper=%SystemRoot%\System32\tar.exe -a -c -f" + if not defined zipper ( + set "die_reason=No archiver. tools\7z.exe needs a 7z.dll, and this Windows has no System32\tar.exe." + set "die_hint=Install 7-Zip, or copy its 7z.dll into tools\." + set rc=1 + goto :die + ) + + call :print_and_run !zipper! OrcaSlicer_dep_win-!dep_variant!_!build_date!.zip OrcaSlicer_dep + %error_check% + REM endlocal is about to discard the name, so carry the path out with it. + for %%z in ("!DEP_TREE_PACK!\OrcaSlicer_dep_win-!dep_variant!_!build_date!.zip") do endlocal & set "bundle=%%~fz" +) + +if "%build_slicer%" == "ON" ( + set "stage=s" + echo Building OrcaSlicer... + + if "%clean%" == "ON" ( + call :clean_tree "%build_dir%" + %error_check% + ) + + if "%slicer_asan%" == "ON" ( + set "slicer_args=!slicer_args! -DSLIC3R_ASAN=ON" + ) + + REM Configuring against a tree that was never built fails deep inside + REM package resolution. Name it here instead. Skipped when -d is about to + REM build it in this same run, and under a dry run, which configures + REM nothing and must not depend on what happens to be on the machine. + if not "%dry_run%" == "ON" if not "%no_configure%" == "ON" if not "%build_deps%" == "ON" if not exist "!DEP_TREE!\OrcaSlicer_dep\usr\local\" ( + for %%p in ("!DEP_TREE!") do set "die_reason=Dependencies not found at %%~fp" + set "die_hint=Build them with build_win.bat -d!recall!." + REM Only worth suggesting to someone who did not name a tree. + if "%deps_dir%" == "" set "die_hint=Build them with build_win.bat -d!recall!, or point --deps-dir at an existing tree." + set rc=1 + goto :die + ) + + if not "%no_configure%" == "ON" ( + call :print_and_run cmake -B "%build_dir%" -G "%generator%" %gen_args% -DORCA_TOOLS=ON %SIG_FLAG% %TESTS_FLAG% %DEP_TREE_FLAG% -DCMAKE_BUILD_TYPE=%build_type% !slicer_args! %ORCA_SLICER_CMAKE_ARGS% + %error_check% + ) + + call :print_and_run cmake --build "%build_dir%" --config %build_type% %SLICER_TARGET_FLAG% %JOBS_FLAG% %VERBOSE_FLAG% + %error_check% + + if "%run_tests%" == "ON" ( + call :print_and_run ctest --test-dir "%build_dir%/tests" -C %build_type% --output-on-failure + %error_check% + ) + + if not "%no_gettext%" == "ON" ( + call :print_and_run call scripts/run_gettext.bat + %error_check% + ) + + if "%install_slicer%" == "ON" ( + call :print_and_run cmake --build "%build_dir%" --target install --config %build_type% + %error_check% + ) +) + +REM Elapsed wall clock. The 1%%a-100 trick strips a leading zero, which set /A +REM would otherwise read as octal, and a negative total means the build ran +REM past midnight. +for /f "tokens=1-3 delims=:.," %%a in ("%_START_TIME: =0%") do set /a "_start_s=(1%%a-100)*3600+(1%%b-100)*60+(1%%c-100)" +for /f "tokens=1-3 delims=:.," %%a in ("%TIME: =0%") do set /a "_end_s=(1%%a-100)*3600+(1%%b-100)*60+(1%%c-100)" +set /a "_elapsed=_end_s - _start_s" +if %_elapsed% lss 0 set /a "_elapsed+=86400" +set /a "_hours=_elapsed / 3600" +set /a "_remainder=_elapsed - _hours * 3600" +set /a "_mins=_remainder / 60" +set /a "_secs=_remainder - _mins * 60" +call :summary +exit /b 0 + +REM Reached only by error_check, from the top level, where exit /b works. +REM The hash block is what CMakeLists already uses for a build that cannot +REM continue, so it means the same thing here. +:die +echo. +echo ############################################################# +REM The paths that set die_reason had no command fail, so last_cmd there +REM names one that succeeded. +if defined die_reason echo !die_reason! +if not defined die_reason if defined last_cmd echo Failed: !last_cmd! +if defined die_hint echo !die_hint! +echo Exit code %rc%. +REM -v only makes the build verbose, so it has nothing to offer a configure +REM that failed before any compiler ran. +set "failed_configure=" +if "!last_cmd:~0,9!" == "cmake -B " set "failed_configure=ON" +if "!last_cmd:~0,9!" == "cmake -S " set "failed_configure=ON" +REM Scoped to the stage that failed. Offering -c for the whole run would +REM discard a dependency tree that was not at fault, and neither flag does +REM anything for a failed pack. A named reason already carries its own advice. +if "!stage!" == "d" set "recall=!recall_tc!!recall_dd!" +if not defined die_reason if defined stage if not "!stage!" == "p" ( + echo. + echo Try + if not defined failed_configure echo build_win.bat -!stage!!recall! -v show the failing compiler command line + echo build_win.bat -!stage!!recall! -c discard that tree and configure from scratch +) +echo ############################################################# +exit /b %rc% + +REM =========================================================================== +REM Function definitions +REM =========================================================================== + +REM summary - what was produced, and what to do with it next. A dry run says +REM so rather than claiming the files exist, but every line below that is +REM worked out the same way in either run. +:summary + for %%p in ("!DEP_TREE!") do set "dep_full=%%~fp" + REM The binary only leaves the build tree when it is installed. + set "slicer_exe=%build_dir%\src\%build_type%\orca-slicer.exe" + if "%install_slicer%" == "ON" set "slicer_exe=%build_dir%\OrcaSlicer\orca-slicer.exe" + for %%p in ("!slicer_exe!") do set "slicer_full=%%~fp" + REM Naming a target builds it and its dependencies, not its dependents, + REM so only a full build or the executable's own target relinks. + set "linked=ON" + if not "%slicer_target%" == "" set "linked=" + if /I "%slicer_target%" == "OrcaSlicer" set "linked=ON" + + echo. + echo ------------------------------------------------------------- + if "%dry_run%" == "ON" ( + echo Dry run: nothing was built. A real run would report: + ) else ( + echo Build completed in %_hours%h %_mins%m %_secs%s + ) + + if "%build_deps%" == "ON" echo Dependencies !dep_full! + if "%build_slicer%" == "ON" if "%linked%" == "ON" echo OrcaSlicer !slicer_full! + if "%build_slicer%" == "ON" if not "%linked%" == "ON" echo Target %slicer_target% + if "%build_slicer%" == "ON" if not "%using_ninja%" == "ON" echo Solution %build_full%\OrcaSlicer.sln + if "%pack_deps%" == "ON" if defined bundle echo Bundle !bundle! + + echo. + echo Next + if "%build_slicer%" == "ON" ( + if "%linked%" == "ON" echo Run it !slicer_exe! + if not "%using_ninja%" == "ON" echo Open in Visual Studio %build_dir%\OrcaSlicer.sln + if "%linked%" == "ON" echo Rebuild after edits build_win.bat -s!recall! --no-configure + if not "%linked%" == "ON" echo Relink the binary build_win.bat -s!recall! --no-configure + if "%linked%" == "ON" if "%using_ninja%" == "ON" echo Rebuild one target build_win.bat -s!recall! --no-configure --slicer-target libslic3r + if "%run_tests%" == "ON" echo Re-run the tests ctest --test-dir %build_dir%/tests -C %build_type% --output-on-failure + ) else ( + if "%build_deps%" == "ON" echo Build the slicer build_win.bat -s!recall! + ) + if "%pack_deps%" == "ON" echo Share the bundle unzip it elsewhere, then build_win.bat -s!recall_tc! --deps-dir ^ + echo ------------------------------------------------------------- + exit /b 0 + +:debug_msg + if "%debugscript%" == "ON" echo %* + exit /b 0 + +REM get_str_len -> length in %ret% +:get_str_len + setlocal + set "in=%~1" + for /L %%i in (0, 1, 100) do ( + if "!in:~%%i,1!" == "" ( + set out=%%i + goto :break_str_len + ) + ) + + echo error in get_str_len: string is too long + endlocal + exit /b 1 + + :break_str_len + endlocal & set ret=%out% + exit /b 0 + +:print_help_msg + setlocal + + REM Measure the widest flag column. Section headers have no flags and + REM must not widen it. + set flags= + set max_len=0 + set /A range_end = %argdefn% - 1 + for /L %%i in (0, 1, %range_end%) do ( + if "!argdefs[%%i].TYPE!" == "section" ( + set "flags[%%i]=" + ) else ( + set str_placeholder= + if not "!argdefs[%%i].TYPE!" == "bool" ( + set "str_placeholder= " + ) + + REM The placeholder goes on the long form only. Repeating it on + REM the short one says nothing extra and costs eight columns. + set "flag_str=" + if not "!argdefs[%%i].SHORT_FLAG!" == "" ( + set "flag_str=-!argdefs[%%i].SHORT_FLAG!" + ) + + if not "!argdefs[%%i].LONG_FLAG!" == "" ( + if "!flag_str!" == "" ( + REM No short flag: pad so the long one lines up with the others. + set "flag_str= " + ) else ( + set "flag_str=!flag_str!, " + ) + set "flag_str=!flag_str!--!argdefs[%%i].LONG_FLAG!!str_placeholder!" + ) else ( + set "flag_str=!flag_str!!str_placeholder!" + ) + set "flag_str=!flag_str! " + set "flags[%%i]=!flag_str!" + call :get_str_len "!flag_str!" + if !ret! GTR !max_len! ( + set max_len=!ret! + ) + ) + ) + + set padding= + for /L %%i in (0, 1, %max_len%) do set "padding=!padding! " + + echo Builds OrcaSlicer and its dependencies on Windows. + echo. + echo Usage: %script_name% [options] + set /A range_end = %argdefn% - 1 + for /L %%i in (0, 1, !range_end!) do ( + if "!argdefs[%%i].TYPE!" == "section" ( + echo. + echo !argdefs[%%i].HELP_TEXT!: + ) else ( + set "flag=!flags[%%i]!%padding%" + echo !flag:~0,%max_len%!!argdefs[%%i].HELP_TEXT! + ) + ) + echo. + echo Examples: + echo %script_name% --install-vs ide Set up a new machine, then restart the shell + echo %script_name% -ds Build the dependencies, then the slicer + echo %script_name% -s -l -x Rebuild the slicer with clang-cl and Ninja + echo %script_name% -s --no-configure -j 8 Rebuild quickly while iterating + echo %script_name% -s --slicer-target glad Compile one target to check the toolchain + echo %script_name% -l -x --run-tests Test that toolchain's build, not the default one + echo. + echo Environment: + echo ORCA_DEPS_CMAKE_ARGS Extra arguments for the deps configure + echo ORCA_SLICER_CMAKE_ARGS Extra arguments for the slicer configure + echo ORCA_UPDATER_SIG_KEY Update signing key baked into the slicer + echo git_commit_hash Revision to stamp, so a commit does not rebuild everything + echo NINJA_STATUS Ninja progress format, if you want your own + echo debugscript Set to ON to trace this script + echo. + echo set ORCA_SLICER_CMAKE_ARGS=-DSLIC3R_PCH=OFF -DSLIC3R_MSVC_PDB=OFF + echo $env:ORCA_SLICER_CMAKE_ARGS = '-DSLIC3R_PCH=OFF' (PowerShell) + echo. + echo --deps-args and --slicer-args cannot carry a value with spaces; use + echo these instead. Neither form supports a value containing an ampersand. + endlocal + exit /b 0 + +REM add_section +:add_section + set argdefs[%argdefn%].VARIABLE_NAME= + set argdefs[%argdefn%].TYPE=section + set argdefs[%argdefn%].SHORT_FLAG= + set argdefs[%argdefn%].LONG_FLAG= + set argdefs[%argdefn%].HELP_TEXT=%~1 + set /A argdefn+=1 + exit /b 0 + +REM add_arg <variable> <type:bool,string,rawstring> <short> <long> <help> +:add_arg + set argdefs[%argdefn%].VARIABLE_NAME=%~1 + set argdefs[%argdefn%].TYPE=%~2 + set argdefs[%argdefn%].SHORT_FLAG=%~3 + set argdefs[%argdefn%].LONG_FLAG=%~4 + set argdefs[%argdefn%].HELP_TEXT=%~5 + + REM Start every option unset, so "defined" means the user gave it. + set %~1= + + if "%debugscript%" == "ON" ( + echo add_arg VARIABLE_NAME: !argdefs[%argdefn%].VARIABLE_NAME! + echo add_arg TYPE: !argdefs[%argdefn%].TYPE! + echo add_arg SHORT_FLAG: !argdefs[%argdefn%].SHORT_FLAG! + echo add_arg LONG_FLAG: !argdefs[%argdefn%].LONG_FLAG! + echo add_arg HELP_TEXT: !argdefs[%argdefn%].HELP_TEXT! + ) + + set /A argdefn+=1 + + exit /b 0 + +REM find_arg <type:short,long> <flag> -> index in %ret% +:find_arg + setlocal + call :debug_msg starting function: find_arg "%~1" "%~2" + + set type= + if /I "%~1" == "short" set type=SHORT + if /I "%~1" == "long" set type=LONG + if not defined type ( + endlocal + set ret= + exit /b 1 + ) + + call :debug_msg find_arg type=%type% + set /A range_end = %argdefn% - 1 + for /L %%i in (0, 1, %range_end%) do ( + if "!argdefs[%%i].%type%_FLAG!" == "%~2" ( + set idx=%%i + goto :find_arg_cont + ) + ) + + echo Error in find_arg: Failed to find arg "%~2" + call :print_help_msg + + endlocal + set ret= + exit /b 1 + + :find_arg_cont + call :debug_msg find_arg: found at %idx% + endlocal & ( + set ret=%idx% + ) + exit /b 0 + +REM set_arg <index> [<value>] +:set_arg + call :debug_msg starting function: set_arg "%~1" "%~2" + + if "%~1" == "" ( + echo Error in set_arg: no index provided + exit /b 1 + ) + + setlocal + if /I "!argdefs[%~1].TYPE!" == "bool" ( + call :debug_msg set_arg: setting bool type to ON + set val=ON + ) else ( + set "val=%~2" + set quote_char=" + REM Delayed expansion throughout: %val% here would be the value from the + REM previous call, since the whole block is parsed before it runs. + if "!val:~0,1!" == "!quote_char!" ( + if "!val:~-1,1!" == "!quote_char!" ( + set "val=!val:~1,-1!" + ) + ) + + call :debug_msg set_arg: setting string type to %~2 + ) + set var_name=!argdefs[%~1].VARIABLE_NAME! + + endlocal & ( + REM Set variable in parent scope + set "%var_name%=%val%" + + REM Add variable to finalize command + set "finalize_cmd=%finalize_cmd% & set "%var_name%=%val%"" + ) + + exit /b 0 + +REM get_arg_type <index> -> type in %ret% +:get_arg_type + call :debug_msg starting function get_arg_type "%~1" + setlocal + set type=!argdefs[%~1].TYPE! + endlocal & set ret=%type% + exit /b 0 + +REM echo_var <variable> +:echo_var + echo %~1=!%~1! + exit /b 0 + +:autodetect_vs + REM Nothing to detect once the release is pinned, or under Ninja. + if not "%vs_version%" == "" exit /b 0 + if "%use_ninja%" == "ON" exit /b 0 + + setlocal + + %VSWHERE% -nologo >nul 2>nul + if not !errorlevel! == 0 ( + REM vswhere is not in its usual place; try msbuild instead. + goto :msbuild_check + ) + + echo Detecting Visual Studio version using vswhere... + for /f "tokens=1 delims=." %%i in ('%VSWHERE% -nologo -products * -latest -property catalog_productDisplayVersion') do ( + set "VS_MAJOR=%%i" + goto :version_found + ) + + :msbuild_check + where msbuild >nul 2>nul + if not !errorlevel! == 0 ( + REM No msbuild either; leave the release empty and let the default apply. + endlocal + exit /b 0 + ) + + echo Detecting Visual Studio version using msbuild... + + REM The version line varies by release, so try two patterns for it. + set VS_MAJOR= + for /f "tokens=*" %%i in ('msbuild -version 2^>^&1 ^| findstr /r "^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*"') do ( + for /f "tokens=1 delims=." %%a in ("%%i") do set VS_MAJOR=%%a + set MSBUILD_OUTPUT=%%i + goto :version_found + ) + + REM The same pattern unanchored, for releases that print a banner first. + if "%VS_MAJOR%"=="" ( + for /f "tokens=*" %%i in ('msbuild -version 2^>^&1 ^| findstr /r "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*"') do ( + for /f "tokens=1 delims=." %%a in ("%%i") do set VS_MAJOR=%%a + set MSBUILD_OUTPUT=%%i + goto :version_found + ) + ) + + :version_found + set "detected=!vs_year_%VS_MAJOR%!" + if not defined detected ( + echo Error: Unsupported Visual Studio major version: %VS_MAJOR% + endlocal + exit /b 1 + ) + echo Detected Visual Studio %VS_MAJOR% ^(!detected!^) + endlocal & set "vs_version=%detected%" + + exit /b 0 + +:setup_dev_env + REM A dry run runs nothing, and VsDevCmd costs seconds. + if "%dry_run%" == "ON" exit /b 0 + set "dev_arch=x64" + if /I "!arch!" == "ARM64" set "dev_arch=arm64" + %VSWHERE% -nologo >nul 2>nul + if not !errorlevel! == 0 ( + REM vswhere is not in its usual place; use the environment as it stands. + exit /b 0 + ) + + for /f "tokens=*" %%i in ('%VSWHERE% -nologo -products * -latest -property resolvedInstallationPath') do ( + set "VS_PATH=%%i" + goto :vs_path_found + ) + exit /b 0 + + :vs_path_found + call "%VS_PATH%\Common7\Tools\VsDevCmd.bat" -arch=!dev_arch! >nul 2>nul + set "VS_PATH=" + + exit /b 0 + +REM clean_tree <path> - remove a build tree, refusing anything that is not +REM one. Nothing here should ever fire; it is a floor under a bug that +REM produced a path far shorter than it looks. +:clean_tree + setlocal + set "target=%~1" + if not defined target ( + echo Refusing to clean: no directory to remove. + exit /b 1 + ) + + REM Resolve first, because "." and "deps/.." are shorter than they read. + for %%p in ("!target!") do set "full=%%~fp" + if "!full:~1!" == ":\" ( + echo Refusing to clean "!full!": that is a drive root. + exit /b 1 + ) + if /I "!full!" == "%WP%" ( + echo Refusing to clean "!full!": that is the repository itself. + exit /b 1 + ) + + call :print_and_run rmdir /S /Q "!full!" + exit /b !errorlevel! + +REM note_failed <name> <code> - record a failed install. Two winget codes +REM mean the tool is already there, which is what -u is for: +REM -1978335135 (0x8A150061) winget declined: a version is already there +REM -1978335189 (0x8A15002B) installed and already the newest version +:note_failed + if "%~2" == "0" exit /b 0 + if "%~2" == "-1978335135" exit /b 0 + if "%~2" == "-1978335189" exit /b 0 + set "install_failed=%install_failed% %~1" + exit /b 0 + +REM trim_slash <variable> - drop a trailing backslash from a path value. +REM A drive root keeps its own: "C:\" is not the same place as "C:". +:trim_slash + set "trim_value=!%~1!" + if not defined trim_value exit /b 0 + if not "!trim_value:~-1!" == "\" exit /b 0 + if "!trim_value:~-2!" == ":\" exit /b 0 + set "%~1=!trim_value:~0,-1!" + exit /b 0 + +REM kill_image <name> - stop every process of one image. The count is printed +REM first because taskkill can take a while and says nothing until it returns. +REM Never fails, so one stubborn image cannot stop the rest. +:kill_image + setlocal + REM A dry run does not count, so it prints the same on every machine. + if "%dry_run%" == "ON" ( + call :print_and_run taskkill /F /IM %~1 + endlocal + exit /b 0 + ) + set "img_count=0" + for /f "tokens=1" %%a in ('tasklist /nh /fi "IMAGENAME eq %~1" 2^>nul') do ( + if /I "%%a" == "%~1" set /a img_count+=1 + ) + if "!img_count!" == "0" ( + echo %~1: none running + endlocal + exit /b 0 + ) + echo %~1: stopping !img_count! + call :print_and_run taskkill /F /IM %~1 + endlocal + exit /b 0 + +REM print_and_run <command...> +:print_and_run + echo + %* + REM Recorded before the command runs. A set afterwards would clear the + REM errorlevel the next line returns, reporting every failure as a pass. + set "last_cmd=%*" + if not "%dry_run%" == "ON" ( + %* + exit /b !errorlevel! + ) + exit /b 0 + +REM handle_args <args...> +:handle_args + call :debug_msg starting function handle_args "%*" + if "%~1" == "" exit /b 0 + + setlocal + set arg=%~1 + set finalize_cmd= + + call :debug_msg Begin handling arg "%arg%" + + if not "%arg:~0,2%" == "--" goto :HAL_check_short + + call :debug_msg Processing long arg + + call :find_arg long %arg:~2% + %repeat_error% + set idx=%ret% + + call :get_arg_type %idx% + %repeat_error% + set type=%ret% + + if /I not "%type%" == "bool" ( + set "string_val=%~2" + if not defined string_val ( + echo Error in handle_args_loop: The option "%arg:~2%" requires a value + exit /b 1 + ) + + REM rawstring options carry cmake arguments, which start with a dash, so + REM only plain string options reject a value that looks like an option. + if /I "%type%" == "string" ( + if "!string_val:~0,1!" == "-" ( + echo Error in handle_args_loop: The option "%arg:~2%" requires a value. "!string_val!" looks like another option. + exit /b 1 + ) + ) + shift + ) + + call :set_arg %idx% "%string_val%" + %repeat_error% + goto :handle_args_loop_reset + + :HAL_check_short + if not "%arg:~0,1%" == "-" ( + echo Unknown argument: %arg% + call :print_help_msg + exit /b 1 + ) + + call :debug_msg processing short args + set /A charidx=1 + :short_arg_loop + if "!arg:~%charidx%,1!" == "" goto :handle_args_loop_reset + + call :find_arg short !arg:~%charidx%,1! + %repeat_error% + set idx=%ret% + + call :get_arg_type %idx% + %repeat_error% + set type=%ret% + + set /A start_idx = %charidx% + 1 + if /I not "%type%" == "bool" ( + REM A value may be attached (-j8) or be the next argument (-j 8). + set remaining=!arg:~%start_idx%! + if defined remaining ( + set string_val=!remaining! + ) else ( + set "string_val=%~2" + shift + ) + if not defined string_val ( + echo Error in handle_args_loop: The option "!arg:~%charidx%,1!" requires a value + exit /b 1 + ) + + REM As in the long-option branch above. + if /I "%type%" == "string" ( + if "!string_val:~0,1!" == "-" ( + echo Error in handle_args_loop: The option "!arg:~%charidx%,1!" requires a value. "!string_val!" looks like another option. + exit /b 1 + ) + ) + call :set_arg !idx! "!string_val!" + %repeat_error% + goto :handle_args_loop_reset + ) + + call :set_arg %idx% + %repeat_error% + set /A charidx+=1 + goto :short_arg_loop + + :handle_args_loop_reset + REM endlocal drops this iteration scope; finalize_cmd re-applies the options + REM it set, in the caller scope. + endlocal %finalize_cmd% + shift + goto :handle_args diff --git a/scripts/test_build_win.ps1 b/scripts/test_build_win.ps1 new file mode 100644 index 0000000000..62eaaae77b --- /dev/null +++ b/scripts/test_build_win.ps1 @@ -0,0 +1,847 @@ +<# +.SYNOPSIS + Tests build_win.bat's option handling and the commands it generates. + +.DESCRIPTION + Cases run the script with --dry-run, so nothing is configured, built or + deleted and the suite finishes in seconds. Each case asserts on the exit + code and on the command lines the script echoes. + + Adding a case means adding one row to $cases. A bare string starts a new + group. Defaults: ExpectExit is 0 and --dry-run is appended, so a row only + states what is unusual about it. + + Name what the case proves, in words + Args arguments, as an array + ExpectExit expected exit code (default 0) + DryRun append --dry-run (default $true) + First regex the first output line must match + Env environment for this case only + Contains literal strings the output must have + NotContains literal strings it must not have + Match regexes; each must match at least one output line + NotMatch regexes; none may match any output line + NotExists paths that must not exist after the case runs + +.PARAMETER Name + Run only the cases whose name matches this regex. Headings with no + matching case are not printed, and a pattern that matches nothing is a + failure rather than an empty pass. + +.EXAMPLE + powershell -File scripts/test_build_win.ps1 + +.EXAMPLE + powershell -File scripts/test_build_win.ps1 -Name solution +#> +[CmdletBinding()] +param( + [string] $Script, + [string] $Name +) + +$ErrorActionPreference = 'Stop' + +if (-not $Script) { + $here = $PSScriptRoot + if (-not $here) { $here = Split-Path -Parent $MyInvocation.MyCommand.Path } + $Script = Join-Path (Split-Path -Parent $here) 'build_win.bat' +} +if (-not (Test-Path $Script)) { throw "build_win.bat not found at $Script" } + +# cmd resumes a batch file by byte offset after `call :label`, and with LF +# endings that offset lands wrong and the label lookup fails. .gitattributes +# pins CRLF; this catches a checkout or an editor that did not honour it. +if ((Get-Content -Raw $Script) -match "(?<!`r)`n") { + throw "$Script has LF line endings; cmd needs CRLF to resume after call :label" +} +$Script = (Resolve-Path $Script).Path + +# Read the long options out of the script itself, so this cannot go stale when +# an option is added. Field order is: add_arg <var> <type> <short> <long>. +$longFlags = @( + Select-String -Path $Script -Pattern '^call :add_arg \S+ \S+ \S+ (\S+) ' | + ForEach-Object { '--' + $_.Matches[0].Groups[1].Value } +) +if ($longFlags.Count -lt 20) { throw "only found $($longFlags.Count) options in $Script; the parser above is wrong" } + +# A winget that always fails, so the prerequisite failure path runs without +# touching the machine. It has to be an .exe: a .bat invoked without `call` +# transfers control and never comes back, which would end the script instead. +# where.exe returns 1 when its patterns match nothing and never prompts. +$fixtures = Join-Path ([IO.Path]::GetTempPath()) 'build_win_test_fixtures' +New-Item -ItemType Directory -Force -Path $fixtures | Out-Null +Copy-Item "$env:SystemRoot\System32\where.exe" (Join-Path $fixtures 'winget.exe') -Force +$stubPath = "$fixtures;C:\Windows\system32;C:\Windows" + +# Stand-in ninjas that only report a version, so the 1.12 boundary in the +# progress format can be exercised on a machine whose real ninja is newer. +# A dry run skips the dev shell, so PATH here is what the script sees. +$ninjaPaths = @{} +foreach ($v in @{ old = '1.11.1'; new = '1.12.0' }.GetEnumerator()) { + $d = Join-Path $fixtures "ninja-$($v.Key)" + New-Item -ItemType Directory -Force -Path $d | Out-Null + Set-Content -Path (Join-Path $d 'ninja.bat') -Encoding ascii -Value @('@echo off', "echo $($v.Value)") + $ninjaPaths[$v.Key] = "$d;$env:PATH" +} + +# The pack stamp is checked against real dates, so a locale-dependent parse +# in the script cannot pass by looking date-shaped. Yesterday is accepted too, +# so a run that crosses midnight does not flake. +$dateStamps = @((Get-Date -Format 'yyyyMMdd'), (Get-Date).AddDays(-1).ToString('yyyyMMdd')) +$stampPattern = '_(' + ($dateStamps -join '|') + ')\.zip$' + +$cases = @( + 'argument handling' + @{ Name = 'no arguments prints help'; Args = @(); DryRun = $false + Contains = @('Usage: build_win.bat [options]', '--clang-cl') } + @{ Name = "--help lists all $($longFlags.Count) options the script defines"; Args = @('--help'); DryRun = $false + Contains = $longFlags } + @{ Name = 'help is grouped and shows usage, examples and environment'; Args = @('--help'); DryRun = $false + Contains = @('Usage: build_win.bat [options]', 'Actions:', 'Build configuration:', 'Toolchain:', + 'How much gets rebuilt:', 'Paths and extra arguments:', 'Diagnostics:', + 'Examples:', 'Environment:') } + @{ Name = 'the environment section shows what to set'; Args = @('--help'); DryRun = $false + Contains = @('ORCA_DEPS_CMAKE_ARGS', 'ORCA_SLICER_CMAKE_ARGS', 'ORCA_UPDATER_SIG_KEY', 'NINJA_STATUS', + 'set ORCA_SLICER_CMAKE_ARGS=-DSLIC3R_PCH=OFF', '(PowerShell)', 'debugscript') } + @{ Name = 'section headers do not widen the flag column'; Args = @('--help'); DryRun = $false + Match = @('^ -d, --deps +Download') } + # Windows Terminal opens at 120 columns and wraps at 120, so 119 is the + # limit. Anyone still on the old conhost gets 80 and will see wrapping. + @{ Name = 'every help line fits a 120 column console'; Args = @('--help'); DryRun = $false + NotMatch = @('^.{120,}$') } + @{ Name = 'an unknown long option is rejected'; Args = @('--nonsense'); ExpectExit = 1 + Contains = @('Failed to find arg') } + @{ Name = 'an unknown short option is rejected'; Args = @('-Z'); ExpectExit = 1 + Contains = @('Failed to find arg') } + @{ Name = 'a bare argument is rejected'; Args = @('deps'); ExpectExit = 1 + Contains = @('Unknown argument') } + @{ Name = 'an unknown architecture is rejected'; Args = @('-d', '--arch', 'sparc'); ExpectExit = 1 + Contains = @('Unknown architecture') } + @{ Name = 'a string option without a value is rejected'; Args = @('-d', '--arch'); ExpectExit = 1 + Contains = @('requires a value') } + @{ Name = 'short options can be bundled'; Args = @('-dx') + Contains = @('-G "Ninja Multi-Config"', '--target deps') } + + 'generator and compiler selection' + @{ Name = 'deps default to the Visual Studio generator'; Args = @('-d') + Contains = @('-G "Visual Studio', '-A x64', '--target deps') + NotContains = @('Ninja', 'clang-cl') } + @{ Name = '-x selects Ninja without changing compiler'; Args = @('-d', '-x') + Contains = @('-G "Ninja Multi-Config"') + NotContains = @('clang-cl', '-A x64') } + @{ Name = '-l -x builds with clang-cl under Ninja'; Args = @('-d', '-l', '-x') + Contains = @('-G "Ninja Multi-Config"', '-DCMAKE_C_COMPILER=clang-cl.exe', '-DCMAKE_CXX_COMPILER=clang-cl.exe') } + @{ Name = '-l alone uses the ClangCL toolset on the VS generator'; Args = @('-d', '-l') + Contains = @('-G "Visual Studio', '-T ClangCL') + NotContains = @('-DCMAKE_C_COMPILER') } + # --msvc and --msbuild name the defaults, so a caller can be explicit and a + # contradictory pair can be caught rather than silently resolved. + @{ Name = '--msvc is the compiler default spelled out'; Args = @('-d', '--msvc') + Contains = @('-G "Visual Studio', '-A x64') + NotContains = @('clang-cl') } + @{ Name = '--msbuild is the generator default spelled out'; Args = @('-d', '--msbuild') + Contains = @('-G "Visual Studio') + NotContains = @('Ninja') } + @{ Name = '--msvc with -x gives Ninja driving cl'; Args = @('-d', '--msvc', '-x') + Contains = @('-G "Ninja Multi-Config"') + NotContains = @('clang-cl') } + @{ Name = '--msbuild with -l gives the VS generator and the ClangCL toolset'; Args = @('-d', '--msbuild', '-l') + Contains = @('-G "Visual Studio', '-T ClangCL') } + # A developer with a standalone LLVM points at it; the VS-bundled clang + # is what a bare clang-cl.exe resolves to after the dev shell runs. + @{ Name = '--clang-path names the compiler, quoted for its spaces'; Args = @('-d', '-x', '--clang-path', 'C:\Program Files\LLVM\bin\clang-cl.exe') + Contains = @('-DCMAKE_C_COMPILER="C:\Program Files\LLVM\bin\clang-cl.exe"', + '-DCMAKE_CXX_COMPILER="C:\Program Files\LLVM\bin\clang-cl.exe"') } + @{ Name = '--clang-path is a clang request on its own'; Args = @('-d', '-x', '--clang-path', 'C:\Program Files\LLVM\bin\clang-cl.exe') + Contains = @('deps/build-clang') } + @{ Name = '--clang-path needs Ninja to take effect'; Args = @('-d', '--clang-path', 'C:\Program Files\LLVM\bin\clang-cl.exe'); ExpectExit = 1 + Contains = @('needs the Ninja generator') } + # `exist` is true for a directory too, and a directory would reach CMake + # as the compiler. + @{ Name = '--clang-path must name the exe, not its folder'; Args = @('-d', '-x', '--clang-path', 'C:\Program Files\LLVM'); ExpectExit = 1 + Contains = @('is a directory') } + @{ Name = 'a clang-cl that is not there is caught early'; Args = @('-d', '-x', '--clang-path', 'C:\nope\clang-cl.exe'); ExpectExit = 1 + Contains = @('No clang-cl at') + NotContains = @('cmake -S deps') } + @{ Name = '--clang-path contradicting --msvc is rejected'; Args = @('-d', '-x', '--msvc', '--clang-path', 'C:\Program Files\LLVM\bin\clang-cl.exe'); ExpectExit = 1 + Contains = @('select different compilers') } + @{ Name = '--clang-cl and --msvc together are rejected'; Args = @('-d', '-l', '--msvc'); ExpectExit = 1 + Contains = @('select different compilers') } + @{ Name = '--ninja and --msbuild together are rejected'; Args = @('-d', '-x', '--msbuild'); ExpectExit = 1 + Contains = @('select different generators') } + # One option with a value, driven by a table, rather than a flag per + # release. Adding a release should not need a new flag. + @{ Name = '--vs 2019 pins that release and skips autodetect'; Args = @('-d', '--vs', '2019') + Contains = @('-G "Visual Studio 16 2019"') + NotContains = @('Detecting Visual Studio') } + @{ Name = '--vs 2022 pins that release'; Args = @('-d', '--vs', '2022') + Contains = @('-G "Visual Studio 17 2022"') } + @{ Name = '--vs 2026 pins that release'; Args = @('-d', '--vs', '2026') + Contains = @('-G "Visual Studio 18 2026"') } + @{ Name = 'an unknown release is rejected and the known ones listed'; Args = @('-d', '--vs', '2015'); ExpectExit = 1 + Contains = @('Unknown Visual Studio release', '2019, 2022, 2026') } + @{ Name = '--vs and --ninja together are rejected'; Args = @('-d', '--vs', '2022', '-x'); ExpectExit = 1 + Contains = @('select different generators') } + @{ Name = 'without --vs the release is autodetected'; Args = @('-d') + Contains = @('Detecting Visual Studio') } + + 'architecture' + @{ Name = 'x64 is the default'; Args = @('-d') + Contains = @('Configuration: Release, x64') + NotContains = @('build-arm64') } + @{ Name = 'arm64 sets the generator platform and deps tree'; Args = @('-d', '--arch', 'arm64') + Contains = @('-A ARM64', 'deps/build-arm64') } + @{ Name = 'the architecture is matched case-insensitively'; Args = @('-d', '--arch', 'ARM64') + Contains = @('-A ARM64', 'deps/build-arm64') } + @{ Name = 'arm64 under Ninja has no -A but keeps the arm64 tree'; Args = @('-d', '--arch', 'arm64', '-x', '-l') + Contains = @('deps/build-clang-arm64', '-DCMAKE_C_COMPILER=clang-cl.exe') + NotContains = @('-A ') } + + 'build configurations' + # One option with a value, driven by a table, so Release is named rather + # than being whatever is left when no flag is passed. + @{ Name = 'release is the default'; Args = @('-s') + Contains = @('-DCMAKE_BUILD_TYPE=Release', 'cmake -B "build" ') } + @{ Name = '--config release is the default spelled out'; Args = @('-s', '--config', 'release') + Contains = @('-DCMAKE_BUILD_TYPE=Release', 'cmake -B "build" ') } + @{ Name = '--config debug builds into build-dbg'; Args = @('-s', '--config', 'debug') + Contains = @('-DCMAKE_BUILD_TYPE=Debug', 'cmake -B "build-dbg" ') } + @{ Name = '--config relwithdebinfo builds into build-dbginfo'; Args = @('-s', '--config', 'relwithdebinfo') + Contains = @('-DCMAKE_BUILD_TYPE=RelWithDebInfo', 'cmake -B "build-dbginfo" ') } + @{ Name = '--config minsizerel builds into build-minsize'; Args = @('-s', '--config', 'minsizerel') + Contains = @('-DCMAKE_BUILD_TYPE=MinSizeRel', 'cmake -B "build-minsize" ') } + # Batch variable names are case-insensitive, so the table lookup is too. + @{ Name = 'the configuration name is matched case-insensitively'; Args = @('-s', '--config', 'RelWithDebInfo') + Contains = @('-DCMAKE_BUILD_TYPE=RelWithDebInfo') } + @{ Name = 'an unknown configuration is rejected and the known ones listed'; Args = @('-s', '--config', 'bogus'); ExpectExit = 1 + Contains = @('Unknown configuration', 'release, debug, relwithdebinfo, minsizerel') } + # Release, RelWithDebInfo and MinSizeRel all link the /MD dependencies, so + # one tree serves all three. Debug is /MDd and cannot share. + @{ Name = 'minsizerel builds against the release deps'; Args = @('-d', '-s', '--config', 'minsizerel') + Contains = @('cmake -S deps -B "deps/build"', 'cmake -B "build-minsize" ') + NotContains = @('deps/build-minsize') } + @{ Name = 'relwithdebinfo builds against them too'; Args = @('-d', '-s', '-l', '--config', 'relwithdebinfo') + Contains = @('cmake -S deps -B "deps/build-clang"', 'cmake -B "build-dbginfo-clang" ') + NotContains = @('deps/build-dbginfo') } + @{ Name = 'debug keeps a dependency tree of its own'; Args = @('-d', '--config', 'debug') + Contains = @('cmake -S deps -B "deps/build-dbg"') } + # The build tree and the deps tree now have different names, so the + # derivation from the binary directory name cannot work and it is named. + @{ Name = 'a shared deps tree is named outright'; Args = @('-s', '-l', '--config', 'relwithdebinfo') + Match = @('-DDEP_BUILD_DIR="[A-Za-z]:\\.*\\deps\\build-clang"') } + @{ Name = 'configuration and arch combine into build-dbg-arm64'; Args = @('-s', '--config', 'debug', '--arch', 'arm64') + Contains = @('cmake -B "build-dbg-arm64" ') } + + 'what gets built' + @{ Name = 'the deps target defaults to deps'; Args = @('-d') + Contains = @('--target deps') } + @{ Name = '-t overrides the deps target'; Args = @('-d', '-t', 'dep_Boost') + Contains = @('--target dep_Boost') } + @{ Name = 'unit tests are off unless asked for'; Args = @('-s') + Contains = @('-DBUILD_TESTS=OFF') } + @{ Name = '--tests turns the unit tests on'; Args = @('-s', '--tests') + Contains = @('-DBUILD_TESTS=ON') } + @{ Name = '-a enables ASAN for the slicer'; Args = @('-s', '-a') + Contains = @('-DSLIC3R_ASAN=ON') } + @{ Name = 'the slicer build runs gettext'; Args = @('-s') + Contains = @('run_gettext.bat') } + # tools\7z.exe needs a 7z.dll beside it, which the repo does not carry, + # so the pack falls back to the bsdtar Windows ships. Either is correct; + # what matters is that one is chosen and handed the right names. + @{ Name = '-p packs the deps tree with whichever archiver is usable'; Args = @('-d', '-p') + Match = @('^\+ .*(7z\.exe a|tar\.exe -a -c -f) OrcaSlicer_dep_win-\S+\.zip OrcaSlicer_dep$') } + # The bundle is only good for what built it, so it carries the same three + # axes as the tree. Release x64 on cl keeps the historical plain name. + @{ Name = 'the bundle name carries compiler and deps flavour'; Args = @('-p', '-l', '--config', 'debug', '--arch', 'arm64') + Contains = @('OrcaSlicer_dep_win-ARM64-clang-dbg_') } + @{ Name = 'a relwithdebinfo pack is the release bundle'; Args = @('-p', '--config', 'relwithdebinfo') + Contains = @('OrcaSlicer_dep_win-x64_') + NotContains = @('-dbg', 'dbginfo') } + @{ Name = 'a plain release bundle keeps its old name'; Args = @('-p') + Contains = @('OrcaSlicer_dep_win-x64_') + NotContains = @('-clang', '-Release') } + @{ Name = 'the bundle is stamped with today, not a shuffled date'; Args = @('-p') + Match = @($stampPattern) } + # powershell.exe is not in System32 itself, so a trimmed PATH used to + # leave the stamp empty and the bundle named OrcaSlicer_dep_win-x64_.zip. + @{ Name = 'the bundle is stamped even with a bare PATH'; Args = @('-p') + Env = @{ PATH = 'C:\Windows\system32;C:\Windows' } + Match = @($stampPattern) } + @{ Name = '-p packs without rebuilding'; Args = @('-p') + Match = @('^\+ .*(7z\.exe a|tar\.exe -a -c -f) ') + NotContains = @('cmake -S deps') } + @{ Name = 'deps and slicer build in one invocation'; Args = @('-d', '-s', '-x', '-l') + Contains = @('cmake -S deps', 'cmake -B "build-clang" ') } + + 'the developer loop' + @{ Name = '--slicer-target builds one target'; Args = @('-s', '--slicer-target', 'libslic3r') + Contains = @('--config Release --target libslic3r') } + @{ Name = '--no-configure skips the slicer configure'; Args = @('-s', '--no-configure') + Contains = @('cmake --build "build"') + NotContains = @('cmake -B "build" ') } + @{ Name = '--no-configure skips the deps configure'; Args = @('-d', '--no-configure') + Contains = @('cmake --build "deps/build"') + NotContains = @('cmake -S deps') } + @{ Name = '--no-gettext skips the translation step'; Args = @('-s', '--no-gettext') + Contains = @('cmake --build "build"') + NotContains = @('run_gettext') } + # Installing copies the whole tree again for a layout only releases need, + # so it is asked for rather than assumed. + @{ Name = 'nothing is installed unless asked'; Args = @('-s') + Contains = @('run_gettext') + NotContains = @('--target install') } + @{ Name = '-i adds the install step'; Args = @('-s', '-i') + Contains = @('--target install') } + # install(TARGETS OrcaSlicer) has no OPTIONAL, so this would fail partway + # through a build instead of before it. + @{ Name = 'installing a tree with no executable is refused'; Args = @('-s', '-i', '--slicer-target', 'glad'); ExpectExit = 1 + Contains = @('--install needs the executable') + NotContains = @('cmake --build') } + # Without -s there is no install step, so there is nothing to refuse. + @{ Name = 'the same flags without a slicer build are left alone'; Args = @('-d', '-i', '--slicer-target', 'glad') + Contains = @('cmake -S deps') + NotContains = @('--install needs the executable') } + @{ Name = 'naming the executable target is allowed'; Args = @('-s', '-i', '--slicer-target', 'OrcaSlicer') + Contains = @('--target install') } + # Ninja counts compilers, so -j goes on the command line. MSBuild's -j + # counts projects while /MP still runs one cl per core inside each, so the + # cap goes to CL_MPCount in the environment instead. A dry run can only + # show that no -j is passed. + @{ Name = '-j on Ninja passes -j to cmake'; Args = @('-s', '-x', '-j', '4') + Contains = @('Parallel jobs: 4', '--config Release -j 4') } + @{ Name = '-j on Ninja reaches the deps build'; Args = @('-d', '-x', '-j', '2') + Contains = @('--target deps -j 2') } + @{ Name = '-j on MSBuild does not pass -j, which would count projects'; Args = @('-s', '-j', '4') + Contains = @('Parallel jobs: 4') + NotContains = @('-j 4') } + @{ Name = '-j on MSBuild leaves the deps build without -j too'; Args = @('-d', '-j', '2') + Contains = @('--target deps') + NotContains = @('-j 2') } + @{ Name = 'no -j means no job limit'; Args = @('-s') + NotContains = @('parallel jobs', '-j ') } + @{ Name = 'a non-numeric -j is rejected'; Args = @('-s', '-j', 'abc'); ExpectExit = 1 + Contains = @('Invalid --jobs value') } + @{ Name = 'a zero -j is rejected'; Args = @('-s', '-j', '0'); ExpectExit = 1 + Contains = @('Invalid --jobs value') } + @{ Name = 'the loop options combine into a single build command'; Args = @('-s', '-x', '--no-configure', '--no-gettext', '--slicer-target', 'libslic3r_tests', '-j', '8') + Contains = @('--target libslic3r_tests -j 8') + NotContains = @('cmake -B "build" ', 'run_gettext', '--target install') } + + 'one tree per configuration, compiler and architecture' + # CMake resets its cache and carries on when the compiler changes under an + # existing tree, leaving stamps from the old toolchain. Give each its own. + @{ Name = 'clang builds land in their own trees'; Args = @('-d', '-s', '-l') + Contains = @('cmake -S deps -B "deps/build-clang"', 'cmake -B "build-clang" ') } + @{ Name = 'MSVC keeps the historical plain names'; Args = @('-d', '-s', '--msvc') + Contains = @('cmake -S deps -B "deps/build"', 'cmake -B "build" ') + NotContains = @('build-clang') } + @{ Name = 'configuration, compiler and arch all name the tree'; Args = @('-d', '-s', '-l', '--config', 'debug', '--arch', 'arm64') + Contains = @('cmake -S deps -B "deps/build-dbg-clang-arm64"', 'cmake -B "build-dbg-clang-arm64" ') } + + 'locating the dependency tree' + # Without --deps-dir nothing is passed, so CMakeLists derives the path from + # the binary directory name as it always has. + @{ Name = 'the deps path is left to CMake by default'; Args = @('-s') + NotContains = @('-DDEP_BUILD_DIR') } + @{ Name = '--deps-dir tells the slicer where the deps are'; Args = @('-s', '--deps-dir', 'D:\orca-deps') + Contains = @('-DDEP_BUILD_DIR="D:\orca-deps"') } + @{ Name = '--deps-dir also redirects the deps build'; Args = @('-d', '--deps-dir', 'D:\orca-deps') + Contains = @('cmake -S deps -B "D:\orca-deps"', 'cmake --build "D:\orca-deps"') + NotContains = @('deps/build') } + # Paths are quoted throughout, so one with spaces survives the whole run. + @{ Name = 'a deps path with spaces survives'; Args = @('-d', '-s', '--deps-dir', 'C:\Program Files\deps') + Contains = @('-B "C:\Program Files\deps"', '-DDEP_BUILD_DIR="C:\Program Files\deps"') } + @{ Name = '--deps-dir also redirects the pack'; Args = @('-p', '--deps-dir', 'D:\orca-deps') + Contains = @('cd /d "D:\orca-deps"') } + @{ Name = 'pack uses an absolute default path'; Args = @('-p') + Match = @('^\+ cd /d "[A-Za-z]:\\.*\\deps\\build"') } + # CMakeLists derives DEP_BUILD_DIR from the build directory's name, so + # pointing the build elsewhere has to name the deps tree outright. + @{ Name = '--build-dir moves the slicer build'; Args = @('-s', '-l', '-x', '--build-dir', 'out/build/x64-clang') + Contains = @('cmake -B "out/build/x64-clang" ') } + @{ Name = '--build-dir still names the deps tree'; Args = @('-s', '-l', '-x', '--build-dir', 'out/build/x64-clang') + Match = @('-DDEP_BUILD_DIR="[A-Za-z]:\\.*\\deps\\build-clang"') } + @{ Name = '--deps-dir wins over the derived tree'; Args = @('-s', '--build-dir', 'out/build/x64-clang', '--deps-dir', 'D:\orca-deps') + Contains = @('-DDEP_BUILD_DIR="D:\orca-deps"') } + # A value ending in a backslash escapes the closing quote it is spliced + # into, so cmake would receive D:\tree" and swallow the next argument. + @{ Name = 'a trailing backslash is trimmed off a path'; Args = @('-s', '--build-dir', 'D:\tree\') + Contains = @('cmake -B "D:\tree" ') } + @{ Name = 'a build directory with spaces survives'; Args = @('-s', '--build-dir', 'C:\Program Files\tree') + Contains = @('cmake -B "C:\Program Files\tree" ') } + @{ Name = 'the default build names no deps tree'; Args = @('-s') + NotContains = @('DEP_BUILD_DIR') } + + 'saying what mode and toolchain are in play' + @{ Name = 'a dry run announces itself before the first command'; Args = @('-u') + First = '^Dry run: printing commands without running them\.$' } + @{ Name = 'the announcement leads even a full build'; Args = @('-ds') + First = '^Dry run: ' } + # Autodetect only runs for the Visual Studio generator, and only when no + # release was pinned, so it needs a Visual Studio on the machine. + @{ Name = 'the detected Visual Studio names its release year'; Args = @('-s') + Match = @('^Detected Visual Studio \d+ \(20\d\d\)$') } + @{ Name = 'pinning a release skips detection'; Args = @('-s', '--vs', '2022') + NotContains = @('Detected Visual Studio') } + + 'an action has to be asked for' + # Neither can happen without building the slicer, so they stand alone the + # way --install-vs does. + @{ Name = '--run-tests is an action on its own'; Args = @('--run-tests') + Contains = @('-DBUILD_TESTS=ON', 'ctest --test-dir') + NotContains = @('Nothing to do') } + @{ Name = '--tests is too'; Args = @('--tests') + Contains = @('-DBUILD_TESTS=ON') + NotContains = @('Nothing to do', 'ctest --test-dir') } + # Naming an action means that action, not a fuller build. + @{ Name = 'they do not add a slicer build to one already asked for'; Args = @('-d', '--tests') + Contains = @('cmake -S deps') + NotContains = @('cmake -B "build"') } + @{ Name = 'shaping options alone are not an action'; Args = @('--config', 'debug'); ExpectExit = 1 + Contains = @('Nothing to do.') + NotContains = @('Build completed') } + @{ Name = '-j alone is not an action either'; Args = @('-j', '4'); ExpectExit = 1 + Contains = @('Nothing to do.') } + @{ Name = '--install-vs counts as an action on its own'; Args = @('--install-vs', 'ide') + NotContains = @('Nothing to do.') } + + 'diagnostics' + @{ Name = '-v asks cmake for the command lines'; Args = @('-s', '-v') + Contains = @('--verbose') } + @{ Name = '-v applies to the deps build too'; Args = @('-d', '-v') + Contains = @('--target deps', '--verbose') } + # ninja's own default shows neither a percentage nor a time. %w and %W + # need ninja 1.12, and an unknown placeholder is fatal, so the format is + # chosen from the version rather than hardcoded. + @{ Name = '-v names the ninja progress format'; Args = @('-s', '-x', '-v') + Match = @('^Ninja progress format: \[.*%p.*\]') } + @{ Name = 'a ninja older than 1.12 gets the format it understands'; Args = @('-s', '-x', '-v') + Env = @{ PATH = $ninjaPaths['old'] } + Contains = @('Ninja progress format: [%s/%t %p :: %e]') } + @{ Name = 'ninja 1.12 gets elapsed and remaining'; Args = @('-s', '-x', '-v') + Env = @{ PATH = $ninjaPaths['new'] } + Contains = @('Ninja progress format: [%f/%t %p :: %w / %W]') } + @{ Name = 'a format you set yourself is left alone'; Args = @('-s', '-x', '-v') + Env = @{ NINJA_STATUS = '[mine] ' } + Contains = @('Ninja progress format: [mine]') } + @{ Name = 'MSBuild builds mention no ninja format'; Args = @('-s', '-v') + NotContains = @('Ninja progress format') } + @{ Name = 'builds are quiet without -v'; Args = @('-s') + NotContains = @('--verbose') } + + 'installing prerequisites' + # -u installs CMake, Perl and Git. Visual Studio is a separate ask, because + # most people already have it, and which one you want is a real choice. + @{ Name = '-u alone installs no Visual Studio'; Args = @('-u') + Contains = @('Kitware.CMake', 'StrawberryPerl', 'Git.Git') + NotContains = @('Microsoft.VisualStudio') } + # Asking for Visual Studio is asking to install prerequisites, so it does + # not also need -u; requiring both meant --install-vs alone did nothing. + @{ Name = '--install-vs works without -u'; Args = @('--install-vs', 'ide') + Contains = @('id=Microsoft.VisualStudio.Community', 'Kitware.CMake', 'Git.Git') } + @{ Name = '--install-vs buildtools asks for the build tools'; Args = @('-u', '--install-vs', 'buildtools') + Contains = @('id=Microsoft.VisualStudio.BuildTools') + NotContains = @('VC.CoreIde') } + @{ Name = '--install-vs ide asks for Community with the IDE component'; Args = @('-u', '--install-vs', 'ide') + Contains = @('id=Microsoft.VisualStudio.Community', 'VC.CoreIde') } + @{ Name = 'an unknown edition is rejected and the known ones listed'; Args = @('-u', '--install-vs', 'bogus'); ExpectExit = 1 + Contains = @('Unknown Visual Studio edition', 'buildtools, ide') } + @{ Name = '--vs picks which release to install'; Args = @('-u', '--vs', '2022', '--install-vs', 'buildtools') + Contains = @('id=Microsoft.VisualStudio.2022.BuildTools') } + @{ Name = '-l adds the clang compiler and the MSBuild toolset'; Args = @('-u', '--install-vs', 'buildtools', '-l') + Contains = @('VC.Llvm.Clang ', 'VC.Llvm.ClangToolset') } + # CMake 4.x breaks Boost.Context on ARM64, so the installer pins 3.31 there + # and leaves x64 on the current release. + @{ Name = 'CMake is pinned to 3.31 when installing for arm64'; Args = @('-u', '--arch', 'arm64') + Contains = @('Kitware.CMake --version 3.31.8') } + @{ Name = 'CMake is not pinned for x64'; Args = @('-u', '--arch', 'x64') + Contains = @('Kitware.CMake') + NotContains = @('--version') } + @{ Name = 'installing for arm64 asks for the ARM64 toolset'; Args = @('--install-vs', 'buildtools', '--arch', 'arm64') + Contains = @('Microsoft.VisualStudio.Component.VC.Tools.ARM64') } + @{ Name = 'an x64 install asks only for the x64 toolset'; Args = @('--install-vs', 'buildtools') + Contains = @('Microsoft.VisualStudio.Component.VC.Tools.x86.x64') + NotContains = @('VC.Tools.ARM64') } + + 'dry run changes nothing' + # clean_tree resolves the path before removing it, so the line echoed is + # absolute. It is the last thing printed before a directory goes. + @{ Name = '-c echoes the deps rmdir rather than running it'; Args = @('-d', '-c') + Match = @('^\+ rmdir /S /Q "[A-Za-z]:\\.*\\deps\\build"$') } + @{ Name = '-c removes the tree --deps-dir named, not the default one'; Args = @('-d', '-c', '--deps-dir', 'D:\orca-deps') + Match = @('^\+ rmdir /S /Q "D:\\orca-deps"$') + NotContains = @('\deps\build') } + @{ Name = '-c echoes the slicer rmdir rather than running it'; Args = @('-s', '-c') + Match = @('^\+ rmdir /S /Q "[A-Za-z]:\\.*\\build"$') } + @{ Name = 'cleaning a slicer build leaves the deps tree alone'; Args = @('-s', '-c') + NotMatch = @('rmdir.*\\deps\\') } + @{ Name = 'cleaning both builds removes both trees'; Args = @('-d', '-s', '-c') + Match = @('^\+ rmdir /S /Q "[A-Za-z]:\\[^"]*\\deps\\build"$', + '^\+ rmdir /S /Q "[A-Za-z]:\\(?!.*\\deps\\)[^"]*\\build"$') } + + # Nothing below should be reachable. They are a floor under a bug that + # hands clean_tree a path far shorter than it looks. + @{ Name = 'a configuration whose lookup comes back empty is rejected'; Args = @('-d', '-c', '--config', 'release '); ExpectExit = 1 + Contains = @('Unknown configuration') + NotContains = @('rmdir') } + @{ Name = 'a drive root is refused'; Args = @('-d', '-c', '--deps-dir', 'D:\'); ExpectExit = 1 + Contains = @('that is a drive root') + NotContains = @('+ rmdir') } + @{ Name = 'the repository itself is refused'; Args = @('-d', '-c', '--deps-dir', '.'); ExpectExit = 1 + Contains = @('that is the repository itself') + NotContains = @('+ rmdir') } + @{ Name = '-k echoes the taskkills rather than running them'; Args = @('-k') + Contains = @('+ taskkill /F /IM MSBuild.exe', '+ taskkill /F /IM cl.exe') } + @{ Name = '-k also covers the Ninja toolchain'; Args = @('-k') + Contains = @('+ taskkill /F /IM ninja.exe', '+ taskkill /F /IM clang-cl.exe') } + @{ Name = '-k announces the dry run like every other action'; Args = @('-k') + First = '^Dry run: ' } + @{ Name = '-u echoes the winget installs rather than running them'; Args = @('-u') + Contains = @('+ winget install', 'Kitware.CMake') + NotContains = @('cmake -S deps') } + # Not a dry run: winget is a stub that fails, so nothing is installed. + @{ Name = 'a failed install is reported, not claimed as success'; Args = @('-u') + DryRun = $false; ExpectExit = 1 + Env = @{ PATH = $stubPath } + Contains = @('Failed to install:', 'CMake', 'Perl', 'Git') + NotContains = @('Installed the prerequisites') } + # The reason belongs inside the frame. Every command this path ran had + # already succeeded, so naming the last one would point at the wrong thing. + @{ Name = 'a failed install names the reason, not the last command'; Args = @('-u') + DryRun = $false; ExpectExit = 1 + Env = @{ PATH = $stubPath } + Contains = @('####', 'Failed to install:') + NotContains = @('Failed: winget') } + @{ Name = 'a dry run does not claim the install happened'; Args = @('-u') + Contains = @('Dry run: nothing was installed.') + NotContains = @('are in place') } + @{ Name = '-u with a build defers that build, not a fuller one'; Args = @('-u', '-d') + Contains = @('build_win.bat -d') + NotContains = @('build_win.bat -ds') } + @{ Name = '-u on its own suggests the whole build'; Args = @('-u') + Contains = @('build_win.bat -ds') } + @{ Name = 'a dry run only echoes, it never configures'; Args = @('-d') + Contains = @('+ cmake') + NotContains = @('CMake Error', 'Configuring done') } + + 'extra configure arguments' + # --deps-args and --slicer-args are declared "rawstring", so a value that + # looks like an option is allowed through. Plain string options still + # reject one, since there it almost always means a forgotten value. + @{ Name = '--deps-args reaches the deps configure'; Args = @('-d', '--deps-args', 'FOO') + Contains = @('-DCMAKE_BUILD_TYPE=Release FOO') } + @{ Name = '--slicer-args reaches the slicer configure'; Args = @('-s', '--slicer-args', 'BAZ') + Contains = @('BAZ') } + @{ Name = '--deps-args accepts a value that starts with a dash'; Args = @('-d', '--deps-args', '-DFOO') + Contains = @('-DFOO') } + @{ Name = 'a plain string option still rejects a dash-leading value'; Args = @('-d', '--deps-target', '--tests'); ExpectExit = 1 + Contains = @('looks like another option') } + # cmd splits arguments on "=" as well as spaces, so an unquoted -D reaches + # the script as two arguments however it was invoked. + @{ Name = 'an unquoted value containing = is rejected'; Args = @('-d', '--deps-args', 'FOO=BAR'); ExpectExit = 1 + Contains = @('Unknown argument') } + # The environment overrides exist for that reason; nothing tokenises them. + @{ Name = 'ORCA_DEPS_CMAKE_ARGS reaches the deps configure'; Args = @('-d') + Env = @{ ORCA_DEPS_CMAKE_ARGS = '-DFOO=BAR -DBAZ=QUX' } + Contains = @('-DFOO=BAR -DBAZ=QUX') } + @{ Name = 'ORCA_SLICER_CMAKE_ARGS reaches the slicer configure'; Args = @('-s') + Env = @{ ORCA_SLICER_CMAKE_ARGS = '-DWANTED=1' } + Contains = @('-DWANTED=1') } + @{ Name = 'the deps override does not leak into the slicer configure'; Args = @('-s') + Env = @{ ORCA_DEPS_CMAKE_ARGS = '-DDEPSONLY=1' } + NotContains = @('-DDEPSONLY=1') } + @{ Name = 'the help points at the environment for a spaced argument'; Args = @('--help'); DryRun = $false + Contains = @('Neither form supports a value containing an ampersand') } + @{ Name = 'the help lists the environment overrides'; Args = @('--help'); DryRun = $false + Contains = @('Environment:', 'ORCA_DEPS_CMAKE_ARGS', 'ORCA_SLICER_CMAKE_ARGS') } + + 'running the unit tests' + @{ Name = '--tests builds them without running them'; Args = @('-s', '--tests') + Contains = @('-DBUILD_TESTS=ON') + NotContains = @('ctest') } + @{ Name = '--run-tests builds and runs them'; Args = @('-s', '--run-tests') + Contains = @('-DBUILD_TESTS=ON', 'ctest --test-dir "build/tests" -C Release --output-on-failure') } + @{ Name = '--run-tests follows the build type and directory'; Args = @('-s', '--run-tests', '--config', 'debug') + Contains = @('ctest --test-dir "build-dbg/tests" -C Debug') } + @{ Name = 'no tests are run by default'; Args = @('-s') + NotContains = @('ctest') } + + 'failures are reported' + @{ Name = 'a missing cmake is caught and exits non-zero'; Args = @('-d'); ExpectExit = 1 + Env = @{ PATH = 'C:\Windows\system32;C:\Windows' } + Contains = @('CMake was not found') } + @{ Name = 'packing does not need cmake, only an archiver'; Args = @('-p') + Env = @{ PATH = 'C:\Windows\system32;C:\Windows' } + NotContains = @('CMake was not found') } + # Not a dry run: a cd to a missing drive is a real failure inside a + # parenthesised block, which is where exit /b silently loses its code. + # Without the jump to :die this exits 0 and a failed build reads as a + # successful one. + @{ Name = 'a failure inside a build block reaches the caller'; Args = @('-p', '--deps-dir', 'Z:\nope') + DryRun = $false; ExpectExit = 1 + Contains = @('Exit code 1.', '####') + NotContains = @('Build completed', 'Try') } + # The retry follows the stage that failed. Offering it for the whole run + # would clean a dependency tree that was not at fault. + @{ Name = 'a failure names a retry scoped to the stage that failed'; Args = @('-d', '-s', '--deps-dir', 'Z:\nope') + DryRun = $false; ExpectExit = 1 + Contains = @('build_win.bat -d --deps-dir "Z:\nope" -c') + NotContains = @('build_win.bat -ds') } + # CMake's own failure here is hundreds of lines about package resolution. + @{ Name = 'a missing dependency tree is named, not left to CMake'; Args = @('-s', '--deps-dir', 'Z:\nope') + DryRun = $false; ExpectExit = 1 + Contains = @('Dependencies not found at', 'Build them with build_win.bat -d --deps-dir "Z:\nope"') + NotContains = @('cmake -B', 'Try') } + # Every other suggestion carries the flags that reproduce the run; a bare + # -d would point at the MSVC tree after a clang build. + @{ Name = 'the missing-deps hint names this toolchain'; Args = @('-s', '-l', '-x', '--deps-dir', 'deps/not-built') + DryRun = $false; ExpectExit = 1 + Contains = @('Build them with build_win.bat -d -l -x --deps-dir "deps/not-built"') + NotExists = @('deps/not-built') } + # A dry run configures nothing, so it must not depend on which trees happen + # to exist on the machine running the suite. + @{ Name = 'a dry run does not check for the deps tree'; Args = @('-s', '--deps-dir', 'Z:\nope') + Contains = @('cmake -B "build"') + NotContains = @('Dependencies not found') } + # -d is about to build them, so there is nothing to report yet. + @{ Name = 'building the deps in the same run skips the check'; Args = @('-d', '-s', '--deps-dir', 'Z:\nope') + DryRun = $false; ExpectExit = 1 + NotContains = @('Dependencies not found') } + # A configure fails before any compiler runs, so -v has nothing to show. + @{ Name = 'a configure failure is not offered a verbose rebuild'; Args = @('-d', '--deps-dir', 'Z:\nope') + DryRun = $false; ExpectExit = 1 + Contains = @('-c discard that tree') + NotContains = @('-v show the failing') } + # A bare --no-configure succeeds on a machine that already has a usable + # build tree, so name one that cannot exist instead. + @{ Name = 'a build failure is'; Args = @('-s', '--no-configure', '--build-dir', 'deps/no-such-tree') + DryRun = $false; ExpectExit = 1 + Contains = @('-v show the failing') + NotExists = @('deps/no-such-tree') } + # --build-dir names the slicer tree, which a deps failure has nothing to do + # with. --deps-dir stays, because that is the tree that failed. + @{ Name = 'a deps retry leaves out the slicer tree'; Args = @('-d', '-s', '--deps-dir', 'Z:\nope', '--build-dir', 'D:\b') + DryRun = $false; ExpectExit = 1 + Contains = @('build_win.bat -d --deps-dir "Z:\nope" -c') + NotContains = @('--build-dir') } + @{ Name = 'an unknown configuration stays a single line'; Args = @('-s', '--config', 'bogus'); ExpectExit = 1 + Contains = @('Unknown configuration') + NotContains = @('####', 'Try') } + @{ Name = 'a bad --jobs value is not framed either'; Args = @('-s', '-j', 'x'); ExpectExit = 1 + Contains = @('Invalid --jobs value') + NotContains = @('####') } + + 'the summary says what to do next' + # Every suggested command carries the flags that reproduce this run. + @{ Name = 'a deps build points at the slicer build'; Args = @('-d', '-l') + Contains = @('Build the slicer build_win.bat -s -l') + NotContains = @('Run it') } + @{ Name = 'a ninja slicer build offers a single target'; Args = @('-s', '-l', '-x') + Contains = @('Rebuild after edits build_win.bat -s -l -x --no-configure', 'Rebuild one target') + NotContains = @('Solution', 'Open in Visual Studio') } + @{ Name = 'a visual studio build names the solution instead'; Args = @('-s') + Contains = @('Solution ', 'Open in Visual Studio build\OrcaSlicer.sln', + 'Rebuild after edits build_win.bat -s --no-configure') + NotContains = @('Rebuild one target') } + @{ Name = 'the configuration and architecture come back'; Args = @('-s', '-l', '-x', '--config', 'debug', '--arch', 'arm64') + Contains = @('build_win.bat -s -l -x --config debug --arch arm64 --no-configure') } + @{ Name = 'the tree overrides come back quoted'; Args = @('-s', '--deps-dir', 'D:\d', '--build-dir', 'D:\b') + Contains = @('--deps-dir "D:\d" --build-dir "D:\b"') } + @{ Name = 'a pinned visual studio release comes back'; Args = @('-s', '--vs', '2022') + Contains = @('build_win.bat -s --vs 2022 --no-configure') } + # Autodetection writes what it found into the same variable, so a detected + # release must not come back as though it had been asked for. + @{ Name = 'a detected release does not'; Args = @('-s') + NotContains = @('--vs') } + @{ Name = 'the binary is named in the build tree it was built in'; Args = @('-s', '-l', '-x') + Contains = @('build-clang\src\Release\orca-slicer.exe') } + @{ Name = 'installing names the installed copy instead'; Args = @('-s', '-l', '-x', '-i') + Contains = @('build-clang\OrcaSlicer\orca-slicer.exe') } + # -i changes where the binary lands, so a rebuild that dropped it would + # leave the path above pointing at a stale copy. + @{ Name = 'the rebuild suggestion keeps -i'; Args = @('-s', '-l', '-x', '-i') + Contains = @('Rebuild after edits build_win.bat -s -l -x -i --no-configure') } + # A deps retry has no install step to repeat. + @{ Name = 'a deps retry drops it'; Args = @('-d', '-s', '-i', '--deps-dir', 'Z:\nope') + DryRun = $false; ExpectExit = 1 + Contains = @('build_win.bat -d --deps-dir "Z:\nope" -c') + NotContains = @('-d -i') } + # Naming a target builds it and its dependencies, not its dependents, so + # the binary on disk is whatever the last full build left there. + @{ Name = 'a single-target build does not claim the whole binary'; Args = @('-s', '-l', '-x', '--slicer-target', 'glad') + Contains = @('Target glad', 'Relink the binary build_win.bat -s -l -x --no-configure') + NotContains = @('Run it', 'orca-slicer.exe', 'Rebuild after edits') } + # The executable has a target of its own, and naming that one does relink. + @{ Name = 'naming the executable target still claims the binary'; Args = @('-s', '-l', '-x', '--slicer-target', 'OrcaSlicer') + Contains = @('Run it', 'orca-slicer.exe', 'Rebuild after edits') + NotContains = @('Target OrcaSlicer', 'Relink the binary') } + @{ Name = '--run-tests offers the ctest line'; Args = @('-s', '-l', '-x', '--run-tests') + Contains = @('Re-run the tests ctest --test-dir build-clang/tests -C Release') } + @{ Name = 'packing names the bundle and how to use it'; Args = @('-p', '-l') + Contains = @('Bundle ', 'Share the bundle') } + # The line supplies its own tree, so the one this run used must not ride + # along and contradict it. + @{ Name = 'the bundle line names one tree, not two'; Args = @('-s', '-p', '-l', '-x', '--deps-dir', 'D:\shared') + Contains = @('then build_win.bat -s -l -x --deps-dir <path>') + NotContains = @('--deps-dir "D:\shared" --deps-dir') } + @{ Name = 'installing prerequisites suggests the build that follows'; Args = @('-u', '-l') + Contains = @('Restart this shell', 'build_win.bat -ds -l') + NotContains = @('Run it') } + # Everything below the header line is worked out the same way in either + # run, which is why a dry run can cover it. + @{ Name = 'a dry run does not claim a build happened'; Args = @('-s', '-l', '-x') + Contains = @('Dry run: nothing was built.') + NotContains = @('Build completed in') } + # --no-configure is the iteration loop and still gets the block; four + # lines after a rebuild is not enough to be worth suppressing. + @{ Name = '--no-configure still gets the summary'; Args = @('-s', '-l', '-x', '--no-configure') + Contains = @('Next', 'Rebuild after edits') } + + 'pointing at the solution' + @{ Name = 'the VS generator says where the solution is'; Args = @('-s') + Match = @('^ Solution .*\\build\\OrcaSlicer\.sln$') } + @{ Name = 'the solution path follows the configuration'; Args = @('-s', '--config', 'debug') + Match = @('^ Solution .*\\build-dbg\\OrcaSlicer\.sln$') } + @{ Name = 'the solution line survives an install'; Args = @('-s', '-i') + Contains = @(' Solution ') } + # The path is resolved, not pasted onto the repository root, so it is + # right whether --build-dir came absolute or with forward slashes. + @{ Name = 'a moved build still prints one real path'; Args = @('-s', '--build-dir', 'out/build/x64-clang') + Match = @('^ Solution [A-Za-z]:\\[^/]+\\OrcaSlicer\.sln$') } + @{ Name = 'an absolute --build-dir is not glued onto the repo root'; Args = @('-s', '--build-dir', 'D:\tree') + Contains = @('Solution D:\tree\OrcaSlicer.sln') } +) + +function Invoke-BuildScript { + param([string[]] $Arguments, [hashtable] $Environment) + + $saved = @{} + if ($Environment) { + foreach ($key in $Environment.Keys) { + $saved[$key] = [Environment]::GetEnvironmentVariable($key) + Set-Item -Path "env:$key" -Value $Environment[$key] + } + } + try { + # 'Stop' turns a native command's stderr into a terminating error, and + # a case that exercises a real failure writes to stderr. Let the output + # through and judge the run by its exit code instead. The assignment is + # scoped to this function, so the rest of the suite keeps 'Stop'. + $ErrorActionPreference = 'Continue' + if ($Arguments.Count -eq 0) { + $out = & $Script 2>&1 | Out-String + } else { + $out = & $Script @Arguments 2>&1 | Out-String + } + return [pscustomobject]@{ Output = $out; Exit = $LASTEXITCODE } + } finally { + foreach ($key in $saved.Keys) { + if ($null -eq $saved[$key]) { Remove-Item -Path "env:$key" -ErrorAction SilentlyContinue } + else { Set-Item -Path "env:$key" -Value $saved[$key] } + } + } +} + +$knownFields = @( + 'Name', 'Args', 'ExpectExit', 'DryRun', 'First', 'Env', + 'Contains', 'NotContains', 'Match', 'NotMatch', 'NotExists' +) + +function Test-Case { + param([hashtable] $Case) + + # Read fields with the indexer, not dot notation. A hashtable exposes its + # own members too, so $Case.Contains returns the Contains *method* whenever + # the case has no key by that name. + $argv = @($Case['Args']) + if (-not $Case.ContainsKey('DryRun') -or $Case['DryRun']) { $argv += '--dry-run' } + + $expect = 0 + if ($Case.ContainsKey('ExpectExit')) { $expect = $Case['ExpectExit'] } + + $result = Invoke-BuildScript -Arguments $argv -Environment $Case['Env'] + + $problems = @() + + # A misspelled field is silently ignored by the checks below, which + # leaves the case asserting nothing at all and passing. + foreach ($field in $Case.Keys) { + if ($knownFields -notcontains $field) { $problems += "unknown field '$field'" } + } + + if ($result.Exit -ne $expect) { $problems += "exit $($result.Exit), expected $expect" } + foreach ($needle in $Case['Contains']) { + if (-not $result.Output.Contains($needle)) { $problems += "missing '$needle'" } + } + foreach ($needle in $Case['NotContains']) { + if ($result.Output.Contains($needle)) { $problems += "unexpected '$needle'" } + } + $lines = $result.Output -split "`r?`n" + if ($Case['First'] -and $lines[0] -notmatch $Case['First']) { + $problems += "first line was '$($lines[0])'" + } + foreach ($pattern in $Case['Match']) { + if (@($lines | Where-Object { $_ -match $pattern }).Count -eq 0) { + $problems += "no line matching /$pattern/" + } + } + foreach ($pattern in $Case['NotMatch']) { + foreach ($line in @($lines | Where-Object { $_ -match $pattern })) { + $problems += "line matches /$pattern/: $line" + } + } + # Output cannot show what a run did not create. + foreach ($path in $Case['NotExists']) { + $full = Join-Path (Split-Path -Parent $Script) $path + if (Test-Path $full) { + $problems += "created '$path'" + } + } + return ,$problems +} + +$pass = 0 +$failed = @() +# Held back so a filtered run does not print headings for groups it skipped. +$heading = $null + +foreach ($case in $cases) { + if ($case -is [string]) { + $heading = $case + continue + } + if ($Name -and $case['Name'] -notmatch $Name) { continue } + if ($heading) { + Write-Host '' + Write-Host $heading -ForegroundColor Cyan + $heading = $null + } + + $problems = Test-Case -Case $case + if ($problems.Count -eq 0) { + $pass++ + Write-Host (' ok ' + $case['Name']) + } else { + $failed += $case['Name'] + Write-Host (' FAIL ' + $case['Name']) -ForegroundColor Red + foreach ($problem in $problems) { Write-Host (' ' + $problem) -ForegroundColor Red } + Write-Host (' args: ' + (@($case['Args']) -join ' ')) + } +} + +Remove-Item -Recurse -Force $fixtures -ErrorAction SilentlyContinue + +Write-Host '' +# A pattern that matched nothing has proved nothing, so do not report it as +# a clean run. +if ($Name -and $pass -eq 0 -and $failed.Count -eq 0) { + Write-Host "no case matched /$Name/" -ForegroundColor Red + exit 1 +} +Write-Host "$pass passed, $($failed.Count) failed" +if ($failed.Count -gt 0) { + foreach ($name in $failed) { Write-Host " failed: $name" -ForegroundColor Red } + exit 1 +} +exit 0 From 918d3914ba40d7db638115e31beef54dc867e4ed Mon Sep 17 00:00:00 2001 From: Thomas <bistory@gmail.com> Date: Tue, 1 Sep 2026 20:05:10 +0200 Subject: [PATCH 18/51] Fixed "jerk" translation inconsistency. (#15463) * Fixed "jerk" translation inconsistency. * Fixed an other "jerk" translation. --- localization/i18n/fr/OrcaSlicer_fr.po | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/localization/i18n/fr/OrcaSlicer_fr.po b/localization/i18n/fr/OrcaSlicer_fr.po index c9bd7f22ef..65589bc5ff 100644 --- a/localization/i18n/fr/OrcaSlicer_fr.po +++ b/localization/i18n/fr/OrcaSlicer_fr.po @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n==0 || n==1) ? 0 : 1;\n" -"X-Generator: Poedit 3.6\n" +"X-Generator: Poedit 3.9\n" # AI Translated msgid "Main Extruder" @@ -10707,7 +10707,7 @@ msgid "Acceleration limitation" msgstr "Limitation d'accélération" msgid "Jerk limitation" -msgstr "Limitation des secousses" +msgstr "Limitation du jerk" msgid "Single extruder multi-material setup" msgstr "Configuration multi-matériaux pour extrudeur unique" @@ -12226,7 +12226,7 @@ msgid "Plate %d: %s does not support filament %s" msgstr "Plaque %d : %s ne prend pas en charge le filament %s" msgid "Setting the jerk speed too low could lead to artifacts on curved surfaces" -msgstr "Un réglage trop bas de la vitesse de saccade peut entraîner des artefacts sur les surfaces courbes" +msgstr "Un réglage trop bas de la vitesse de jerk peut entraîner des artefacts sur les surfaces courbes" msgid "" "The jerk setting exceeds the printer's maximum jerk (machine_max_jerk_x/machine_max_jerk_y).\n" @@ -12234,7 +12234,7 @@ msgid "" "You can adjust the maximum jerk setting in your printer's configuration to get higher speeds." msgstr "" "Le réglage du jerk dépasse le jerk maximum de l’imprimante (machine_max_jerk_x/machine_max_jerk_y).\n" -"Orca plafonne automatiquement la vitesse de l’impulsion pour s’assurer qu’elle ne dépasse pas les capacités de l’imprimante.\n" +"Orca plafonne automatiquement la vitesse du jerk pour s’assurer qu’elle ne dépasse pas les capacités de l’imprimante.\n" "Vous pouvez ajuster le réglage du jerk maximum dans la configuration de votre imprimante pour obtenir des vitesses plus élevées." msgid "" @@ -21188,8 +21188,7 @@ msgstr "" "Divisez vos impressions en plateaux\n" "Saviez-vous que vous pouvez diviser un modèle comportant de nombreuses pièces en plateaux individuels prêts à être imprimés ? Cela simplifie le processus de suivi de toutes les pièces." -#: resources/data/hints.ini: [hint:Speed up your print with Adaptive Layer -#: Height] +#: resources/data/hints.ini: [hint:Speed up your print with Adaptive Layer Height] msgid "" "Speed up your print with Adaptive Layer Height\n" "Did you know that you can print a model even faster by using the Adaptive Layer Height option? Check it out!" @@ -21261,8 +21260,7 @@ msgstr "" "Améliorer la solidité\n" "Saviez-vous que vous pouvez définir un plus grand nombre de périmètre et une densité de remplissage plus élevée pour améliorer la résistance du modèle ?" -#: resources/data/hints.ini: [hint:When do you need to print with the printer -#: door opened] +#: resources/data/hints.ini: [hint:When do you need to print with the printer door opened] msgid "" "When do you need to print with the printer door opened?\n" "Did you know that opening the printer door can reduce the probability of extruder/hotend clogging when printing lower temperature filament with a higher enclosure temperature? There is more info about this in the Wiki." From e108ddfd56b6527a7b372c009307a5a2e5291347 Mon Sep 17 00:00:00 2001 From: Ian Bassi <ian.bassi@outlook.com> Date: Tue, 1 Sep 2026 15:37:08 -0300 Subject: [PATCH 19/51] Fix wrong JA jerk translation. (#15488) Update OrcaSlicer_ja.po --- localization/i18n/ja/OrcaSlicer_ja.po | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/localization/i18n/ja/OrcaSlicer_ja.po b/localization/i18n/ja/OrcaSlicer_ja.po index 327e3df661..d67a39463d 100644 --- a/localization/i18n/ja/OrcaSlicer_ja.po +++ b/localization/i18n/ja/OrcaSlicer_ja.po @@ -10617,7 +10617,7 @@ msgid "Junction Deviation" msgstr "接合偏差" msgid "Jerk(XY)" -msgstr "ジャーク(XY)" +msgstr "Jerk(XY)" msgid "Raft" msgstr "ラフト" @@ -10914,7 +10914,7 @@ msgid "Acceleration limitation" msgstr "加速制限" msgid "Jerk limitation" -msgstr "振動特性" +msgstr "Jerk制限" msgid "Single extruder multi-material setup" msgstr "シングルエクストルーダー マルチマテリアル設定" @@ -12485,7 +12485,7 @@ msgid "Plate %d: %s does not support filament %s" msgstr "プレート %d: %s がフィラメント %s を使用できません" msgid "Setting the jerk speed too low could lead to artifacts on curved surfaces" -msgstr "ジャーク速度を低く設定しすぎると曲面にアーティファクトが発生する可能性があります" +msgstr "Jerk速度を低く設定しすぎると曲面にアーティファクトが発生する可能性があります" # AI Translated msgid "" @@ -14750,7 +14750,7 @@ msgid "Klipper's max_accel_to_decel will be adjusted to this %% of acceleration. msgstr "Klipperのmax_accel_to_decelが、加速度のこの%%に調整されます。" msgid "Default jerk." -msgstr "デフォルトジャーク。" +msgstr "デフォルトのJerkです。" # AI Translated msgid "Marlin Firmware Junction Deviation (replaces the traditional XY Jerk setting)." @@ -15841,28 +15841,28 @@ msgid "Maximum acceleration of the E axis" msgstr "E軸最大加速度" msgid "Maximum jerk X" -msgstr "最大振動 X" +msgstr "最大Jerk X" msgid "Maximum jerk Y" -msgstr "最大振動 Y" +msgstr "最大Jerk Y" msgid "Maximum jerk Z" -msgstr "最大振動 Z" +msgstr "最大Jerk Z" msgid "Maximum jerk E" -msgstr "最大振動 E" +msgstr "最大Jerk E" msgid "Maximum jerk of the X axis" -msgstr "最大振動 X" +msgstr "X軸最大Jerk" msgid "Maximum jerk of the Y axis" -msgstr "最大振動 Y" +msgstr "Y軸最大Jerk" msgid "Maximum jerk of the Z axis" -msgstr "最大振動 Z" +msgstr "Z軸最大Jerk" msgid "Maximum jerk of the E axis" -msgstr "最大振動 E" +msgstr "E軸最大Jerk" msgid "Maximum Junction Deviation" msgstr "最大接合偏差" From 36228c4755782447f74296a7c8d9c430288b3bad Mon Sep 17 00:00:00 2001 From: weng haishi <74546450+wenghaishi@users.noreply.github.com> Date: Wed, 2 Sep 2026 03:39:12 +0800 Subject: [PATCH 20/51] fix: prevent heap corruption when repairing models with auto-backup (#15395) * fix: prevent heap corruption in model repair with auto-backup The CGAL model repair (fix_model_with_cgal_gui) runs on a worker thread that mutates the live ModelObject (split / delete_volume / set_mesh). Those mutators transitively call save_object_mesh(), which hands the object to the auto-backup manager. The manager clones and serializes the object on its own thread via an internal Model documented as "visit only in main thread". Running that path from the repair worker races the backup thread on the shared model, causing use-after-free / heap corruption -- EXC_BAD_ACCESS and libmalloc "corruption of free block" aborts, always with the "cgal_fix_model" worker on the stack inside add_object_mesh -> Model::add_object / delete_object. Wrap the repair in a SaveObjectGaurd so the backup manager ignores the object for the duration of the repair; a single backup is taken when the guard is released on the main thread after the worker joins. This mirrors existing batch-edit usage of SaveObjectGaurd (Model.hpp, GUI_ObjectList). Repro: repair a multi-part / splittable object with auto-backup enabled (Preferences > Backup); crashed within a few repairs on macOS arm64. * Update FixModelByCgal.cpp --------- Co-authored-by: Ian Bassi <ian.bassi@outlook.com> --- src/slic3r/Utils/FixModelByCgal.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/slic3r/Utils/FixModelByCgal.cpp b/src/slic3r/Utils/FixModelByCgal.cpp index 8d196f7201..9d973844bb 100644 --- a/src/slic3r/Utils/FixModelByCgal.cpp +++ b/src/slic3r/Utils/FixModelByCgal.cpp @@ -12,6 +12,7 @@ #include "libslic3r/MeshBoolean.hpp" #include "libslic3r/Model.hpp" +#include "libslic3r/Format/bbs_3mf.hpp" #include "libslic3r/format.hpp" #include "libslic3r/Thread.hpp" #include "../GUI/I18N.hpp" @@ -69,6 +70,9 @@ public: // Returns false if fixing was canceled. fix_result contains error message if failed. bool fix_model_with_cgal_gui(ModelObject &model_object, int volume_idx, GUI::ProgressDialog &progress_dialog, const wxString &msg_header, std::string &fix_result, bool keep_painting) { + // Hold SaveObjectGaurd to prevent backup manager from racing concurrent mesh mutations (use-after-free). + SaveObjectGaurd backup_gaurd(model_object); + // Orca: Synchronization primitives for progress updates between worker thread and GUI. std::mutex mtx; std::condition_variable condition; From e8115658e044c1a4bc9b537f9197ec31531b1ca4 Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Wed, 2 Sep 2026 00:07:02 +0300 Subject: [PATCH 21/51] Fix overhang fan control when overhang slowdown is enabled (#15158) --- src/libslic3r/GCode.cpp | 7 +-- src/libslic3r/GCode/CoolingBuffer.cpp | 21 ++++---- src/libslic3r/GCode/FanMover.cpp | 11 ++--- src/libslic3r/GCode/GCodeProcessor.cpp | 4 +- tests/fff_print/test_cooling.cpp | 68 ++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 21 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index e947be47a1..e9cdb620e0 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -8197,9 +8197,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, } variable_speed = std::any_of(new_points.begin(), new_points.end(), [speed](const ProcessedPoint &p) { return fabs(double(p.speed) - speed) > 1; }); // Ignore small speed variations (under 1mm/sec) - if (!NOZZLE_CONFIG(enable_overhang_speed) && FILAMENT_CONFIG(enable_overhang_bridge_fan) && m_enable_cooling_markers) { - for (ProcessedPoint &point : new_points) - point.speed = speed; + if (FILAMENT_CONFIG(enable_overhang_bridge_fan) && m_enable_cooling_markers) { + if (!NOZZLE_CONFIG(enable_overhang_speed)) + for (ProcessedPoint &point : new_points) + point.speed = speed; variable_speed = new_points.size() > 1; } } diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp index 3bca1f8df9..e55b89212e 100644 --- a/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/src/libslic3r/GCode/CoolingBuffer.cpp @@ -1024,28 +1024,29 @@ std::string CoolingBuffer::apply_layer_cooldown( } if (need_set_fan) { + const auto set_fan = [&](int speed) { + if (m_current_fan_speed != speed) { + new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, speed, part_cooling_fan_min_pwm); + m_current_fan_speed = speed; + } + }; if (fan_speed_change_requests[CoolingLine::TYPE_OVERHANG_FAN_START]){ - new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, overhang_fan_speed, part_cooling_fan_min_pwm); - m_current_fan_speed = overhang_fan_speed; + set_fan(overhang_fan_speed); } else if (fan_speed_change_requests[CoolingLine::TYPE_INTERNAL_BRIDGE_FAN_START]){ // ORCA: Add support for separate internal bridge fan speed control - new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, internal_bridge_fan_speed, part_cooling_fan_min_pwm); - m_current_fan_speed = internal_bridge_fan_speed; + set_fan(internal_bridge_fan_speed); } else if (fan_speed_change_requests[CoolingLine::TYPE_SUPPORT_INTERFACE_FAN_START]){ - new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, supp_interface_fan_speed, part_cooling_fan_min_pwm); - m_current_fan_speed = supp_interface_fan_speed; + set_fan(supp_interface_fan_speed); } else if (fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START]){ - new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, ironing_fan_speed, part_cooling_fan_min_pwm); - m_current_fan_speed = ironing_fan_speed; + set_fan(ironing_fan_speed); } else if(fan_speed_change_requests[CoolingLine::TYPE_FORCE_RESUME_FAN] && m_current_fan_speed != -1){ new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_current_fan_speed, part_cooling_fan_min_pwm); fan_speed_change_requests[CoolingLine::TYPE_FORCE_RESUME_FAN] = false; } else { - new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_fan_speed, part_cooling_fan_min_pwm); - m_current_fan_speed = m_fan_speed; + set_fan(m_fan_speed); } need_set_fan = false; } diff --git a/src/libslic3r/GCode/FanMover.cpp b/src/libslic3r/GCode/FanMover.cpp index 112066bb85..9d77d1d04c 100644 --- a/src/libslic3r/GCode/FanMover.cpp +++ b/src/libslic3r/GCode/FanMover.cpp @@ -170,14 +170,13 @@ void FanMover::_put_in_middle_G1(std::list<BufferData>::iterator item_to_split, void FanMover::_print_in_middle_G1(BufferData& line_to_split, float nb_sec, const std::string &line_to_write) { if (nb_sec < line_to_split.time * 0.1) { - // doesn't really need to be split, print it after - m_process_output += line_to_split.raw + "\n"; + // Doesn't need to be split: the insertion point is at the start. m_process_output += line_to_write + (line_to_write.back() == '\n'?"":"\n"); - } else if (nb_sec > line_to_split.time * 0.9) { - // doesn't really need to be split, print it before - //will also print before if line_to_split.time == 0 - m_process_output += line_to_write + (line_to_write.back() == '\n' ? "" : "\n"); m_process_output += line_to_split.raw + "\n"; + } else if (nb_sec > line_to_split.time * 0.9) { + // Doesn't need to be split: the insertion point is at the end. + m_process_output += line_to_split.raw + "\n"; + m_process_output += line_to_write + (line_to_write.back() == '\n' ? "" : "\n"); }else if(line_to_split.raw.size() > 2 && line_to_split.raw[0] == 'G' && line_to_split.raw[1] == '1' && line_to_split.raw[2] == ' ') { float percent = nb_sec / line_to_split.time; diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 4f3f95f297..2ac8bd45a6 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -532,7 +532,7 @@ void GCodeProcessor::TimeMachine::calculate_time(GCodeProcessorResult& result, P const float height = interpolate ? lerp(prev_move.height, curr_move.height, t) : curr_move.height; // ORCA: Fix issue with flow rate changes being visualized incorrectly const float mm3_per_mm = curr_move.mm3_per_mm; - const float fan_speed = interpolate ? lerp(prev_move.fan_speed, curr_move.fan_speed, t) : curr_move.fan_speed; + const float fan_speed = curr_move.fan_speed; const float temperature = interpolate ? lerp(prev_move.temperature, curr_move.temperature, t) : curr_move.temperature; actual_speed_moves.push_back({ block.move_id, @@ -563,7 +563,7 @@ void GCodeProcessor::TimeMachine::calculate_time(GCodeProcessorResult& result, P const float height = interpolate ? lerp(prev_move.height, curr_move.height, t) : curr_move.height; // ORCA: Fix issue with flow rate changes being visualized incorrectly const float mm3_per_mm = curr_move.mm3_per_mm; - const float fan_speed = interpolate ? lerp(prev_move.fan_speed, curr_move.fan_speed, t) : curr_move.fan_speed; + const float fan_speed = curr_move.fan_speed; const float temperature = interpolate ? lerp(prev_move.temperature, curr_move.temperature, t) : curr_move.temperature; actual_speed_moves.push_back({ block.move_id, diff --git a/tests/fff_print/test_cooling.cpp b/tests/fff_print/test_cooling.cpp index ec29b5fdc9..a21ff236ce 100644 --- a/tests/fff_print/test_cooling.cpp +++ b/tests/fff_print/test_cooling.cpp @@ -2,7 +2,10 @@ #include "test_helpers.hpp" +#include <algorithm> +#include <sstream> #include <string> +#include <vector> using namespace Slic3r; using namespace Slic3r::Test; @@ -25,3 +28,68 @@ TEST_CASE("Cooling consumes its internal speed markers", "[Cooling]") const std::string gcode = slice({ cube(20) }, { { "layer_height", 0.2 } }); CHECK(gcode.find(";_EXTRUDE_SET_SPEED") == std::string::npos); } + +TEST_CASE("Overhang fan transitions do not depend on overhang speed", "[Cooling][Regression]") +{ + DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "bridge_speed", 2.0 }, + { "enable_arc_fitting", false }, + { "enable_overhang_bridge_fan", true }, + { "enable_overhang_speed", false }, + { "initial_layer_print_height", 0.3 }, + { "inner_wall_speed", 30.0 }, + { "layer_height", 0.3 }, + { "outer_wall_speed", 30.0 }, + { "overhang_1_4_speed", "30" }, + { "overhang_2_4_speed", "29" }, + { "overhang_3_4_speed", "6" }, + { "overhang_4_4_speed", "3" }, + { "slow_down_for_layer_cooling", false }, + { "slowdown_for_curled_perimeters", false }, + }); + config.set_key_value("fan_max_speed", new ConfigOptionFloats{20.0}); + config.set_key_value("fan_min_speed", new ConfigOptionFloats{20.0}); + config.set_key_value("overhang_fan_speed", new ConfigOptionInts{100}); + config.set_key_value("overhang_fan_threshold", new ConfigOptionEnumsGeneric{Overhang_threshold_2_4}); + config.set_key_value("layer_change_gcode", new ConfigOptionString{";TEST_LAYER_Z=[layer_z]"}); + + const auto fan_commands = [](const std::string &gcode) { + std::vector<std::pair<std::string, std::string>> commands; + std::istringstream input(gcode); + std::string layer; + std::string line; + while (std::getline(input, line)) { + if (line.rfind(";TEST_LAYER_Z=", 0) == 0) + layer = line; + else if (!layer.empty() && (line.rfind("M106", 0) == 0 || line.rfind("M107", 0) == 0)) + commands.emplace_back(layer, line); + } + return commands; + }; + const auto feedrates = [](const std::string &gcode) { + std::vector<std::string> values; + std::istringstream input(gcode); + std::string word; + while (input >> word) + if (!word.empty() && word.front() == 'F') + values.push_back(word); + return values; + }; + + constexpr double sphere_radius = 50.0; // 100 mm diameter. + const std::string without_speed_gcode = slice({make_sphere(sphere_radius, PI / 24.0)}, config); + config.set_deserialize_strict({{"enable_overhang_speed", true}}); + const std::string with_speed_gcode = slice({make_sphere(sphere_radius, PI / 24.0)}, config); + + const auto without_speed_fan = fan_commands(without_speed_gcode); + const auto with_speed_fan = fan_commands(with_speed_gcode); + const auto without_speed_feedrates = feedrates(without_speed_gcode); + const auto with_speed_feedrates = feedrates(with_speed_gcode); + + REQUIRE_FALSE(without_speed_fan.empty()); + REQUIRE(std::any_of(without_speed_fan.begin(), without_speed_fan.end(), + [](const auto &command) { return command.second.find("S255") != std::string::npos; })); + REQUIRE(with_speed_feedrates != without_speed_feedrates); + CHECK(with_speed_fan == without_speed_fan); +} From b6ef6cf1be428b931d669dcc31b7f43ae320be85 Mon Sep 17 00:00:00 2001 From: Clifford <cliff@cigii.com> Date: Tue, 1 Sep 2026 18:29:11 -0400 Subject: [PATCH 22/51] fix: out-of-bounds write migrating per-variant values when switching printers (#15456) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> --- src/libslic3r/PrintConfig.cpp | 57 +++++++++++-- .../test_config_variant_expansion.cpp | 81 +++++++++++++++++++ 2 files changed, 131 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 2a4eb8d7a7..17d7cee678 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -10091,6 +10091,10 @@ int DynamicPrintConfig::update_values_from_single_to_multi(DynamicPrintConfig& m for (int index = 0; index < variant_count; index++) { + //variant_count is the variant column width, src_opt the value array; + //they disagree when the source was authored at a different width + if (index >= (int)src_opt->values.size()) + break; if (opt->values[index] > src_opt->values[index]) opt->values[index] = src_opt->values[index]; } @@ -10108,6 +10112,8 @@ int DynamicPrintConfig::update_values_from_single_to_multi(DynamicPrintConfig& m for (int index = 0; index < variant_count; index++) { + if (index >= (int)src_opt->values.size()) + break; if (opt->values[index].value > src_opt->values[index].value) opt->values[index] = src_opt->values[index]; } @@ -10302,6 +10308,10 @@ int DynamicPrintConfig::update_values_from_multi_to_multi(DynamicPrintConfig& ne for(auto idx : variant_indices){ assert(idx < old_count); + //the counts come from the variant columns, the arrays from the options; + //they disagree when a config was authored at a different variant width + if (idx >= old_count || new_variant_index >= (int)opt->values.size()) + continue; if (old_values[idx] < opt->values[new_variant_index]) opt->values[new_variant_index] = old_values[idx]; } @@ -10332,6 +10342,10 @@ int DynamicPrintConfig::update_values_from_multi_to_multi(DynamicPrintConfig& ne for(auto idx : variant_indices){ assert(idx < old_count); + //the counts come from the variant columns, the arrays from the options; + //they disagree when a config was authored at a different variant width + if (idx >= old_count || new_variant_index >= (int)opt->values.size()) + continue; if (old_values[idx] < opt->values[new_variant_index]) opt->values[new_variant_index] = old_values[idx]; } @@ -10362,6 +10376,8 @@ int DynamicPrintConfig::update_values_from_multi_to_multi(DynamicPrintConfig& ne for(auto idx : variant_indices){ assert(idx < old_count); + if (idx >= old_count || new_variant_index >= (int)opt->values.size()) + continue; if (old_values[idx]) //enabled opt->values[new_variant_index] = old_values[idx]; } @@ -10402,6 +10418,15 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st same_variant_indices.emplace_back(indices); } + //dst_values below is the destination PRINT preset's per-variant row, sized to its own + //print_extruder_variant; dst_extruder_variants is the PRINTER's list. They disagree until + //the print preset is re-selected, so size the row to the variant count before indexing it. + const size_t dst_variant_count = dst_extruder_variants.size(); + if (dst_variant_count == 0) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", Line %1%: empty destination variant list")%__LINE__; + return -1; + } + t_config_option_keys keys = this->keys(); for(auto& key : keys){ if(key_sets.find(key) == key_sets.end()) @@ -10417,7 +10442,13 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st { ConfigOptionFloatsNullable* opt = this->option<ConfigOptionFloatsNullable>(key); auto src_values = opt->values; - auto dst_values = dst_config.option<ConfigOptionFloatsNullable>(key) ->values; + const auto* dst_opt = dst_config.option<ConfigOptionFloatsNullable>(key); + if(!dst_opt){ + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: %2% missing from destination config")%__LINE__%key; + break; + } + auto dst_values = dst_opt->values; + dst_values.resize(dst_variant_count, ConfigOptionFloatsNullable::nil_value()); for(size_t dst_idx =0; dst_idx < same_variant_indices.size(); ++dst_idx){ auto& indices = same_variant_indices[dst_idx]; if(indices.empty()) @@ -10425,7 +10456,7 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st bool has_value = false; double target_value = std::numeric_limits<double>::max(); for(auto idx : indices){ - if(opt && idx < opt->values.size() && !opt->is_nil(idx)){ + if(idx < (int)opt->values.size() && !opt->is_nil(idx)){ has_value = true; target_value = std::min(target_value, src_values[idx]); } @@ -10441,7 +10472,13 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st { ConfigOptionFloatsOrPercentsNullable* opt = this->option<ConfigOptionFloatsOrPercentsNullable>(key); auto src_values = opt->values; - auto dst_values = dst_config.option<ConfigOptionFloatsOrPercentsNullable>(key) ->values; + const auto* dst_opt = dst_config.option<ConfigOptionFloatsOrPercentsNullable>(key); + if(!dst_opt){ + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: %2% missing from destination config")%__LINE__%key; + break; + } + auto dst_values = dst_opt->values; + dst_values.resize(dst_variant_count, ConfigOptionFloatsOrPercentsNullable::nil_value()); for(size_t dst_idx =0; dst_idx < same_variant_indices.size(); ++dst_idx){ auto& indices = same_variant_indices[dst_idx]; if(indices.empty()) @@ -10449,7 +10486,7 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st bool has_value = false; FloatOrPercent target_value{9999.f, true}; for(auto idx : indices){ - if(opt && !opt->is_nil(idx)){ + if(idx < (int)opt->values.size() && !opt->is_nil(idx)){ has_value = true; target_value = src_values[idx].value < target_value.value ? src_values[idx] : target_value; } @@ -10465,15 +10502,21 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st { ConfigOptionBoolsNullable* opt = this->option<ConfigOptionBoolsNullable>(key); auto src_values = opt->values; - auto dst_values = dst_config.option<ConfigOptionBoolsNullable>(key) ->values; + const auto* dst_opt = dst_config.option<ConfigOptionBoolsNullable>(key); + if(!dst_opt){ + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: %2% missing from destination config")%__LINE__%key; + break; + } + auto dst_values = dst_opt->values; + dst_values.resize(dst_variant_count, ConfigOptionBoolsNullable::nil_value()); for(size_t dst_idx =0; dst_idx < same_variant_indices.size(); ++dst_idx){ auto indices = same_variant_indices[dst_idx]; if(indices.empty()) continue; bool has_value = false; - bool target_value; + bool target_value = false; for(auto idx : indices){ - if(opt && !opt->is_nil(idx)){ + if(idx < (int)opt->values.size() && !opt->is_nil(idx)){ has_value = true; target_value = src_values[idx]; break; diff --git a/tests/libslic3r/test_config_variant_expansion.cpp b/tests/libslic3r/test_config_variant_expansion.cpp index dd7de2af44..28901702cc 100644 --- a/tests/libslic3r/test_config_variant_expansion.cpp +++ b/tests/libslic3r/test_config_variant_expansion.cpp @@ -479,3 +479,84 @@ TEST_CASE("update_values_to_printer_extruders_for_multiple_filaments resolves pe REQUIRE(config.option<ConfigOptionInts>("filament_self_index")->values == std::vector<int>({1, 2})); } } + +// update_values_from_multi_to_multi_2 walks the DESTINATION PRINTER's variant list while writing +// into a row taken from the destination PRINT preset, whose arrays are sized to its own +// print_extruder_variant. Those two widths disagree until the print preset is re-selected for the +// new printer -- Tab::load_current_preset() runs this migration first -- so a project authored on +// a single-variant printer, opened and switched to a wider one, wrote past the end of the row. +TEST_CASE("update_values_from_multi_to_multi_2 sizes the destination row to the variant count", + "[Config][VariantExpansion]") +{ + const std::vector<std::string> src_variants{"Direct Drive Standard"}; + const std::vector<std::string> dst_variants{"Direct Drive Standard", "Direct Drive High Flow", + "Direct Drive Standard", "Direct Drive High Flow"}; + const std::set<std::string> keys{"outer_wall_speed"}; + + // The per-object override as authored on the single-variant printer. + const auto object_override = [] { + DynamicPrintConfig c; + c.option<ConfigOptionFloatsNullable>("outer_wall_speed", true)->values = {42.}; + return c; + }; + + SECTION("a row narrower than the variant list is grown, not overrun") { + DynamicPrintConfig object_config = object_override(); + DynamicPrintConfig dst; + dst.option<ConfigOptionFloatsNullable>("outer_wall_speed", true)->values = {200.}; + + REQUIRE(object_config.update_values_from_multi_to_multi_2(src_variants, dst_variants, dst, keys) == 0); + + const auto& out = object_config.option<ConfigOptionFloatsNullable>("outer_wall_speed")->values; + REQUIRE(out.size() == dst_variants.size()); + // Both "Direct Drive Standard" columns match the source variant, so they take the override. + CHECK(out[0] == Catch::Approx(42.)); + CHECK(out[2] == Catch::Approx(42.)); + // The High Flow columns have no matching source variant: nil, so the destination keeps + // tracking the print preset rather than being pinned to another variant's value. + CHECK(std::isnan(out[1])); + CHECK(std::isnan(out[3])); + } + + // The regression guard: where the row already matches the variant list -- every case that was + // not corrupting the heap -- the resize is a no-op and the output is unchanged. + SECTION("a correctly sized row is untouched") { + DynamicPrintConfig object_config = object_override(); + DynamicPrintConfig dst; + dst.option<ConfigOptionFloatsNullable>("outer_wall_speed", true)->values = {200., 500., 210., 510.}; + + REQUIRE(object_config.update_values_from_multi_to_multi_2(src_variants, dst_variants, dst, keys) == 0); + + const auto& out = object_config.option<ConfigOptionFloatsNullable>("outer_wall_speed")->values; + REQUIRE(out.size() == 4); + CHECK(out[0] == Catch::Approx(42.)); // matched -> override + CHECK(out[1] == Catch::Approx(500.)); // unmatched -> preset value preserved + CHECK(out[2] == Catch::Approx(42.)); + CHECK(out[3] == Catch::Approx(510.)); + } + + // is_nil(idx) indexes values[idx] with no bounds check, so a source shorter than its own + // variant list read out of range before the guard was added. + SECTION("a source shorter than its variant list is read in range") { + DynamicPrintConfig object_config = object_override(); // one value... + DynamicPrintConfig dst; + dst.option<ConfigOptionFloatsNullable>("outer_wall_speed", true)->values = {200., 500.}; + + REQUIRE(object_config.update_values_from_multi_to_multi_2( + {"Direct Drive Standard", "Direct Drive Standard"}, // ...but two source variants + {"Direct Drive Standard", "Direct Drive High Flow"}, dst, keys) == 0); + + const auto& out = object_config.option<ConfigOptionFloatsNullable>("outer_wall_speed")->values; + REQUIRE(out.size() == 2); + CHECK(out[0] == Catch::Approx(42.)); + CHECK(out[1] == Catch::Approx(500.)); + } + + SECTION("an empty destination variant list is refused") { + DynamicPrintConfig object_config = object_override(); + DynamicPrintConfig dst; + dst.option<ConfigOptionFloatsNullable>("outer_wall_speed", true)->values = {200.}; + + CHECK(object_config.update_values_from_multi_to_multi_2(src_variants, {}, dst, keys) == -1); + } +} From e523acc164ecacb9e25d080cd72bbdf9f58abfe8 Mon Sep 17 00:00:00 2001 From: SoftFever <103989404+SoftFever@users.noreply.github.com> Date: Wed, 2 Sep 2026 15:22:55 +0800 Subject: [PATCH 23/51] Add script to run full profile checks locally (#15496) * Run the CI profile checks locally --- .gitignore | 1 + scripts/check_profile.bat | 6 + scripts/check_profile.ps1 | 564 ++++++++++++++++++++++++++++++++++++++ scripts/check_profile.sh | 527 +++++++++++++++++++++++++++++++++++ 4 files changed, 1098 insertions(+) create mode 100644 scripts/check_profile.bat create mode 100644 scripts/check_profile.ps1 create mode 100755 scripts/check_profile.sh diff --git a/.gitignore b/.gitignore index e36d0dfa49..d994d922c1 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,4 @@ internal_docs/ __pycache__/ *.pyc *.opc +/.test/ diff --git a/scripts/check_profile.bat b/scripts/check_profile.bat new file mode 100644 index 0000000000..231fa721d4 --- /dev/null +++ b/scripts/check_profile.bat @@ -0,0 +1,6 @@ +@echo off +REM Runs check_profile.ps1, the Windows twin of check_profile.sh, from cmd. +REM -ExecutionPolicy Bypass is needed because a Windows client defaults to Restricted, +REM which refuses to run a checked-out .ps1 at all. +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0check_profile.ps1" %* +exit /b %ERRORLEVEL% diff --git a/scripts/check_profile.ps1 b/scripts/check_profile.ps1 new file mode 100644 index 0000000000..5c5dcb20c8 --- /dev/null +++ b/scripts/check_profile.ps1 @@ -0,0 +1,564 @@ +<# +.SYNOPSIS + Local twin of the "Check profiles" CI job (.github/workflows/check_profiles.yml), for Windows. + +.DESCRIPTION + The Windows counterpart of scripts/check_profile.sh, and kept deliberately close to it. + + Runs the same five checks, in the same order, with the same validator flags, and with the + same semantics: every check runs even after an earlier one fails (the workflow's + continue-on-error), then the script exits non-zero once at the end. + + extra_json_check scripts/orca_extra_profile_check.py + validate_system validator -p <profiles> -l <level> + validate_slice validator -p <profiles> -s -l <level> + validate_filament_subtypes validator -p <profiles> -l <level> -f + validate_custom validator against every released custom-preset fixture + + Everything that has to be downloaded - the profile validator and the custom-preset fixture + archives - lands under <repo>\.test\check_profiles and is reused on the next run. That + directory also holds one log per check plus a copy of the comment CI would post on the PR. + + resources\profiles\user, which the validator creates as its data dir but a CI checkout never + has, is moved aside for the duration of the run and restored on exit. Only one run per work + dir at a time. + + x64 and ARM64 hosts are both supported. A locally built validator is chosen by the machine + type in its PE header rather than by the name of its build tree, so build\ (x64) and + build-arm64\ side by side resolve correctly; the published nightly is x64 only and runs + under emulation on ARM64. + +.PARAMETER ProfilesDir + Profile tree to validate (default: resources\profiles). extra_json_check always looks at the + tree next to the script, so this only redirects the validator checks. + +.PARAMETER Validator + OrcaSlicer_profile_validator.exe to use; also $env:ORCA_PROFILE_VALIDATOR. Default: the local + build*\ Release build (then RelWithDebInfo, MinSizeRel, Debug) for this architecture, else + the nightly release build is downloaded. + +.PARAMETER Download + Ignore local builds and use the downloaded nightly validator. + +.PARAMETER Refresh + Re-download the validator and fixtures instead of using the cache. + +.PARAMETER WorkDir + Downloads, logs and fixture trees (default: .test\check_profiles). Point it somewhere short, + such as D:\t, if a fixture tree trips Windows' 260-character path limit. + +.PARAMETER LogLevel + Validator log level (default: 2, as in CI). + +.PARAMETER Checks + Checks to run, by name (default: all of them, in the order listed above). + +.EXAMPLE + scripts\check_profile.bat + +.EXAMPLE + powershell -ExecutionPolicy Bypass -File scripts\check_profile.ps1 validate_system validate_slice +#> + +# PositionalBinding is off so that the check names are the only positional arguments; left on, +# a bare "validate_system" would bind to whichever named parameter came next in this block. +[CmdletBinding(PositionalBinding = $false)] +param( + [Alias('p')] [string] $ProfilesDir, + [string] $Validator, + [string] $WorkDir, + [Alias('l')] [int] $LogLevel = 2, + [switch] $Download, + [switch] $Refresh, + [Alias('h')] [switch] $Help, + [Parameter(Position = 0, ValueFromRemainingArguments = $true)] [string[]] $Checks +) + +$ErrorActionPreference = 'Stop' + +# Windows PowerShell 5.1 still negotiates TLS 1.0/1.1, which github.com refuses. +[Net.ServicePointManager]::SecurityProtocol = + [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 + +$ValidatorReleaseUrl = 'https://github.com/OrcaSlicer/OrcaSlicer/releases/download/nightly-builds' +$FixtureReleaseUrl = 'https://github.com/OrcaSlicer/OrcaSlicer-profile-validator/releases/download/fixture-archive' + +$RepoRoot = Split-Path -Parent $PSScriptRoot + +# PROCESSOR_ARCHITECTURE reports the architecture of the *shell*, so a 32-bit PowerShell on a +# 64-bit OS says x86; ARCHITEW6432 is the machine's own in that case. +$HostArch = if ($env:PROCESSOR_ARCHITEW6432) { $env:PROCESSOR_ARCHITEW6432 } else { $env:PROCESSOR_ARCHITECTURE } +$HostArch = switch ($HostArch) { + 'ARM64' { 'arm64' } + 'AMD64' { 'x64' } + default { 'x86' } +} + +$AllChecks = @('extra_json_check', 'validate_system', 'validate_slice', 'validate_filament_subtypes', 'validate_custom') + +$script:LogWriter = $null +$script:Python = '' + +# ---------------------------------------------------------------------------- helpers + +function Die([string] $Message) { + Write-Host "check_profile.ps1: $Message" -ForegroundColor Red + exit 2 +} + +# UTF-8 without a BOM, so a log reads the same here as the artifact CI uploads. +function New-LogWriter([string] $Path) { + New-Object IO.StreamWriter($Path, $false, (New-Object Text.UTF8Encoding($false))) +} + +# Output of the check being run: shown, and kept in that check's log. +function Write-CheckLog([string] $Text) { + Write-Host $Text + if ($script:LogWriter) { $script:LogWriter.WriteLine($Text) } +} + +# Runs a program and returns its exit code, streaming stdout and stderr into the current check's +# log. -OutFile sends that output to a file of its own instead, silently. +function Invoke-Tool { + param([string] $Exe, [string[]] $Arguments, [string] $OutFile) + + # Under 'Stop', 2>&1 turns every stderr line of a native command into a terminating error. + # Assigning the preference here scopes it to this function, so it undoes itself on return. + $ErrorActionPreference = 'Continue' + + $writer = if ($OutFile) { New-LogWriter $OutFile } else { $null } + try { + & $Exe @Arguments 2>&1 | ForEach-Object { + if ($writer) { $writer.WriteLine("$_") } else { Write-CheckLog "$_" } + } + return $LASTEXITCODE + } catch { + if ($writer) { $writer.WriteLine("$_") } else { Write-CheckLog "$_" } + return 1 + } finally { + if ($writer) { $writer.Dispose() } + } +} + +# The first $Limit characters of a log, as CI truncates them for the PR comment. +function Get-LogHead([string] $Path, [int] $Limit) { + $text = if (Test-Path -LiteralPath $Path) { [IO.File]::ReadAllText($Path) } else { '' } + if (-not $text) { return 'No output captured' } + if ($text.Length -gt $Limit) { return $text.Substring(0, $Limit) } + return $text +} + +# ---------------------------------------------------------------------------- arguments + +if ($Help) { Get-Help $PSCommandPath -Detailed; exit 0 } + +foreach ($name in $Checks) { + if ($name -like '-*') { Die "unknown option '$name' (try -Help)" } + if ($AllChecks -notcontains $name) { Die "unknown check '$name' (try -Help)" } +} +if (-not $Checks) { $Checks = $AllChecks } + +if (-not $ProfilesDir) { $ProfilesDir = Join-Path $RepoRoot 'resources\profiles' } +if (-not (Test-Path -LiteralPath $ProfilesDir -PathType Container)) { Die "profile directory not found: $ProfilesDir" } +$ProfilesDir = (Resolve-Path -LiteralPath $ProfilesDir).Path + +if (-not $WorkDir) { $WorkDir = Join-Path $RepoRoot '.test\check_profiles' } +$LogDir = Join-Path $WorkDir 'logs' +try { New-Item -ItemType Directory -Force -Path $LogDir | Out-Null } catch { Die "cannot create ${LogDir}: $_" } +$WorkDir = (Resolve-Path -LiteralPath $WorkDir).Path +$LogDir = Join-Path $WorkDir 'logs' + +if (-not $Validator) { $Validator = $env:ORCA_PROFILE_VALIDATOR } + +# ------------------------------------------------------------------- clean profile tree + +# The validator points its data dir at the profile tree, so it creates - and, with -g, fills - +# <profiles>\user. A CI checkout never has that directory, and anything left in it from an +# earlier local run would be loaded as user presets and validated too. Move it aside for the +# duration of the run so what gets checked is what CI checks. +$script:StashedUserDir = '' + +function Push-UserPresets { + $user = Join-Path $ProfilesDir 'user' + if (-not (Test-Path -LiteralPath $user -PathType Container)) { return } + $script:StashedUserDir = Join-Path $WorkDir "user-presets-$PID" + Remove-Item -LiteralPath $script:StashedUserDir -Recurse -Force -ErrorAction SilentlyContinue + try { Move-Item -LiteralPath $user -Destination $script:StashedUserDir } + catch { $script:StashedUserDir = ''; Die "cannot move $user aside: $_" } + Write-Host "moved $user aside for the run (restored on exit)" +} + +function Pop-UserPresets { + # The validator leaves an empty user\default\{filament,machine,process} skeleton behind. + # Prune it directory by directory, never wholesale: one that holds a real file survives and + # is reported instead of being deleted. Runs even when nothing was stashed, so a tree that + # had no user\ before the run does not gain one. + $user = Join-Path $ProfilesDir 'user' + Remove-EmptyDirs $user + if (-not $script:StashedUserDir) { return } + if (Test-Path -LiteralPath $user) { + Write-Host "$user is not empty; your presets stay in $($script:StashedUserDir)" + } else { + Move-Item -LiteralPath $script:StashedUserDir -Destination $user + } + $script:StashedUserDir = '' +} + +function Remove-EmptyDirs([string] $Path) { + if (-not (Test-Path -LiteralPath $Path -PathType Container)) { return } + Get-ChildItem -LiteralPath $Path -Recurse -Directory -Force | + Sort-Object { $_.FullName.Length } -Descending | + ForEach-Object { + if (-not (Get-ChildItem -LiteralPath $_.FullName -Force)) { + Remove-Item -LiteralPath $_.FullName -Force + } + } + if (-not (Get-ChildItem -LiteralPath $Path -Force)) { Remove-Item -LiteralPath $Path -Force } +} + +# ---------------------------------------------------------------------------- downloads + +# Cached; -Refresh, or -Force, pulls a new copy. Release assets never change, so caching them is +# safe; the fixture manifest is the index that grows with every release, and CI re-reads it on +# every run. +function Save-Asset { + param([string] $Url, [string] $Dest, [switch] $Force) + + if (-not $Refresh -and -not $Force -and (Test-Path -LiteralPath $Dest -PathType Leaf) -and + (Get-Item -LiteralPath $Dest).Length -gt 0) { + return + } + New-Item -ItemType Directory -Force -Path (Split-Path -Parent $Dest) | Out-Null + Write-Host "downloading $(Split-Path -Leaf $Dest) ..." + + # Invoke-WebRequest spends most of a large download repainting its progress bar. + $ProgressPreference = 'SilentlyContinue' + $part = "$Dest.part" + for ($attempt = 1; ; $attempt++) { + try { + Invoke-WebRequest -Uri $Url -OutFile $part -UseBasicParsing + break + } catch { + if ($attempt -ge 3) { + Remove-Item -LiteralPath $part -Force -ErrorAction SilentlyContinue + throw "download failed: $Url" + } + } + } + Move-Item -LiteralPath $part -Destination $Dest -Force +} + +function Get-Sha256([string] $Path) { + return (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash +} + +# Directories a built validator can sit in, best first: build_win.bat names its trees build, +# build-dbginfo, build-minsize and build-dbg, each optionally -clang and -arm64 suffixed, and +# CMake puts the binary in src\<config>. Each pattern is matched both directly under a build root +# and one level down (build\x64), for trees laid out the way the macOS ones are. +function Get-ValidatorSearchDirs { + foreach ($config in 'Release', 'RelWithDebInfo', 'MinSizeRel', 'Debug') { + Join-Path $RepoRoot "build*\src\$config" + Join-Path $RepoRoot "build*\*\src\$config" + } + Join-Path $RepoRoot 'build*\src' + Join-Path $RepoRoot 'build*\*\src' +} + +# The machine type from the PE header, which is what actually decides whether an .exe can run +# here - the name of the build tree only says what it was meant to be. +function Get-ExeArch([string] $Path) { + try { + $stream = [IO.File]::OpenRead($Path) + try { + $reader = New-Object IO.BinaryReader($stream) + $stream.Position = 0x3C # e_lfanew: offset of the PE header + $stream.Position = $reader.ReadInt32() + if ($reader.ReadUInt32() -ne 0x00004550) { return '' } # "PE\0\0" + switch ($reader.ReadUInt16()) { + 0x8664 { 'x64' } + 0xAA64 { 'arm64' } + 0x014C { 'x86' } + default { '' } + } + } finally { $stream.Dispose() } + } catch { '' } +} + +# First locally built OrcaSlicer_profile_validator.exe, in the order above. An x86 build, and on +# ARM64 an x64 one, is kept only as a fallback: it runs, but emulated. An ARM64 build on an x64 +# host does not run at all and is never offered. +function Find-LocalValidator { + $emulated = '' + foreach ($pattern in (Get-ValidatorSearchDirs)) { + foreach ($dir in @(Resolve-Path -Path $pattern -ErrorAction SilentlyContinue)) { + $candidate = Join-Path $dir.Path 'OrcaSlicer_profile_validator.exe' + if (-not (Test-Path -LiteralPath $candidate -PathType Leaf)) { continue } + $arch = Get-ExeArch $candidate + if (-not $arch -or $arch -eq $HostArch) { return $candidate } + if (-not $emulated -and ($arch -eq 'x86' -or $HostArch -eq 'arm64')) { $emulated = $candidate } + } + } + if ($emulated) { Write-Host "no $HostArch build found, falling back to $emulated (emulated)" } + return $emulated +} + +# The nightly release build, same one CI uses. Windows ships the bare .exe, x64 only. +function Save-NightlyValidator { + if ($HostArch -ne 'x64') { + Write-Host "the nightly Windows validator is x64; it runs here under emulation" + } + $exe = Join-Path $WorkDir 'validator\OrcaSlicer_profile_validator.exe' + Save-Asset -Url "$ValidatorReleaseUrl/OrcaSlicer_profile_validator_Windows_nightly.exe" -Dest $exe + return $exe +} + +function Resolve-Validator { + if ($Validator) { + if (-not (Test-Path -LiteralPath $Validator -PathType Leaf)) { Die "validator not found: $Validator" } + return (Resolve-Path -LiteralPath $Validator).Path + } + if (-not $Download) { + $local = Find-LocalValidator + if ($local) { + Write-Host "using locally built validator: $local" + return $local + } + } + try { $downloaded = Save-NightlyValidator } catch { Die "could not obtain a profile validator: $_" } + Write-Host "using downloaded validator: $downloaded" + return $downloaded +} + +# python3 is rarely on PATH on Windows: the py launcher is the reliable way in, and a bare +# `python` may be the Store stub, which prints an advert and exits non-zero. Probe each for the +# interpreter it actually resolves to, and use that. +function Resolve-Python { + $ErrorActionPreference = 'Continue' + if ($script:Python) { return $script:Python } + foreach ($candidate in 'py -3', 'python', 'python3') { + $words = $candidate -split ' ' + $exe = Get-Command $words[0] -CommandType Application -ErrorAction SilentlyContinue | Select-Object -First 1 + if (-not $exe) { continue } + $leading = @($words | Select-Object -Skip 1) + $found = & $exe.Source @leading -c 'import sys; print(sys.executable)' 2>$null + if ($LASTEXITCODE -eq 0 -and $found) { + $script:Python = "$found" + return $script:Python + } + } + Die 'no Python 3 found; install it (or the py launcher) and re-run' +} + +# ---------------------------------------------------------------------------- checks + +$CheckBodies = @{ + + extra_json_check = { + Invoke-Tool -Exe (Resolve-Python) -Arguments @((Join-Path $RepoRoot 'scripts\orca_extra_profile_check.py')) + } + + validate_system = { + Invoke-Tool -Exe $Validator -Arguments @('-p', $ProfilesDir, '-l', "$LogLevel") + } + + # Slices a two-colour cube through every printer so all custom g-code (incl. + # change_filament_gcode) is expanded - catches undefined-placeholder / invalid-flow bugs the + # static checks cannot see. + validate_slice = { + Invoke-Tool -Exe $Validator -Arguments @('-p', $ProfilesDir, '-s', '-l', "$LogLevel") + } + + validate_filament_subtypes = { + Invoke-Tool -Exe $Validator -Arguments @('-p', $ProfilesDir, '-l', "$LogLevel", '-f') + } + + # Every released fixture is a snapshot of user presets saved by that OrcaSlicer version; each + # is unpacked over the current system profiles and validated, so a profile change that would + # break an existing user's presets fails here. + validate_custom = { + $fixturesDir = Join-Path $WorkDir 'profile-fixtures' + $outputDir = Join-Path $WorkDir 'custom-preset-validation' + New-Item -ItemType Directory -Force -Path $fixturesDir, $outputDir | Out-Null + + $manifestPath = Join-Path $fixturesDir 'manifest.json' + Save-Asset -Url "$FixtureReleaseUrl/manifest.json" -Dest $manifestPath -Force + + $manifest = Get-Content -LiteralPath $manifestPath -Raw | ConvertFrom-Json + $entries = if ($manifest -is [array]) { $manifest } else { $manifest.fixtures } + $fixtures = @($entries | Where-Object { $_.version -and $_.asset }) + if (-not $fixtures) { + Write-CheckLog "No custom preset fixtures found in $FixtureReleaseUrl/manifest.json" + return 1 + } + + $status = 0 + $failedLogs = @() + $summary = @('## Custom Preset Fixture Validation', '', '| Version | Status | Log |', '| --- | --- | --- |') + + foreach ($fixture in $fixtures) { + $version = $fixture.version + $asset = $fixture.asset + $fixtureZip = Join-Path $fixturesDir $asset + $profileTree = Join-Path $outputDir "profiles-$version" + $logPath = Join-Path $outputDir "$version.log" + $assetUrl = "$FixtureReleaseUrl/$([uri]::EscapeDataString($asset))" + + Save-Asset -Url $assetUrl -Dest $fixtureZip + + $expected = $fixture.asset_sha256 + if ($expected -and $expected -ne '<sha256>' -and (Get-Sha256 $fixtureZip) -ne $expected.ToUpperInvariant()) { + # A cached zip can be stale or truncated; the release asset itself is immutable, + # so deleting it forces Save-Asset to pull a fresh copy. + Write-Host "checksum mismatch for $asset, re-downloading" + Remove-Item -LiteralPath $fixtureZip -Force + Save-Asset -Url $assetUrl -Dest $fixtureZip + $actual = Get-Sha256 $fixtureZip + if ($actual -ne $expected.ToUpperInvariant()) { + Write-CheckLog "${asset}: expected $expected, got $actual" + return 1 + } + } + + Write-Host "validating custom presets from $version ..." + Remove-Item -LiteralPath $profileTree -Recurse -Force -ErrorAction SilentlyContinue + New-Item -ItemType Directory -Force -Path $profileTree | Out-Null + # Piped rather than copied through <profiles>\*, so a vendor directory whose name + # holds a wildcard character is still copied by its literal path. + Get-ChildItem -LiteralPath $ProfilesDir -Force | Copy-Item -Destination $profileTree -Recurse -Force + Remove-Item -LiteralPath (Join-Path $profileTree 'user') -Recurse -Force -ErrorAction SilentlyContinue + Expand-Archive -LiteralPath $fixtureZip -DestinationPath $profileTree -Force + + $result = Invoke-Tool -Exe $Validator -Arguments @('-p', $profileTree, '-l', "$LogLevel") -OutFile $logPath + if ($result -eq 0) { + $summary += "| $version | PASS | $version.log |" + # Only failures are worth keeping; each tree is a full copy of resources\profiles. + Remove-Item -LiteralPath $profileTree -Recurse -Force + } else { + $summary += "| $version | FAIL | $version.log |" + $failedLogs += $logPath + $status = 1 + } + } + + [IO.File]::WriteAllLines((Join-Path $outputDir 'summary.md'), [string[]] $summary) + $summary | ForEach-Object { Write-CheckLog $_ } + + if ($failedLogs) { + Write-CheckLog '' + Write-CheckLog '## Failed Fixture Logs' + foreach ($logPath in $failedLogs) { + Write-CheckLog '' + Write-CheckLog "### $([IO.Path]::GetFileNameWithoutExtension($logPath))" + Write-CheckLog '```' + Write-CheckLog (Get-LogHead $logPath 12000) + Write-CheckLog '```' + } + } + return $status + } +} + +# Heading CI puts above this check's log in the PR comment. +$CommentHeadings = @{ + extra_json_check = '### Extra JSON Check Failed' + validate_system = '### System Profile Validation Failed' + validate_slice = '### Slice Validation Failed (custom g-code expansion)' + validate_filament_subtypes = '### Filament Subtype Validation Failed' + validate_custom = '### Custom Preset Validation Failed' +} + +# ---------------------------------------------------------------------------- run + +function Invoke-Check([string] $Name) { + $log = Join-Path $LogDir "$Name.log" + Write-Host '' + Write-Host "==> $Name" -ForegroundColor Cyan + + $script:LogWriter = New-LogWriter $log + try { + $result = & $CheckBodies[$Name] | Select-Object -Last 1 + } catch { + Write-CheckLog "$_" + $result = 1 + } finally { + $script:LogWriter.Dispose() + $script:LogWriter = $null + } + + if ([int] $result -eq 0) { + Write-Host " $Name passed" -ForegroundColor Green + return $true + } + Write-Host " $Name failed (exit $result)" -ForegroundColor Red + return $false +} + +# The fixture trees under the work dir are shared scratch space keyed by fixture version, so a +# second run would delete a tree the first one is validating. +$LockDir = Join-Path $WorkDir '.lock' +try { New-Item -ItemType Directory -Path $LockDir -ErrorAction Stop | Out-Null } +catch { Die "another run is using $WorkDir (pass -WorkDir, or remove $LockDir if no run is active)" } + +# The validator writes UTF-8, but PowerShell decodes a child process's output using the console +# code page, which mangles the accented and CJK preset names in its messages. +$PreviousOutputEncoding = [Console]::OutputEncoding + +try { + [Console]::OutputEncoding = New-Object Text.UTF8Encoding($false) + Push-UserPresets + + if ($Checks | Where-Object { $_ -ne 'extra_json_check' }) { $Validator = Resolve-Validator } + + $results = [ordered] @{} + foreach ($name in $AllChecks) { + if ($Checks -contains $name) { $results[$name] = Invoke-Check $name } + } + + Write-Host '' + Write-Host '==> summary' -ForegroundColor Cyan + foreach ($name in $results.Keys) { + if ($results[$name]) { + Write-Host " PASS $name" -ForegroundColor Green + } else { + Write-Host " FAIL $name ($(Join-Path $LogDir "$name.log"))" -ForegroundColor Red + } + } + + $failed = @($results.Keys | Where-Object { -not $results[$_] }) + if (-not $failed) { + Remove-Item -LiteralPath (Join-Path $WorkDir 'pr_comment.md') -Force -ErrorAction SilentlyContinue + Write-Host '' + Write-Host "All checks passed. Logs: $LogDir" -ForegroundColor Green + exit 0 + } + + # The comment check_profiles_comment.yml would post when something fails. + $comment = @( + # Marker matched by check_profiles_comment.yml to delete prior comments. + '<!-- profile-validation-comment -->' + '## :x: Profile Validation Errors' + '' + foreach ($name in $failed) { + $CommentHeadings[$name] + '' + '```' + Get-LogHead (Join-Path $LogDir "$name.log") 30000 + '```' + '' + } + '---' + '*Please fix the above errors and push a new commit.*' + ) + $commentPath = Join-Path $WorkDir 'pr_comment.md' + [IO.File]::WriteAllLines($commentPath, [string[]] $comment) + + Write-Host '' + Write-Host "One or more profile checks failed. Logs: $LogDir" -ForegroundColor Red + Write-Host "The comment CI would post: $commentPath" + exit 1 +} finally { + Pop-UserPresets + Remove-Item -LiteralPath $LockDir -Force -ErrorAction SilentlyContinue + [Console]::OutputEncoding = $PreviousOutputEncoding +} diff --git a/scripts/check_profile.sh b/scripts/check_profile.sh new file mode 100755 index 0000000000..9b841d0612 --- /dev/null +++ b/scripts/check_profile.sh @@ -0,0 +1,527 @@ +#!/usr/bin/env bash +# +# Local twin of the "Check profiles" CI job (.github/workflows/check_profiles.yml). +# +# Runs the same five checks, in the same order, with the same validator flags, and with the +# same semantics: every check runs even after an earlier one fails (the workflow's +# continue-on-error), then the script exits non-zero once at the end. +# +# Everything that has to be downloaded - the profile validator and the custom-preset fixture +# archives - lands under <repo>/.test/check_profiles/ and is reused on the next run. That +# directory also holds one log per check plus a copy of the comment CI would post on the PR. +# +# resources/profiles/user, which the validator creates as its data dir but a CI checkout never +# has, is moved aside for the duration of the run and restored on exit. Only one run per work +# dir at a time. +# +# Usage: scripts/check_profile.sh [OPTION]... [CHECK]... + +# The check_* functions run through run_check, which dispatches on the check name, so +# ShellCheck cannot see that they (and what they call) are used. +# shellcheck disable=SC2329 + +set -uo pipefail + +VALIDATOR_RELEASE_URL="https://github.com/OrcaSlicer/OrcaSlicer/releases/download/nightly-builds" +FIXTURE_RELEASE_URL="https://github.com/OrcaSlicer/OrcaSlicer-profile-validator/releases/download/fixture-archive" + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)" + +HOST_ARCH="$(uname -m)" + +PROFILES_DIR="${REPO_ROOT}/resources/profiles" +WORK_DIR="${REPO_ROOT}/.test/check_profiles" +VALIDATOR="${ORCA_PROFILE_VALIDATOR:-}" +LOG_LEVEL=2 +PREFER_DOWNLOAD=0 +REFRESH=0 + +ALL_CHECKS=(extra_json_check validate_system validate_slice validate_filament_subtypes validate_custom) +CHECKS=() +# "<check><TAB>pass|fail" per check that ran; a string rather than an array because bash 3.2 +# (still the /bin/bash on macOS) cannot expand an empty array under `set -u`. +RESULTS="" + +usage() { + cat <<EOF +Run the profile checks from .github/workflows/check_profiles.yml locally. + +Usage: scripts/check_profile.sh [OPTION]... [CHECK]... + +Checks (default: all, in this order): + extra_json_check scripts/orca_extra_profile_check.py + validate_system validator -p <profiles> -l <level> + validate_slice validator -p <profiles> -s -l <level> + validate_filament_subtypes validator -p <profiles> -l <level> -f + validate_custom validator against every released custom-preset fixture + +Options: + -p, --profiles DIR profile tree to validate (default: resources/profiles) + --validator BIN OrcaSlicer_profile_validator to use; also \$ORCA_PROFILE_VALIDATOR. + Default: the local build*/ Release build (then RelWithDebInfo, then + Debug) for this architecture, else the nightly release build is + downloaded for this platform + --download ignore local builds and use the downloaded nightly validator + --refresh re-download the validator and fixtures instead of using the cache + --work-dir DIR downloads, logs and fixture trees (default: .test/check_profiles) + -l, --log-level N validator log level (default: ${LOG_LEVEL}, as in CI) + -h, --help show this help + +Note: extra_json_check always looks at the tree next to the script +(<repo>/resources/profiles); --profiles only redirects the validator checks. +EOF +} + +msg() { printf '%s\n' "$*" >&2; } +die() { printf 'check_profile.sh: %s\n' "$*" >&2; exit 2; } + +if [ -t 1 ]; then + C_RED=$'\033[91m'; C_GREEN=$'\033[92m'; C_BOLD=$'\033[1m'; C_RESET=$'\033[0m' +else + C_RED=''; C_GREEN=''; C_BOLD=''; C_RESET='' +fi + +# ---------------------------------------------------------------------------- arguments + +while [ $# -gt 0 ]; do + case "$1" in + -h|--help) usage; exit 0 ;; + -p|--profiles) [ $# -ge 2 ] || die "$1 needs a directory"; PROFILES_DIR="$2"; shift 2 ;; + --validator) [ $# -ge 2 ] || die "$1 needs a path"; VALIDATOR="$2"; shift 2 ;; + --work-dir) [ $# -ge 2 ] || die "$1 needs a directory"; WORK_DIR="$2"; shift 2 ;; + -l|--log-level) [ $# -ge 2 ] || die "$1 needs a number"; LOG_LEVEL="$2"; shift 2 ;; + --download) PREFER_DOWNLOAD=1; shift ;; + --refresh) REFRESH=1; shift ;; + -*) die "unknown option '$1' (try --help)" ;; + *) + known=0 + for check in "${ALL_CHECKS[@]}"; do + [ "$1" = "${check}" ] && known=1 + done + [ "${known}" -eq 1 ] || die "unknown check '$1' (try --help)" + CHECKS[${#CHECKS[@]}]="$1" + shift + ;; + esac +done + +[ "${#CHECKS[@]}" -gt 0 ] || CHECKS=("${ALL_CHECKS[@]}") + +[ -d "${PROFILES_DIR}" ] || die "profile directory not found: ${PROFILES_DIR}" +PROFILES_DIR="$(cd -- "${PROFILES_DIR}" && pwd)" + +LOG_DIR="${WORK_DIR}/logs" +mkdir -p "${LOG_DIR}" || die "cannot create ${LOG_DIR}" +WORK_DIR="$(cd -- "${WORK_DIR}" && pwd)" +LOG_DIR="${WORK_DIR}/logs" + +wants() { + local check + for check in "${CHECKS[@]}"; do + [ "${check}" = "$1" ] && return 0 + done + return 1 +} + +# ------------------------------------------------------------------- clean profile tree + +# The validator points its data dir at the profile tree, so it creates - and, with -g, fills - +# <profiles>/user. A CI checkout never has that directory, and anything left in it from an +# earlier local run would be loaded as user presets and validated too. Move it aside for the +# duration of the run so what gets checked is what CI checks. +STASHED_USER_DIR="" + +stash_user_presets() { + [ -d "${PROFILES_DIR}/user" ] || return 0 + STASHED_USER_DIR="${WORK_DIR}/user-presets-$$" + rm -rf "${STASHED_USER_DIR}" + mv "${PROFILES_DIR}/user" "${STASHED_USER_DIR}" || { STASHED_USER_DIR=""; die "cannot move ${PROFILES_DIR}/user aside"; } + msg "moved ${PROFILES_DIR}/user aside for the run (restored on exit)" +} + +restore_user_presets() { + # The validator leaves an empty user/default/{filament,machine,process} skeleton behind. + # Prune it with rmdir, never rm -rf: a directory that holds a real file survives and is + # reported instead of being deleted. Runs even when nothing was stashed, so a tree that had + # no user/ before the run does not gain one. + find "${PROFILES_DIR}/user" -depth -type d -exec rmdir {} + 2>/dev/null + [ -n "${STASHED_USER_DIR}" ] || return 0 + if [ -d "${PROFILES_DIR}/user" ]; then + msg "${PROFILES_DIR}/user is not empty; your presets stay in ${STASHED_USER_DIR}" + STASHED_USER_DIR="" + return 0 + fi + mv "${STASHED_USER_DIR}" "${PROFILES_DIR}/user" + STASHED_USER_DIR="" +} + +# The fixture trees under the work dir are shared scratch space keyed by fixture version, so a +# second run would delete a tree the first one is validating. +LOCK_DIR="${WORK_DIR}/.lock" +mkdir "${LOCK_DIR}" 2>/dev/null || + die "another run is using ${WORK_DIR} (pass --work-dir, or remove ${LOCK_DIR} if no run is active)" + +cleanup() { + restore_user_presets + rmdir "${LOCK_DIR}" 2>/dev/null +} + +# Installed only once the lock is ours, so a refused start never releases someone else's. +trap cleanup EXIT +trap 'cleanup; exit 130' INT TERM + +stash_user_presets + +# ---------------------------------------------------------------------------- downloads + +# fetch URL DEST [force] - cached; --refresh, or a non-empty third argument, forces a new +# download. Release assets never change, so caching them is safe; the fixture manifest is the +# index that grows with every release, and CI re-reads it on every run. +fetch() { + local url="$1" dest="$2" force="${3:-}" + if [ "${REFRESH}" -eq 0 ] && [ -z "${force}" ] && [ -s "${dest}" ]; then + return 0 + fi + mkdir -p "$(dirname -- "${dest}")" || return 1 + msg "downloading $(basename -- "${dest}") ..." + if ! curl -fsSL --retry 3 -o "${dest}.part" "${url}"; then + rm -f "${dest}.part" + msg "download failed: ${url}" + return 1 + fi + mv -f "${dest}.part" "${dest}" +} + +sha256_of() { + if command -v sha256sum >/dev/null 2>&1; then + sha256sum "$1" | cut -d' ' -f1 + elif command -v shasum >/dev/null 2>&1; then + shasum -a 256 "$1" | cut -d' ' -f1 + else + return 1 + fi +} + +# Directories a built validator can sit in, best first: every Ninja Multi-Config Release tree, +# then RelWithDebInfo, then Debug, then a single-config generator's plain src/. Each pattern is +# matched both directly under a build root (build/) and one level down (build/arm64, build/x64), +# and unmatched globs are dropped by the caller's -d test. +validator_search_dirs() { + local config + for config in Release RelWithDebInfo Debug; do + printf '%s\n' "${REPO_ROOT}"/build*/src/"${config}" "${REPO_ROOT}"/build*/*/src/"${config}" + done + printf '%s\n' "${REPO_ROOT}"/build*/src "${REPO_ROOT}"/build*/*/src +} + +# A build tree named for the other architecture (build/x86_64 on an arm64 host, build/arm64 on +# an x64 one) is a last resort: on Linux it will not run at all, on macOS it goes via Rosetta. +# Takes a repo-relative path - an absolute one would also match an arch name in the checkout path. +is_foreign_arch_dir() { + case "${HOST_ARCH}" in + arm64|aarch64) case "$1" in *x86_64*|*x86-64*|*x64*|*amd64*) return 0 ;; esac ;; + x86_64|amd64) case "$1" in *arm64*|*aarch64*) return 0 ;; esac ;; + esac + return 1 +} + +# First locally built OrcaSlicer_profile_validator, in the order above. macOS puts it in an .app +# bundle, Linux and Windows next to the other binaries. +find_local_validator() { + local dir candidate foreign="" + while IFS= read -r dir; do + [ -d "${dir}" ] || continue + for candidate in \ + "${dir}/OrcaSlicer_profile_validator" \ + "${dir}/OrcaSlicer_profile_validator.exe" \ + "${dir}/OrcaSlicer_profile_validator.app/Contents/MacOS/OrcaSlicer_profile_validator"; do + [ -f "${candidate}" ] && [ -x "${candidate}" ] || continue + if ! is_foreign_arch_dir "${dir#"${REPO_ROOT}"/}"; then + printf '%s\n' "${candidate}" + return 0 + fi + [ -n "${foreign}" ] || foreign="${candidate}" + done + done <<EOF +$(validator_search_dirs) +EOF + [ -n "${foreign}" ] || return 1 + msg "no ${HOST_ARCH} build found, falling back to ${foreign}" + printf '%s\n' "${foreign}" +} + +# The nightly release build, same one CI uses. Linux ships the bare binary, macOS a .dmg +# holding the signed .app, Windows an .exe. +download_validator() { + local dest="${WORK_DIR}/validator" binary dmg app mounted app_src + case "$(uname -s)" in + Linux*) + case "${HOST_ARCH}" in + arm64|aarch64) msg "the nightly Linux validator is x86_64; build it locally for ${HOST_ARCH}" ;; + esac + binary="${dest}/OrcaSlicer_profile_validator" + fetch "${VALIDATOR_RELEASE_URL}/OrcaSlicer_profile_validator_Linux_Ubuntu2404_nightly" "${binary}" || return 1 + chmod +x "${binary}" || return 1 + ;; + Darwin*) + dmg="${dest}/OrcaSlicer_profile_validator.dmg" + app="${dest}/OrcaSlicer_profile_validator.app" + binary="${app}/Contents/MacOS/OrcaSlicer_profile_validator" + fetch "${VALIDATOR_RELEASE_URL}/OrcaSlicer_profile_validator_Mac_universal_nightly.dmg" "${dmg}" || return 1 + if [ ! -x "${binary}" ] || [ "${REFRESH}" -eq 1 ]; then + mounted="${dest}/mnt" + rm -rf "${mounted}" "${app}" + mkdir -p "${mounted}" || return 1 + hdiutil attach -nobrowse -readonly -mountpoint "${mounted}" "${dmg}" >/dev/null || return 1 + app_src="$(find "${mounted}" -maxdepth 1 -name '*.app' -print 2>/dev/null | head -n 1)" + if [ -n "${app_src}" ]; then + cp -R "${app_src}" "${app}" + fi + hdiutil detach "${mounted}" >/dev/null 2>&1 + rmdir "${mounted}" 2>/dev/null + [ -x "${binary}" ] || { msg "no validator app inside ${dmg}"; return 1; } + fi + ;; + MINGW*|MSYS*|CYGWIN*) + binary="${dest}/OrcaSlicer_profile_validator.exe" + fetch "${VALIDATOR_RELEASE_URL}/OrcaSlicer_profile_validator_Windows_nightly.exe" "${binary}" || return 1 + chmod +x "${binary}" || return 1 + ;; + *) + msg "no nightly validator published for $(uname -s); build it (-DORCA_TOOLS=ON) and pass --validator" + return 1 + ;; + esac + printf '%s\n' "${binary}" +} + +resolve_validator() { + if [ -n "${VALIDATOR}" ]; then + [ -x "${VALIDATOR}" ] || die "validator not executable: ${VALIDATOR}" + return 0 + fi + if [ "${PREFER_DOWNLOAD}" -eq 0 ]; then + VALIDATOR="$(find_local_validator)" + if [ -n "${VALIDATOR}" ]; then + msg "using locally built validator: ${VALIDATOR}" + return 0 + fi + fi + VALIDATOR="$(download_validator)" || die "could not obtain a profile validator" + msg "using downloaded validator: ${VALIDATOR}" +} + +# ---------------------------------------------------------------------------- checks + +check_extra_json_check() { + python3 "${REPO_ROOT}/scripts/orca_extra_profile_check.py" +} + +check_validate_system() { + "${VALIDATOR}" -p "${PROFILES_DIR}" -l "${LOG_LEVEL}" +} + +# Slices a two-colour cube through every printer so all custom g-code (incl. change_filament_gcode) +# is expanded - catches undefined-placeholder / invalid-flow bugs the static checks cannot see. +check_validate_slice() { + "${VALIDATOR}" -p "${PROFILES_DIR}" -s -l "${LOG_LEVEL}" +} + +check_validate_filament_subtypes() { + "${VALIDATOR}" -p "${PROFILES_DIR}" -l "${LOG_LEVEL}" -f +} + +# Every released fixture is a snapshot of user presets saved by that OrcaSlicer version; each is +# unpacked over the current system profiles and validated, so a profile change that would break +# an existing user's presets fails here. +check_validate_custom() { + local fixtures_dir="${WORK_DIR}/profile-fixtures" + local output_dir="${WORK_DIR}/custom-preset-validation" + local summary="${output_dir}/summary.md" + local status=0 failed_logs="" + local version asset expected_sha256 asset_url fixture_zip profile_tree log_path actual_sha256 result + + command -v unzip >/dev/null 2>&1 || { msg "unzip is required for validate_custom"; return 1; } + mkdir -p "${fixtures_dir}" "${output_dir}" || return 1 + + fetch "${FIXTURE_RELEASE_URL}/manifest.json" "${fixtures_dir}/manifest.json" force || return 1 + + MANIFEST_PATH="${fixtures_dir}/manifest.json" python3 - > "${fixtures_dir}/fixtures.tsv" <<'PY' +import json +import os + +with open(os.environ["MANIFEST_PATH"], encoding="utf-8") as fh: + manifest = json.load(fh) + +if isinstance(manifest, dict): + entries = manifest.get("fixtures", []) +else: + entries = manifest + +for entry in entries: + version = entry.get("version", "") + asset = entry.get("asset", "") + sha256 = entry.get("asset_sha256", "") + if not version or not asset: + continue + print(f"{version}\t{asset}\t{sha256}") +PY + + if [ ! -s "${fixtures_dir}/fixtures.tsv" ]; then + echo "No custom preset fixtures found in ${FIXTURE_RELEASE_URL}/manifest.json" + return 1 + fi + + { + echo "## Custom Preset Fixture Validation" + echo "" + echo "| Version | Status | Log |" + echo "| --- | --- | --- |" + } > "${summary}" + + while IFS=$'\t' read -r version asset expected_sha256; do + [ -n "${version}" ] || continue + fixture_zip="${fixtures_dir}/${asset}" + profile_tree="${output_dir}/profiles-${version}" + log_path="${output_dir}/${version}.log" + + asset_url="${FIXTURE_RELEASE_URL}/$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "${asset}")" + fetch "${asset_url}" "${fixture_zip}" || return 1 + + if [ -n "${expected_sha256}" ] && [ "${expected_sha256}" != "<sha256>" ]; then + actual_sha256="$(sha256_of "${fixture_zip}")" + if [ -z "${actual_sha256}" ]; then + msg "no sha256 tool available, skipping checksum of ${asset}" + elif [ "${actual_sha256}" != "${expected_sha256}" ]; then + # A cached zip can be stale or truncated; the release asset itself is immutable, + # so deleting it forces fetch to pull a fresh copy. + msg "checksum mismatch for ${asset}, re-downloading" + rm -f "${fixture_zip}" + fetch "${asset_url}" "${fixture_zip}" || return 1 + actual_sha256="$(sha256_of "${fixture_zip}")" + [ "${actual_sha256}" = "${expected_sha256}" ] || { msg "${asset}: expected ${expected_sha256}, got ${actual_sha256}"; return 1; } + fi + fi + + msg "validating custom presets from ${version} ..." + rm -rf "${profile_tree}" + mkdir -p "${profile_tree}" || return 1 + cp -a "${PROFILES_DIR}/." "${profile_tree}/" || return 1 + rm -rf "${profile_tree}/user" + unzip -q "${fixture_zip}" -d "${profile_tree}" || return 1 + + "${VALIDATOR}" -p "${profile_tree}" -l "${LOG_LEVEL}" > "${log_path}" 2>&1 + result=$? + + if [ "${result}" -eq 0 ]; then + echo "| ${version} | PASS | ${version}.log |" >> "${summary}" + # Only failures are worth keeping; each tree is a full copy of resources/profiles. + rm -rf "${profile_tree}" + else + echo "| ${version} | FAIL | ${version}.log |" >> "${summary}" + failed_logs="${failed_logs}${log_path}"$'\n' + status=1 + fi + done < "${fixtures_dir}/fixtures.tsv" + + cat "${summary}" + if [ -n "${failed_logs}" ]; then + echo "" + echo "## Failed Fixture Logs" + while IFS= read -r log_path; do + [ -n "${log_path}" ] || continue + echo "" + echo "### $(basename "${log_path}" .log)" + echo '```' + head -c 12000 "${log_path}" || echo "No output captured" + echo '```' + done <<EOF +${failed_logs} +EOF + fi + + return "${status}" +} + +# Heading CI puts above this check's log in the PR comment. +comment_heading() { + case "$1" in + extra_json_check) echo "### Extra JSON Check Failed" ;; + validate_system) echo "### System Profile Validation Failed" ;; + validate_slice) echo "### Slice Validation Failed (custom g-code expansion)" ;; + validate_filament_subtypes) echo "### Filament Subtype Validation Failed" ;; + validate_custom) echo "### Custom Preset Validation Failed" ;; + esac +} + +# ---------------------------------------------------------------------------- run + +run_check() { + local name="$1" + local log="${LOG_DIR}/${name}.log" + local result + printf '\n%s==> %s%s\n' "${C_BOLD}" "${name}" "${C_RESET}" + "check_${name}" 2>&1 | tee "${log}" + result="${PIPESTATUS[0]}" + if [ "${result}" -eq 0 ]; then + printf '%s %s passed%s\n' "${C_GREEN}" "${name}" "${C_RESET}" + RESULTS="${RESULTS}${name}"$'\t'"pass"$'\n' + else + printf '%s %s failed (exit %s)%s\n' "${C_RED}" "${name}" "${result}" "${C_RESET}" + RESULTS="${RESULTS}${name}"$'\t'"fail"$'\n' + fi +} + +if wants validate_system || wants validate_slice || wants validate_filament_subtypes || wants validate_custom; then + resolve_validator +fi + +for check in "${ALL_CHECKS[@]}"; do + wants "${check}" && run_check "${check}" +done + +# Summary, plus the comment check_profiles_comment.yml would post when something fails. +failed=0 +printf '\n%s==> summary%s\n' "${C_BOLD}" "${C_RESET}" +while IFS=$'\t' read -r name result; do + [ -n "${name}" ] || continue + if [ "${result}" = "pass" ]; then + printf '%s PASS%s %s\n' "${C_GREEN}" "${C_RESET}" "${name}" + else + printf '%s FAIL%s %s (%s)\n' "${C_RED}" "${C_RESET}" "${name}" "${LOG_DIR}/${name}.log" + failed=1 + fi +done <<EOF +${RESULTS} +EOF + +if [ "${failed}" -eq 0 ]; then + rm -f "${WORK_DIR}/pr_comment.md" + printf '\n%sAll checks passed.%s Logs: %s\n' "${C_GREEN}" "${C_RESET}" "${LOG_DIR}" + exit 0 +fi + +{ + # Marker matched by check_profiles_comment.yml to delete prior comments. + echo "<!-- profile-validation-comment -->" + echo "## :x: Profile Validation Errors" + echo "" + while IFS=$'\t' read -r name result; do + [ "${result}" = "fail" ] || continue + comment_heading "${name}" + echo "" + echo '```' + head -c 30000 "${LOG_DIR}/${name}.log" || echo "No output captured" + echo '```' + echo "" + done <<INNER +${RESULTS} +INNER + echo "---" + echo "*Please fix the above errors and push a new commit.*" +} > "${WORK_DIR}/pr_comment.md" + +printf '\n%sOne or more profile checks failed.%s Logs: %s\n' "${C_RED}" "${C_RESET}" "${LOG_DIR}" +printf 'The comment CI would post: %s\n' "${WORK_DIR}/pr_comment.md" +exit 1 From 1749c293a6ed71172959d6e16d9e98759aab8fcb Mon Sep 17 00:00:00 2001 From: Kris Austin <kris.austin@gmail.com> Date: Wed, 2 Sep 2026 05:38:05 -0500 Subject: [PATCH 24/51] build: clear 237 warnings - unused lambda captures (#15417) * build: enable /Zc:lambda for MSVC MSVC keeps its legacy lambda processor under /std:c++17, which rejects reading a constexpr constant inside a lambda that does not capture it (C3493). No other compiler requires that capture, and clang reports it as an unused one, so the two cannot both be satisfied without the flag. /Zc:lambda selects the conforming lambda parser that clang and GCC already use. It is implied by /std:c++20 and /permissive-, so it is only needed while we are on C++17. clang-cl is conforming already and does not take the flag. It requires VS2019 16.8, so build_release_vs.bat now says 16.8+. * build: clear 237 unused lambda capture warnings 236 captures across 81 files, 142 of them `this`. Removing an unused capture changes no behavior; clang does not report a capture whose type has a non-trivial destructor, so nothing held only to extend an object's lifetime is in this set. Nine of them are the second half of the warning, "is not required to be captured for this use", where the capture is a const or constexpr value the body does read. Those depend on the /Zc:lambda change in the previous commit. One of them, in FillRectilinear.cpp, had been worked around with an #ifndef __APPLE__ guard around the capture list, which is now gone. GUI_ObjectTableSettings.cpp captured its reset button only to read it inside #ifdef __WXOSX_MAC__. That branch now takes the button from the event it is already handling. * build: fail configure on MSVC older than 19.28 instead of dropping /Zc:lambda cl.exe answers an unrecognized /Zc: sub-option with warning D9002 and keeps going, so on VS2019 before 16.8 the flag is silently ignored and the build instead dies with C3493 in FillRectilinear.cpp, nowhere near the cause. * fix: delete three locals that are now unused Their only remaining use was the lambda capture this branch removed. The Clang builds set -Wno-unused-variable, so the build never flagged them. --------- Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> --- CMakeLists.txt | 16 ++++++ build_release_vs.bat | 2 +- src/OrcaSlicer.cpp | 2 +- src/libslic3r/Arrange.cpp | 2 +- src/libslic3r/Fill/FillRectilinear.cpp | 7 +-- src/libslic3r/GCode/GCodeProcessor.cpp | 8 +-- src/libslic3r/GCode/WipeTower.cpp | 4 +- src/libslic3r/Model.cpp | 2 +- src/libslic3r/PresetBundle.cpp | 4 +- src/libslic3r/Print.cpp | 4 +- src/libslic3r/PrintObject.cpp | 2 +- src/libslic3r/PrintObjectSlice.cpp | 4 +- src/libslic3r/Support/SupportCommon.cpp | 2 +- src/libslic3r/Support/SupportMaterial.cpp | 2 +- src/libslic3r/Support/TreeSupport.cpp | 2 +- src/slic3r/GUI/AMSDryControl.cpp | 6 +- src/slic3r/GUI/BindDialog.cpp | 6 +- src/slic3r/GUI/CaliHistoryDialog.cpp | 2 +- src/slic3r/GUI/Calibration.cpp | 2 +- src/slic3r/GUI/CalibrationWizard.cpp | 2 +- src/slic3r/GUI/CalibrationWizardCaliPage.cpp | 2 +- src/slic3r/GUI/CalibrationWizardPage.cpp | 2 +- src/slic3r/GUI/CalibrationWizardSavePage.cpp | 6 +- src/slic3r/GUI/CameraPopup.cpp | 2 +- src/slic3r/GUI/ConfigWizard.cpp | 2 +- src/slic3r/GUI/CreatePresetsDialog.cpp | 2 +- src/slic3r/GUI/Field.cpp | 2 +- src/slic3r/GUI/FilamentPickerDialog.cpp | 4 +- src/slic3r/GUI/GCodeViewer.cpp | 24 ++++---- src/slic3r/GUI/GLCanvas3D.cpp | 20 +++---- src/slic3r/GUI/GUI_App.cpp | 10 ++-- src/slic3r/GUI/GUI_AuxiliaryList.cpp | 2 +- src/slic3r/GUI/GUI_Factories.cpp | 14 ++--- src/slic3r/GUI/GUI_ObjectLayers.cpp | 2 +- src/slic3r/GUI/GUI_ObjectList.cpp | 8 +-- src/slic3r/GUI/GUI_ObjectTable.cpp | 4 +- src/slic3r/GUI/GUI_ObjectTableSettings.cpp | 17 +++--- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- .../GUI/Gizmos/GizmoObjectManipulation.cpp | 2 +- src/slic3r/GUI/HMS.cpp | 4 +- src/slic3r/GUI/Jobs/FillBedJob.cpp | 2 +- src/slic3r/GUI/Jobs/PrintJob.cpp | 5 +- src/slic3r/GUI/Jobs/RotoptimizeJob.cpp | 2 +- src/slic3r/GUI/Jobs/SendJob.cpp | 3 +- src/slic3r/GUI/MainFrame.cpp | 28 ++++----- src/slic3r/GUI/MultiMachine.cpp | 2 +- src/slic3r/GUI/MultiMachineManagerPage.cpp | 2 +- src/slic3r/GUI/MultiMachinePage.cpp | 2 +- src/slic3r/GUI/MultiTaskManagerPage.cpp | 2 +- src/slic3r/GUI/NetworkPluginDialog.cpp | 4 +- src/slic3r/GUI/NetworkTestDialog.cpp | 2 +- src/slic3r/GUI/Notebook.cpp | 2 +- src/slic3r/GUI/OG_CustomCtrl.cpp | 2 +- src/slic3r/GUI/ObjColorDialog.cpp | 2 +- src/slic3r/GUI/ParamsPanel.cpp | 6 +- src/slic3r/GUI/Plater.cpp | 57 +++++++++---------- src/slic3r/GUI/Preferences.cpp | 6 +- src/slic3r/GUI/PresetComboBoxes.cpp | 4 +- src/slic3r/GUI/PrintHostDialogs.cpp | 2 +- src/slic3r/GUI/Printer/PrinterFileSystem.cpp | 4 +- src/slic3r/GUI/PrivacyUpdateDialog.cpp | 2 +- src/slic3r/GUI/ReleaseNote.cpp | 2 +- src/slic3r/GUI/SavePresetDialog.cpp | 2 +- src/slic3r/GUI/SelectMachine.cpp | 8 +-- src/slic3r/GUI/SelectMachinePop.cpp | 12 ++-- src/slic3r/GUI/SendMultiMachinePage.cpp | 2 +- src/slic3r/GUI/SkipPartCanvas.cpp | 4 +- src/slic3r/GUI/SliceInfoPanel.cpp | 2 +- src/slic3r/GUI/StepMeshDialog.cpp | 4 +- src/slic3r/GUI/SyncAmsInfoDialog.cpp | 4 +- src/slic3r/GUI/Tab.cpp | 14 ++--- src/slic3r/GUI/TroubleshootDialog.cpp | 4 +- src/slic3r/GUI/WebGuideDialog.cpp | 4 +- src/slic3r/GUI/WebUserLoginDialog.cpp | 4 +- src/slic3r/Utils/3DPrinterOS.cpp | 2 +- src/slic3r/Utils/Moonraker.cpp | 4 +- src/slic3r/Utils/Obico.cpp | 2 +- src/slic3r/Utils/PresetUpdater.cpp | 2 +- src/slic3r/Utils/Repetier.cpp | 2 +- src/slic3r/Utils/SimplyPrint.cpp | 6 +- 83 files changed, 226 insertions(+), 217 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f5ccbeb44..972627d0c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -362,6 +362,22 @@ if (MSVC) if (SLIC3R_MSVC_COMPILE_PARALLEL AND CMAKE_GENERATOR MATCHES "Visual Studio") add_compile_options(/MP) endif () + + # Parse lambdas the way the standard says, as clang and GCC already do. Without it + # MSVC keeps its legacy lambda processor under /std:c++17 and rejects reading a + # constexpr constant inside a lambda that does not capture it (C3493), which no + # other compiler requires. Implied by /std:c++20 and /permissive-, so it is only + # needed while we are on C++17. clang-cl is conforming already and does not take + # the flag. Requires VS2019 16.8 or newer. + if (NOT IS_CLANG_CL) + # cl.exe only warns (D9002) about an unknown /Zc: option, so without this the + # flag would be dropped and the first lambda reading a constexpr constant would + # fail with C3493 far from the cause. + if (MSVC_VERSION LESS 1928) + message(FATAL_ERROR "Visual Studio 2019 16.8 (MSVC 19.28) or newer is required; detected MSVC ${MSVC_VERSION}.") + endif () + add_compile_options(/Zc:lambda) + endif () # /bigobj (Increase Number of Sections in .Obj file) # error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm90' or greater # Generate symbols at every build target, even for the release. diff --git a/build_release_vs.bat b/build_release_vs.bat index a52d940455..3842f1d198 100644 --- a/build_release_vs.bat +++ b/build_release_vs.bat @@ -86,7 +86,7 @@ if "%VS_MAJOR%"=="16" ( set CMAKE_GENERATOR="Visual Studio 18 2026" ) else ( echo Error: Unsupported Visual Studio version: %VS_MAJOR% - echo Supported versions: VS2019 (16.x^), VS2022 (17.x^), VS2026 (18.x^) + echo Supported versions: VS2019 (16.8+^), VS2022 (17.x^), VS2026 (18.x^) exit /b 1 ) diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 8176e9f444..33669abcf2 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -1969,7 +1969,7 @@ int CLI::run(int argc, char **argv) } } - auto load_config_file = [config_substitution_rule](const std::string& file, DynamicPrintConfig& config, std::string& config_type, + auto load_config_file = [](const std::string& file, DynamicPrintConfig& config, std::string& config_type, std::string& config_name, std::string& filament_id, std::string& config_from) { if (! boost::filesystem::exists(file)) { boost::nowide::cerr << __FUNCTION__<< ": can not find setting file: " << file << std::endl; diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index 48e6950a82..fd496537f4 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -797,7 +797,7 @@ public: } }); - m_pck.unfitIndicator([this](std::string name) { + m_pck.unfitIndicator([](std::string name) { BOOST_LOG_TRIVIAL(debug) << "arrange progress: " + name; }); diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp index 0c82354b38..db340748ab 100644 --- a/src/libslic3r/Fill/FillRectilinear.cpp +++ b/src/libslic3r/Fill/FillRectilinear.cpp @@ -2395,12 +2395,7 @@ static std::vector<MonotonicRegionLink> chain_monotonic_regions( } // Probability (unnormalized) of traversing a link between two monotonic regions. - auto path_probability = [ -#ifndef __APPLE__ - // clang complains when capturing constexpr constants. - pheromone_alpha, pheromone_beta -#endif // __APPLE__ - ](AntPath &path) { + auto path_probability = [](AntPath &path) { return pow(path.pheromone, pheromone_alpha) * pow(path.visibility, pheromone_beta); }; diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 2ac8bd45a6..cd6c494f33 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -1273,7 +1273,7 @@ void GCodeProcessor::run_post_process() // add lines M73 to exported gcode auto process_line_move = [ // Lambdas, mostly for string formatting, all with an empty capture block. - time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute,format_line_exhaust_fan_control, + time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute, &self = std::as_const(m_time_processor), // Caches, to be modified &g1_times_cache_it, &last_exported_main, &last_exported_stop, @@ -5304,7 +5304,7 @@ void GCodeProcessor::process_VG1(const GCodeReader::GCodeLine& line) float filament_radius = 0.5f * filament_diameter; float area_filament_cross_section = static_cast<float>(M_PI) * sqr(filament_radius); - auto absolute_position = [this, area_filament_cross_section](Axis axis, const GCodeReader::GCodeLine& lineG1) { + auto absolute_position = [this](Axis axis, const GCodeReader::GCodeLine& lineG1) { bool is_relative = (m_global_positioning_type == EPositioningType::Relative); if (axis == E) is_relative |= (m_e_local_positioning_type == EPositioningType::Relative); @@ -5755,7 +5755,7 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line, bool cloc if (travel_length < 0.001) return; - auto adjust_target = [this, area_filament_cross_section](const AxisCoords& target, const AxisCoords& prev_position) { + auto adjust_target = [this](const AxisCoords& target, const AxisCoords& prev_position) { AxisCoords ret = target; if (m_global_positioning_type == EPositioningType::Relative) { for (unsigned char a = X; a <= E; ++a) { @@ -7006,7 +7006,7 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type, get_acceleration(normal_mode)); const float junction_deviation = get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, normal_mode_id); const bool use_jd_jerk = (m_flavor == gcfMarlinFirmware && junction_deviation > 0.0f); - const auto axis_jerk_for_preview = [this, normal_mode, use_jd_jerk, move_acceleration](Axis axis) { + const auto axis_jerk_for_preview = [this, use_jd_jerk, move_acceleration](Axis axis) { return use_jd_jerk ? get_axis_max_jerk_with_jd(normal_mode, axis, move_acceleration) : get_axis_max_jerk(normal_mode, axis); }; const float jerk_x = axis_jerk_for_preview(X); diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 5834937169..8aff5f4a3f 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -4083,7 +4083,7 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat } return time * 60.f; }; - auto estimate_wipe_time = [&estimate_time_kernel, & cleaning_box, &target_speed, &x_to_wipe, &xr, &xl, &dy, &WipeSpeedMap, &solid_tool_toolchange](int begin_line) -> float { + auto estimate_wipe_time = [&estimate_time_kernel, & cleaning_box, &x_to_wipe, &xr, &xl, &dy, &solid_tool_toolchange](int begin_line) -> float { int n = std::ceil(x_to_wipe / (xr - xl)); if (solid_tool_toolchange) n = (cleaning_box.lu[1] - cleaning_box.ld[1]) / dy; float total_time = estimate_time_kernel(n); @@ -5111,7 +5111,7 @@ Polygon WipeTower::generate_rib_polygon(const box_coordinates &wt_box) Polygon WipeTower::generate_support_wall_new(WipeTowerWriter &writer, const box_coordinates &wt_box, double feedrate, bool first_layer,bool rib_wall, bool extrude_perimeter, bool skip_points) { - auto get_closet_idx = [this, &writer](Polylines &pls) -> std::pair<int,int> { + auto get_closet_idx = [&writer](Polylines &pls) -> std::pair<int,int> { Vec2f anchor{writer.x(), writer.y()}; int closestIndex = -1; int closestPl = -1; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index bbc3aa80f3..8f1dd8926c 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -877,7 +877,7 @@ void Model::convert_multipart_object(unsigned int max_extruders) // Revert the centering operation. trafo_volume.set_offset(trafo_volume.get_offset() - o->origin_translation); int counter = 1; - auto copy_volume = [o, v, max_extruders, &counter, &extruder_counter](ModelVolume *new_v) { + auto copy_volume = [o, v, &counter](ModelVolume *new_v) { assert(new_v != nullptr); new_v->name = (counter > 1) ? o->name + "_" + std::to_string(counter++) : o->name; //BBS: Use extruder priority: volumn > object > default diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index 53524887a9..8e5d565c55 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -2157,7 +2157,7 @@ int PresetBundle::validate_presets(const std::string &file_name, DynamicPrintCon void PresetBundle::remove_users_preset(AppConfig &config, std::map<std::string, std::map<std::string, std::string>> *my_presets) { - auto check_removed = [my_presets, this](Preset &preset) -> bool { + auto check_removed = [my_presets](Preset &preset) -> bool { if (my_presets == nullptr) return true; if (my_presets->find(preset.name) != my_presets->end()) return false; if (!preset.sync_info.empty()) return false; // syncing, not remove @@ -3412,7 +3412,7 @@ void PresetBundle::get_ams_cobox_infos(AMSComboInfo& combox_info) combox_info.ams_names.push_back(ams_name); continue; } - iter = std::find_if(filaments.begin(), filaments.end(), [&filament_type](auto &f) { return f.is_compatible && f.is_system; }); + iter = std::find_if(filaments.begin(), filaments.end(), [](auto &f) { return f.is_compatible && f.is_system; }); if (iter == filaments.end()) continue; } diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 40764342fb..e96304e874 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -2288,7 +2288,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache) obj->clear_shared_object(); //add the print_object share check logic - auto is_print_object_the_same = [this](const PrintObject* object1, const PrintObject* object2) -> bool{ + auto is_print_object_the_same = [](const PrintObject* object1, const PrintObject* object2) -> bool{ if (object1->trafo().matrix() != object2->trafo().matrix()) return false; const ModelObject* model_obj1 = object1->model_object(); @@ -5699,7 +5699,7 @@ int Print::load_cached_data(const std::string& directory) return CLI_IMPORT_CACHE_NOT_FOUND; } - auto find_region = [this](PrintObject* object, size_t config_hash) -> const PrintRegion* { + auto find_region = [](PrintObject* object, size_t config_hash) -> const PrintRegion* { int regions_count = object->num_printing_regions(); for (int index = 0; index < regions_count; index++ ) { diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 7bc18f6b86..a228bb7436 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -2666,7 +2666,7 @@ void PrintObject::bridge_over_infill() // SECTION to gather and filter surfaces for expanding, and then cluster them by layer { tbb::concurrent_vector<CandidateSurface> candidate_surfaces; - tbb::parallel_for(tbb::blocked_range<size_t>(0, this->layers().size()), [po = static_cast<const PrintObject *>(this), &candidate_surfaces, has_lightning_infill](tbb::blocked_range<size_t> r) { + tbb::parallel_for(tbb::blocked_range<size_t>(0, this->layers().size()), [po = static_cast<const PrintObject *>(this), &candidate_surfaces](tbb::blocked_range<size_t> r) { PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT); for (size_t lidx = r.begin(); lidx < r.end(); lidx++) { const Layer *layer = po->get_layer(lidx); diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index 07eb885eda..f6a6b43e09 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -527,7 +527,7 @@ bool groupingVolumes(std::vector<VolumeSlices> objSliceByVolume, std::vector<gro } tbb::parallel_for(tbb::blocked_range<int>(0, osvIndex.size()), - [&osvIndex, &objSliceByVolume, &offsetValue, &resolution](const tbb::blocked_range<int>& range) { + [&osvIndex, &objSliceByVolume, &resolution](const tbb::blocked_range<int>& range) { for (auto k = range.begin(); k != range.end(); ++k) { for (ExPolygon& poly_ex : objSliceByVolume[osvIndex[k][0]].slices[osvIndex[k][1]]) poly_ex.douglas_peucker(resolution); @@ -535,7 +535,7 @@ bool groupingVolumes(std::vector<VolumeSlices> objSliceByVolume, std::vector<gro }); tbb::parallel_for(tbb::blocked_range<int>(0, osvIndex.size()), - [&osvIndex, &objSliceByVolume,&offsetValue, &resolution](const tbb::blocked_range<int>& range) { + [&osvIndex, &objSliceByVolume,&offsetValue](const tbb::blocked_range<int>& range) { for (auto k = range.begin(); k != range.end(); ++k) { objSliceByVolume[osvIndex[k][0]].slices[osvIndex[k][1]] = offset_ex(objSliceByVolume[osvIndex[k][0]].slices[osvIndex[k][1]], offsetValue); } diff --git a/src/libslic3r/Support/SupportCommon.cpp b/src/libslic3r/Support/SupportCommon.cpp index 15640cb0f2..0c7a4b832e 100644 --- a/src/libslic3r/Support/SupportCommon.cpp +++ b/src/libslic3r/Support/SupportCommon.cpp @@ -132,7 +132,7 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa return nullptr; }; tbb::parallel_for(tbb::blocked_range<int>(0, int(intermediate_layers.size())), - [&bottom_contacts, &top_contacts, &top_interface_layers, &top_base_interface_layers, &intermediate_layers, &insert_layer, &support_params, + [&bottom_contacts, &top_contacts, &top_interface_layers, &top_base_interface_layers, &intermediate_layers, &insert_layer, num_top_interface_layers, num_bottom_interface_layers, num_top_base_interface_layers, num_bottom_base_interface_layers, num_top_interface_layers_only, num_bottom_interface_layers_only, snug_supports, &interface_layers, &base_interface_layers](const tbb::blocked_range<int>& range) { diff --git a/src/libslic3r/Support/SupportMaterial.cpp b/src/libslic3r/Support/SupportMaterial.cpp index cd60489e75..12ac275592 100644 --- a/src/libslic3r/Support/SupportMaterial.cpp +++ b/src/libslic3r/Support/SupportMaterial.cpp @@ -1588,7 +1588,7 @@ static inline std::tuple<Polygons, Polygons, double> detect_contacts( // Cache support trimming polygons derived from lower layer polygons, possible merged with "on build plate only" trimming polygons. auto slices_margin_update = - [&slices_margin, &layer, &lower_layer, &lower_layer_polygons, buildplate_only, has_enforcer, &annotations, layer_id] + [&slices_margin, &lower_layer, &lower_layer_polygons, buildplate_only, has_enforcer, &annotations, layer_id] (float slices_margin_offset, float no_interface_offset) { if (slices_margin.offset != slices_margin_offset) { slices_margin.offset = slices_margin_offset; diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index de08870216..2b06f11244 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -2667,7 +2667,7 @@ void TreeSupport::drop_nodes() SupportNode::diameter_angle_scale_factor = diameter_angle_scale_factor; float DO_NOT_MOVER_UNDER_MM = is_slim ? 0 : 5; // do not move contact points under 5mm - auto get_max_move_dist = [this, &config, tan_angle, wall_count, support_extrusion_width](const SupportNode *node, int power = 1) { + auto get_max_move_dist = [this, tan_angle, support_extrusion_width](const SupportNode *node, int power = 1) { if (node->max_move_dist == 0) { node->radius = get_radius(node); node->max_move_dist = std::min(tan_angle * node->height, support_extrusion_width); diff --git a/src/slic3r/GUI/AMSDryControl.cpp b/src/slic3r/GUI/AMSDryControl.cpp index ddd3380975..f83eed30db 100644 --- a/src/slic3r/GUI/AMSDryControl.cpp +++ b/src/slic3r/GUI/AMSDryControl.cpp @@ -437,7 +437,7 @@ wxBoxSizer* AMSDryCtrWin::create_normal_state_panel(wxPanel* parent) m_temperature_input = new wxTextCtrl(parent, wxID_ANY, "", wxDefaultPosition, wxSize(FromDIP(80), -1)); m_temperature_input->SetMaxLength(3); // Limit to 3 digits - m_temperature_input->Bind(wxEVT_CHAR, [this](wxKeyEvent& event) { + m_temperature_input->Bind(wxEVT_CHAR, [](wxKeyEvent& event) { int keycode = event.GetKeyCode(); if (keycode >= '0' && keycode <= '9') { event.Skip(); @@ -464,7 +464,7 @@ wxBoxSizer* AMSDryCtrWin::create_normal_state_panel(wxPanel* parent) m_time_input = new wxTextCtrl(parent, wxID_ANY, "", wxDefaultPosition, wxSize(FromDIP(100), -1)); m_time_input->SetMaxLength(3); // Limit to 3 digits - m_time_input->Bind(wxEVT_CHAR, [this](wxKeyEvent& event) { + m_time_input->Bind(wxEVT_CHAR, [](wxKeyEvent& event) { int keycode = event.GetKeyCode(); if (keycode >= '0' && keycode <= '9') { event.Skip(); @@ -698,7 +698,7 @@ wxBoxSizer* AMSDryCtrWin::create_guide_info_section(wxPanel* parent) m_rotate_spool_toggle = new wxCheckBox(parent, wxID_ANY, ""); m_rotate_spool_toggle->SetValue(false); - m_rotate_spool_toggle->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& event) { + m_rotate_spool_toggle->Bind(wxEVT_CHECKBOX, [](wxCommandEvent& event) { bool is_checked = event.IsChecked(); // Add toggle behavior logic here }); diff --git a/src/slic3r/GUI/BindDialog.cpp b/src/slic3r/GUI/BindDialog.cpp index a4b568e82d..4c6d3c249d 100644 --- a/src/slic3r/GUI/BindDialog.cpp +++ b/src/slic3r/GUI/BindDialog.cpp @@ -468,7 +468,7 @@ PingCodeBindDialog::~PingCodeBindDialog() { m_link_privacy_title->SetFont(Label::Head_13); m_link_privacy_title->SetMaxSize(wxSize(FromDIP(450), -1)); m_link_privacy_title->Wrap(FromDIP(450)); - m_link_privacy_title->Bind(wxEVT_LEFT_DOWN, [this](auto& e) { + m_link_privacy_title->Bind(wxEVT_LEFT_DOWN, [](auto& e) { std::string url; std::string country_code = Slic3r::GUI::wxGetApp().app_config->get_country_code(); @@ -893,7 +893,7 @@ void BindMachineDialog::on_show(wxShowEvent &event) } } }) - .on_error([this](std::string body, std::string error, unsigned status) { + .on_error([](std::string body, std::string error, unsigned status) { //BOOST_LOG_TRIVIAL(info) << "load oss picture failed, oss path: " << oss_path << " status:" << status << " error:" << error; }).perform(); } @@ -1099,7 +1099,7 @@ void UnBindMachineDialog::on_show(wxShowEvent &event) } } }) - .on_error([this](std::string body, std::string error, unsigned status) { + .on_error([](std::string body, std::string error, unsigned status) { //BOOST_LOG_TRIVIAL(info) << "load oss picture failed, oss path: " << oss_path << " status:" << status << " error:" << error; }).perform(); diff --git a/src/slic3r/GUI/CaliHistoryDialog.cpp b/src/slic3r/GUI/CaliHistoryDialog.cpp index 4de90d8b8f..6c1e612864 100644 --- a/src/slic3r/GUI/CaliHistoryDialog.cpp +++ b/src/slic3r/GUI/CaliHistoryDialog.cpp @@ -443,7 +443,7 @@ void HistoryWindow::sync_history_data() { auto edit_button = new Button(m_history_data_panel, _L("Edit")); edit_button->SetStyle(ButtonStyle::Confirm, ButtonType::Window); - edit_button->Bind(wxEVT_BUTTON, [this, result, k_value, name_value, edit_button](auto& e) { + edit_button->Bind(wxEVT_BUTTON, [this, result, k_value, name_value](auto& e) { if (m_ui_op_lock) return; PACalibResult result_buffer = result; diff --git a/src/slic3r/GUI/Calibration.cpp b/src/slic3r/GUI/Calibration.cpp index 0c2b4f1659..f3351fdb6b 100644 --- a/src/slic3r/GUI/Calibration.cpp +++ b/src/slic3r/GUI/Calibration.cpp @@ -201,7 +201,7 @@ wxWindow* CalibrationDialog::create_check_option(wxString title, wxWindow* paren checkbox->SetToolTip(tooltip); text->SetToolTip(tooltip); - text->Bind(wxEVT_LEFT_DOWN, [this, check](wxMouseEvent&) { check->SetValue(check->GetValue() ? false : true); }); + text->Bind(wxEVT_LEFT_DOWN, [check](wxMouseEvent&) { check->SetValue(check->GetValue() ? false : true); }); m_checkbox_list[param] = check; m_checkbox_list[param]->SetValue(true); return checkbox; diff --git a/src/slic3r/GUI/CalibrationWizard.cpp b/src/slic3r/GUI/CalibrationWizard.cpp index b1f5c206c6..7496d59a51 100644 --- a/src/slic3r/GUI/CalibrationWizard.cpp +++ b/src/slic3r/GUI/CalibrationWizard.cpp @@ -477,7 +477,7 @@ void CalibrationWizard::on_cali_go_home() if (go_home_dialog == nullptr) go_home_dialog = new SecondaryCheckDialog(this, wxID_ANY, _L("Confirm")); - go_home_dialog->Bind(EVT_SECONDARY_CHECK_CONFIRM, [this, method](wxCommandEvent &e) { + go_home_dialog->Bind(EVT_SECONDARY_CHECK_CONFIRM, [this](wxCommandEvent &e) { if (curr_obj) { curr_obj->command_task_abort(); } else { diff --git a/src/slic3r/GUI/CalibrationWizardCaliPage.cpp b/src/slic3r/GUI/CalibrationWizardCaliPage.cpp index d9604da84a..152f46f37c 100644 --- a/src/slic3r/GUI/CalibrationWizardCaliPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardCaliPage.cpp @@ -90,7 +90,7 @@ void CalibrationCaliPage::on_subtask_abort(wxCommandEvent& event) if (abort_dlg == nullptr) { abort_dlg = new SecondaryCheckDialog(this->GetParent(), wxID_ANY, _L("Cancel print")); - abort_dlg->Bind(EVT_SECONDARY_CHECK_CONFIRM, [this, obj](wxCommandEvent& e) { + abort_dlg->Bind(EVT_SECONDARY_CHECK_CONFIRM, [obj](wxCommandEvent& e) { if (obj) obj->command_task_abort(); }); } diff --git a/src/slic3r/GUI/CalibrationWizardPage.cpp b/src/slic3r/GUI/CalibrationWizardPage.cpp index ef17da9081..c117ec8857 100644 --- a/src/slic3r/GUI/CalibrationWizardPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardPage.cpp @@ -762,7 +762,7 @@ void CaliPageActionPanel::bind_button(CaliPageActionType action_type, bool is_bl if (is_block) { m_action_btns[i]->Bind(wxEVT_BUTTON, - [this](wxCommandEvent& evt) { + [](wxCommandEvent& evt) { MessageDialog msg(nullptr, _L("The current firmware version of the printer does not support calibration.\nPlease upgrade the printer firmware."), _L("Calibration not supported"), wxOK | wxICON_WARNING); msg.ShowModal(); }); diff --git a/src/slic3r/GUI/CalibrationWizardSavePage.cpp b/src/slic3r/GUI/CalibrationWizardSavePage.cpp index 78bc4bb77f..f7699cfab0 100644 --- a/src/slic3r/GUI/CalibrationWizardSavePage.cpp +++ b/src/slic3r/GUI/CalibrationWizardSavePage.cpp @@ -272,7 +272,7 @@ void CaliPASaveAutoPanel::sync_cali_result(const std::vector<PACalibResult>& cal preset_names = default_naming(preset_names); std::vector<PACalibResult> sorted_cali_result = cali_result; - std::sort(sorted_cali_result.begin(), sorted_cali_result.end(), [this](const PACalibResult &left, const PACalibResult& right) { + std::sort(sorted_cali_result.begin(), sorted_cali_result.end(), [](const PACalibResult &left, const PACalibResult& right) { return left.tray_id < right.tray_id; }); @@ -366,7 +366,7 @@ void CaliPASaveAutoPanel::sync_cali_result(const std::vector<PACalibResult>& cal } } - comboBox_tray_name->Bind(wxEVT_COMBOBOX, [this, comboBox_tray_name, k_value, n_value](auto& e) { + comboBox_tray_name->Bind(wxEVT_COMBOBOX, [comboBox_tray_name](auto& e) { int selection = comboBox_tray_name->GetSelection(); auto history = filtered_results[selection]; }); @@ -744,7 +744,7 @@ void CaliPASaveAutoPanel::sync_cali_result_for_multi_extruder(const std::vector< } } - comboBox_tray_name->Bind(wxEVT_COMBOBOX, [this, comboBox_tray_name, k_value, n_value](auto &e) { + comboBox_tray_name->Bind(wxEVT_COMBOBOX, [comboBox_tray_name](auto &e) { int selection = comboBox_tray_name->GetSelection(); auto history = filtered_results[selection]; }); diff --git a/src/slic3r/GUI/CameraPopup.cpp b/src/slic3r/GUI/CameraPopup.cpp index 0ee5694a34..cc7e00eec6 100644 --- a/src/slic3r/GUI/CameraPopup.cpp +++ b/src/slic3r/GUI/CameraPopup.cpp @@ -140,7 +140,7 @@ CameraPopup::CameraPopup(wxWindow *parent) vcamera_guide_link->Wrap(-1); vcamera_guide_link->SetForegroundColour(wxColour(0x1F, 0x8E, 0xEA)); auto text_size = vcamera_guide_link->GetTextExtent(text); - vcamera_guide_link->Bind(wxEVT_LEFT_DOWN, [this, url](wxMouseEvent& e) {wxLaunchDefaultBrowser(url); }); + vcamera_guide_link->Bind(wxEVT_LEFT_DOWN, [url](wxMouseEvent& e) {wxLaunchDefaultBrowser(url); }); link_underline = new wxPanel(m_panel, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); link_underline->SetBackgroundColour(wxColour(0x1F, 0x8E, 0xEA)); diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index dba8699105..412df19091 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -2752,7 +2752,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent) }); if (wxLinux_gtk3) - this->Bind(wxEVT_SHOW, [this, vsizer](const wxShowEvent& e) { + this->Bind(wxEVT_SHOW, [](const wxShowEvent& e) { ; }); diff --git a/src/slic3r/GUI/CreatePresetsDialog.cpp b/src/slic3r/GUI/CreatePresetsDialog.cpp index 33f49c2a38..063d1ce628 100644 --- a/src/slic3r/GUI/CreatePresetsDialog.cpp +++ b/src/slic3r/GUI/CreatePresetsDialog.cpp @@ -1885,7 +1885,7 @@ wxBoxSizer *CreatePrinterPresetDialog::create_nozzle_diameter_item(wxWindow *par m_custom_nozzle_diameter_ctrl = new wxTextCtrl(parent, wxID_ANY, "", wxDefaultPosition, NAME_OPTION_COMBOBOX_SIZE); m_custom_nozzle_diameter_ctrl->SetHint(_L("Input Custom Nozzle Diameter")); - m_custom_nozzle_diameter_ctrl->Bind(wxEVT_CHAR, [this](wxKeyEvent &event) { + m_custom_nozzle_diameter_ctrl->Bind(wxEVT_CHAR, [](wxKeyEvent &event) { int key = event.GetKeyCode(); if (key != 44 && key != 46 && cannot_input_key.find(key) != cannot_input_key.end()) { // "@" can not be inputed event.Skip(false); diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index dbbf5ec5e2..b0302f2cf8 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -1324,7 +1324,7 @@ void SpinCtrl::BUILD() { bEnterPressed = true; }), temp->GetId()); - temp->GetTextCtrl()->Bind(wxEVT_TEXT, ([this, temp](wxCommandEvent e) + temp->GetTextCtrl()->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { // # On OSX / Cocoa, SpinInput::GetValue() doesn't return the new value // # when it was changed from the text control, so the on_change callback diff --git a/src/slic3r/GUI/FilamentPickerDialog.cpp b/src/slic3r/GUI/FilamentPickerDialog.cpp index 98c955fb76..5b5af59501 100644 --- a/src/slic3r/GUI/FilamentPickerDialog.cpp +++ b/src/slic3r/GUI/FilamentPickerDialog.cpp @@ -426,11 +426,11 @@ wxScrolledWindow* FilamentPickerDialog::CreateColorGrid() }); // Hover highlight - btn->Bind(wxEVT_ENTER_WINDOW, [btn](wxMouseEvent& evt) { + btn->Bind(wxEVT_ENTER_WINDOW, [](wxMouseEvent& evt) { evt.Skip(); }); - btn->Bind(wxEVT_LEAVE_WINDOW, [btn](wxMouseEvent& evt) { + btn->Bind(wxEVT_LEAVE_WINDOW, [](wxMouseEvent& evt) { evt.Skip(); }); diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 15085c3cc4..e5a88e4ea4 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -2613,7 +2613,7 @@ void GCodeViewer::render_all_plates_stats(const std::vector<const GCodeProcessor return ret; }; - auto append_item = [icon_size, &imgui, imperial_units, &window_padding, &draw_list, this](const ColorRGBA& color, const std::vector<std::pair<std::string, float>>& columns_offsets) + auto append_item = [icon_size, &imgui, &window_padding, &draw_list, this](const ColorRGBA& color, const std::vector<std::pair<std::string, float>>& columns_offsets) { // render icon ImVec2 pos = ImVec2(ImGui::GetCursorScreenPos().x + window_padding * 3, ImGui::GetCursorScreenPos().y); @@ -2648,7 +2648,7 @@ void GCodeViewer::render_all_plates_stats(const std::vector<const GCodeProcessor } ImGui::Separator(); }; - auto get_used_filament_from_volume = [this, imperial_units, &filament_diameters, &filament_densities](double volume, int extruder_id) { + auto get_used_filament_from_volume = [imperial_units, &filament_diameters, &filament_densities](double volume, int extruder_id) { double koef = imperial_units ? 1.0 / GizmoObjectManipulation::in_to_mm : 0.001; std::pair<double, double> ret = { koef * volume / (PI * sqr(0.5 * filament_diameters[extruder_id])), volume * filament_densities[extruder_id] * 0.001 }; @@ -3233,7 +3233,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv //ImVec2(pos_rect.x + ImGui::GetWindowWidth() + ImGui::GetFrameHeight(),pos_rect.y + ImGui::GetFrameHeight() + window_padding * 2.5), //ImGui::GetColorU32(ImVec4(0,0,0,0.3))); - auto append_item = [icon_size, &imgui, imperial_units, &window_padding, &draw_list, this]( + auto append_item = [icon_size, &imgui, &window_padding, &draw_list, this]( EItemType type, const ColorRGBA& color, const std::vector<std::pair<std::string, float>>& columns_offsets, @@ -3368,7 +3368,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv return ret; }; - auto calculate_offsets = [&imgui, max_width, window_padding, this](const std::vector<std::pair<std::string, std::vector<::string>>>& title_columns, float extra_size = 0.0f) { + auto calculate_offsets = [max_width, this](const std::vector<std::pair<std::string, std::vector<::string>>>& title_columns, float extra_size = 0.0f) { const ImGuiStyle& style = ImGui::GetStyle(); std::vector<float> offsets; // ORCA increase spacing for more readable format. Using direct number requires much less code change in here. GetTextLineHeight for additional spacing for icon_size @@ -3856,7 +3856,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv columns_offsets.push_back({ distance_text, offsets[3] }); if (full_layout && !count_text.empty()) columns_offsets.push_back({ count_text, distance_text.empty() ? offsets[3] : offsets[4] }); - append_item(EItemType::Rect, color, columns_offsets, true, offsets.back()/*ORCA checkbox_pos*/, visible, [this, type, visible]() { + append_item(EItemType::Rect, color, columns_offsets, true, offsets.back()/*ORCA checkbox_pos*/, visible, [this, type]() { m_viewer.toggle_option_visibility(type); update_moves_slider(); }); @@ -3913,7 +3913,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv columns_offsets.push_back({used_filaments_length[i], offsets[3]}); columns_offsets.push_back({used_filaments_weight[i], offsets[4]}); append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_extrusion_role_color(role)), columns_offsets, - true, offsets.back(), visible, [this, role, visible]() { + true, offsets.back(), visible, [this, role]() { m_viewer.toggle_extrusion_role_visibility(role); update_moves_slider(); }); @@ -3932,7 +3932,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv columns_offsets.push_back({ travel_percent, offsets[2] }); columns_offsets.push_back({ travel_distance, offsets[3] }); // Usage column columns_offsets.push_back({ travel_moves, offsets[4] }); // Usage column - append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), columns_offsets, true, offsets.back()/*ORCA checkbox_pos*/, visible, [this, item, visible]() { + append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), columns_offsets, true, offsets.back()/*ORCA checkbox_pos*/, visible, [this, item]() { m_viewer.toggle_option_visibility(item); update_moves_slider(); }); @@ -3951,7 +3951,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} }); const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f)); - append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this, travel_visible]() { + append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this]() { m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels); // refresh(*m_gcode_result, wxGetApp().plater()->get_extruder_colors_from_plater_config(m_gcode_result)); update_moves_slider(); @@ -3968,7 +3968,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} }); const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f)); - append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this, travel_visible]() { + append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this]() { m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels); // refresh(*m_gcode_result, wxGetApp().plater()->get_extruder_colors_from_plater_config(m_gcode_result)); update_moves_slider(); @@ -3985,7 +3985,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} }); const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f)); - append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this, travel_visible]() { + append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this]() { m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels); update_moves_slider(); }); @@ -4001,7 +4001,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} }); const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f)); - append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this, travel_visible]() { + append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this]() { m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels); update_moves_slider(); }); @@ -4121,7 +4121,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv } float checkbox_pos = std::max(predictable_icon_pos, color_print_offsets[_u8L("Display")]); // ORCA prefer predictable_icon_pos when header not reacing end - append_item(EItemType::Rect, libvgcode::convert(tool_colors[extruder_idx]), columns_offsets, false, checkbox_pos/*ORCA*/, true, [this, extruder_idx]() {}); + append_item(EItemType::Rect, libvgcode::convert(tool_colors[extruder_idx]), columns_offsets, false, checkbox_pos/*ORCA*/, true, []() {}); } i++; } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 34279369a1..7db7e01e9c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -9236,7 +9236,7 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar() ImVec2 size = ImVec2(button_width, button_height); ImVec2 end_pos = ImVec2(start_pos.x + size.x, start_pos.y + size.y); // ORCA show additional information depends on state - auto draw_info_btn = [end_pos, f_scale, margin, window_bg](std::string str, ImVec4 bg_color, ImVec4 fg_color){ + auto draw_info_btn = [end_pos, f_scale, margin](std::string str, ImVec4 bg_color, ImVec4 fg_color){ GImGui->FontSize = 15.0f * f_scale; ImVec2 txt_slice_sz = ImGui::CalcTextSize(str.c_str()); ImVec2 btn_pad = ImVec2(8.f, 1.f) * f_scale; @@ -9492,7 +9492,7 @@ void GLCanvas3D::_render_canvas_toolbar() Plater* p = wxGetApp().plater(); AppConfig* cfg = wxGetApp().app_config; - auto create_menu_item = [this, sc]( + auto create_menu_item = [sc]( const std::string& name, bool enable, bool condition, @@ -9509,7 +9509,7 @@ void GLCanvas3D::_render_canvas_toolbar() create_menu_item( _utf8(L("3D Navigator")), m_canvas_type != ECanvasType::CanvasAssembleView, // not work on assembly wxGetApp().show_3d_navigator(), - [this]{ + []{ wxGetApp().toggle_show_3d_navigator(); ImGui::CloseCurrentPopup(); // Close popup to show changes on UI } @@ -9518,7 +9518,7 @@ void GLCanvas3D::_render_canvas_toolbar() create_menu_item( _utf8(L("Zoom button")), true, // work on all wxGetApp().show_canvas_zoom_button(), - [this]{ + []{ wxGetApp().toggle_canvas_zoom_button(); ImGui::CloseCurrentPopup(); // Close popup to show changes on UI } @@ -9529,13 +9529,13 @@ void GLCanvas3D::_render_canvas_toolbar() create_menu_item( _utf8(L("Overhangs")), m_canvas_type == ECanvasType::CanvasView3D, // work only on prepare p->is_view3D_overhang_shown(), - [this, p]{p->show_view3D_overhang(!p->is_view3D_overhang_shown());} + [p]{p->show_view3D_overhang(!p->is_view3D_overhang_shown());} ); create_menu_item( _utf8(L("Outline")), m_canvas_type != ECanvasType::CanvasPreview, // not work on preview wxGetApp().show_outline(), - [this]{wxGetApp().toggle_show_outline();} + []{wxGetApp().toggle_show_outline();} ); create_menu_item( _utf8(L("Wireframe")), @@ -9547,7 +9547,7 @@ void GLCanvas3D::_render_canvas_toolbar() create_menu_item( _utf8(L("Realistic View")), m_canvas_type != ECanvasType::CanvasPreview, // not work on preview cfg->get_bool(SETTING_OPENGL_REALISTIC_MODE), - [this, &cfg]{ + [&cfg]{ cfg->set_bool(SETTING_OPENGL_REALISTIC_MODE, !cfg->get_bool(SETTING_OPENGL_REALISTIC_MODE)); cfg->save(); } @@ -9558,7 +9558,7 @@ void GLCanvas3D::_render_canvas_toolbar() create_menu_item( _utf8(L("Perspective")), true, // work on all cfg->get_bool("use_perspective_camera"), - [this, &cfg]{ + [&cfg]{ cfg->set_bool("use_perspective_camera", !(cfg->get_bool("use_perspective_camera"))); wxGetApp().update_ui_from_settings(); } @@ -9575,7 +9575,7 @@ void GLCanvas3D::_render_canvas_toolbar() create_menu_item( _utf8(L("Gridlines")), m_canvas_type != ECanvasType::CanvasAssembleView, // not work on assembly wxGetApp().show_plate_gridlines(), - [this]{wxGetApp().toggle_show_plate_gridlines();} + []{wxGetApp().toggle_show_plate_gridlines();} ); ImGui::Separator(); @@ -9583,7 +9583,7 @@ void GLCanvas3D::_render_canvas_toolbar() create_menu_item( _utf8(L("Labels")), m_canvas_type == ECanvasType::CanvasView3D, // work only on prepare p->are_view3D_labels_shown(), - [this, p]{p->show_view3D_labels(!p->are_view3D_labels_shown());} + [p]{p->show_view3D_labels(!p->are_view3D_labels_shown());} ); ImGui::PopItemFlag(); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 223829f435..d661b012a3 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2641,7 +2641,7 @@ std::string GUI_App::get_bbl_client_version() void GUI_App::on_start_subscribe_again(std::string dev_id) { auto start_subscribe_timer = new wxTimer(this, wxID_ANY); - Bind(wxEVT_TIMER, [this, start_subscribe_timer, dev_id](auto& e) { + Bind(wxEVT_TIMER, [start_subscribe_timer, dev_id](auto& e) { start_subscribe_timer->Stop(); Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); if (!dev) return; @@ -3231,7 +3231,7 @@ bool GUI_App::on_init_inner() } }); - Bind(EVT_SHOW_NO_NEW_VERSION, [this](const wxCommandEvent& evt) { + Bind(EVT_SHOW_NO_NEW_VERSION, [](const wxCommandEvent& evt) { wxString msg = _L("This is the newest version."); InfoDialog dlg(nullptr, _L("Info"), msg); dlg.ShowModal(); @@ -5256,7 +5256,7 @@ std::string GUI_App::handle_web_request(std::string cmd) } } else if (command_str.compare("begin_network_plugin_download") == 0) { - CallAfter([this] { wxGetApp().ShowDownNetPluginDlg(); }); + CallAfter([] { wxGetApp().ShowDownNetPluginDlg(); }); } else if (command_str.compare("get_web_shortcut") == 0) { if (root.get_child_optional("key_event") != boost::none) { @@ -8297,7 +8297,7 @@ bool GUI_App::show_modal_ip_address_enter_dialog(bool input_sn, wxString title) dlg.set_machine_obj(obj); if (!title.empty()) dlg.update_title(title); - dlg.Bind(EVT_ENTER_IP_ADDRESS, [this, obj](wxCommandEvent& e) { + dlg.Bind(EVT_ENTER_IP_ADDRESS, [obj](wxCommandEvent& e) { auto selection_data_arr = wxSplit(e.GetString().ToStdString(), '|'); if (selection_data_arr.size() == 2) { @@ -8777,7 +8777,7 @@ bool GUI_App::check_and_keep_current_preset_changes(const wxString& caption, con if (!no_need_change && dlg.ShowModal() == wxID_CANCEL) return false; - auto reset_modifications = [this, is_called_from_configwizard]() { + auto reset_modifications = [this]() { //if (is_called_from_configwizard) // return; // no need to discared changes. It will be done fromConfigWizard closing diff --git a/src/slic3r/GUI/GUI_AuxiliaryList.cpp b/src/slic3r/GUI/GUI_AuxiliaryList.cpp index 1fa5b194ec..be9f99a76a 100644 --- a/src/slic3r/GUI/GUI_AuxiliaryList.cpp +++ b/src/slic3r/GUI/GUI_AuxiliaryList.cpp @@ -217,7 +217,7 @@ void AuxiliaryList::on_context_menu(wxDataViewEvent& evt) } else { append_menu_item(menu, wxID_ANY, _L("Open"), wxEmptyString, - [this, node](wxCommandEvent&) + [node](wxCommandEvent&) { wxLaunchDefaultApplication(node->path, 0); }); diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index be407a270f..d8e54978fa 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -1414,7 +1414,7 @@ void MenuFactory::create_default_menu() append_menu_check_item(&m_default_menu, wxID_ANY, _L("Show Labels"), "", [](wxCommandEvent&) { plater()->show_view3D_labels(!plater()->are_view3D_labels_shown()); plater()->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); }, &m_default_menu, - []() { return plater()->is_view3D_shown(); }, [this]() { return plater()->are_view3D_labels_shown(); }, m_parent); + []() { return plater()->is_view3D_shown(); }, []() { return plater()->are_view3D_labels_shown(); }, m_parent); } void MenuFactory::create_common_object_menu(wxMenu* menu) @@ -2090,7 +2090,7 @@ void MenuFactory::append_menu_item_clone(wxMenu* menu) static const wxString ctrl = _L("Ctrl+"); #endif append_menu_item(menu, wxID_ANY, _L("Clone") + "\t" + ctrl + "K", "", - [this](wxCommandEvent&) { + [](wxCommandEvent&) { plater()->clone_selection(); }, "", nullptr, []() { @@ -2115,7 +2115,7 @@ void MenuFactory::append_menu_item_smooth_mesh(wxMenu *menu) void MenuFactory::append_menu_item_center(wxMenu* menu) { append_menu_item(menu, wxID_ANY, _L("Center") , "", - [this](wxCommandEvent&) { + [](wxCommandEvent&) { plater()->center_selection(); }, "", nullptr, []() { @@ -2134,7 +2134,7 @@ void MenuFactory::append_menu_item_center(wxMenu* menu) void MenuFactory::append_menu_item_drop(wxMenu* menu) { append_menu_item(menu, wxID_ANY, _L("Drop") , "", - [this](wxCommandEvent&) { + [](wxCommandEvent&) { plater()->drop_selection(); }, "", nullptr, []() { @@ -2309,7 +2309,7 @@ void MenuFactory::append_menu_item_set_printable(wxMenu* menu) } } - wxMenuItem* menu_item_set_printable = append_menu_check_item(menu, wxID_ANY, _L("Printable") + "\t" + "V", "", [this, all_printable](wxCommandEvent&) { + wxMenuItem* menu_item_set_printable = append_menu_check_item(menu, wxID_ANY, _L("Printable") + "\t" + "V", "", [all_printable](wxCommandEvent&) { Selection& selection = plater()->canvas3D()->get_selection(); selection.set_printable(!all_printable); }, menu); @@ -2329,7 +2329,7 @@ void MenuFactory::append_menu_item_set_auto_drop(wxMenu* menu) wxString menu_tooltip = _L("Automatically snaps the selected object to the build plate."); wxMenuItem* menu_item_set_auto_drop = append_menu_check_item( menu, wxID_ANY, menu_text, menu_tooltip, - [this, current_auto_drop](wxCommandEvent&) { + [current_auto_drop](wxCommandEvent&) { Selection& selection = plater()->canvas3D()->get_selection(); selection.set_auto_drop(!current_auto_drop); }, @@ -2384,7 +2384,7 @@ void MenuFactory::append_menu_item_plate_name(wxMenu *menu) auto item = append_menu_item( menu, wxID_ANY, name, "", - [plate](wxCommandEvent &e) { + [](wxCommandEvent &e) { int hover_idx =plater()->canvas3D()->GetHoverId(); if (hover_idx == -1) { int plate_idx=plater()->GetPlateIndexByRightMenuInLeftUI(); diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp index 3b36158bd1..bbd7294ae5 100644 --- a/src/slic3r/GUI/GUI_ObjectLayers.cpp +++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp @@ -223,7 +223,7 @@ void ObjectLayers::update_layers_list() // only call sizer->Clear(true) via CallAfter, otherwise crash happens in Linux when press enter in Height Range // because an element cannot be destroyed while there are pending events for this element.(https://github.com/wxWidgets/Phoenix/issues/1854) - wxGetApp().CallAfter([this, type, objects_ctrl, range]() { + wxGetApp().CallAfter([this, type, range]() { m_og->ctrl_parent()->Freeze(); // Delete all controls from options group diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index b33cc82abc..8067afd8df 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2324,7 +2324,7 @@ void ObjectList::load_modifier(const wxArrayString& input_files, ModelObject& mo bool split_compound = wxGetApp().app_config->get_bool("is_split_compound"); model = Model::read_from_step( input_file, LoadStrategy::LoadModel, nullptr, nullptr, - [this, &is_user_cancel, &linear, &angle, &split_compound](Slic3r::Step& file, double& linear_value, + [&is_user_cancel, &linear, &angle, &split_compound](Slic3r::Step& file, double& linear_value, double& angle_value, bool& is_split) -> int { if (wxGetApp().app_config->get_bool("enable_step_mesh_setting")) { StepMeshDialog mesh_dlg(nullptr, file, linear, angle); @@ -3317,7 +3317,7 @@ void ObjectList::boolean() } } - TriangleMesh mesh = Plater::combine_mesh_fff(*object, -1, [this](const std::string& msg) {return wxGetApp().notification_manager()->push_plater_error_notification(msg); }); + TriangleMesh mesh = Plater::combine_mesh_fff(*object, -1, [](const std::string& msg) {return wxGetApp().notification_manager()->push_plater_error_notification(msg); }); // add mesh to model as a new object, keep the original object's name and config Model* model = object->get_model(); @@ -6267,7 +6267,7 @@ void GUI::ObjectList::smooth_mesh() get_selection_indexes(obj_idxs, vol_idxs); auto object_idx = obj_idxs.front(); ModelObject *obj{nullptr}; - auto show_warning_dlg = [this](int cur_face_count,std::string name,bool is_part) { + auto show_warning_dlg = [](int cur_face_count,std::string name,bool is_part) { int limit_face_count = 1000000; if (cur_face_count > limit_face_count) { auto name_str = wxString::FromUTF8(name); @@ -6280,7 +6280,7 @@ void GUI::ObjectList::smooth_mesh() } return false; }; - auto show_smooth_mesh_error_dlg = [this](std::string name) { + auto show_smooth_mesh_error_dlg = [](std::string name) { auto name_str = wxString::FromUTF8(name); auto content = wxString::Format(_L("\"%s\" part's mesh contains errors. Please repair it first."), name_str); WarningDialog dlg(static_cast<wxWindow *>(wxGetApp().mainframe), content, wxEmptyString, wxOK); diff --git a/src/slic3r/GUI/GUI_ObjectTable.cpp b/src/slic3r/GUI/GUI_ObjectTable.cpp index 1fc07bf5a2..35508c6113 100644 --- a/src/slic3r/GUI/GUI_ObjectTable.cpp +++ b/src/slic3r/GUI/GUI_ObjectTable.cpp @@ -3520,13 +3520,13 @@ void GridCellTextEditor::BeginEdit(int row, int col, wxGrid *grid) Text()->GetTextCtrl()->SetInsertionPointEnd(); - m_control->Bind(wxEVT_TEXT_ENTER, [this, row, col, grid](wxCommandEvent &e) { + m_control->Bind(wxEVT_TEXT_ENTER, [grid](wxCommandEvent &e) { grid->HideCellEditControl(); grid->SaveEditControlValue(); e.Skip(); }); - m_control->Bind(wxEVT_CHAR_HOOK, [this, row, col, grid](wxKeyEvent &e) { + m_control->Bind(wxEVT_CHAR_HOOK, [grid](wxKeyEvent &e) { if (e.GetKeyCode() == WXK_ESCAPE) { grid->HideCellEditControl(); grid->SaveEditControlValue(); diff --git a/src/slic3r/GUI/GUI_ObjectTableSettings.cpp b/src/slic3r/GUI/GUI_ObjectTableSettings.cpp index e72c421a08..2290018419 100644 --- a/src/slic3r/GUI/GUI_ObjectTableSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectTableSettings.cpp @@ -184,7 +184,7 @@ bool ObjectTableSettings::update_settings_list(bool is_object, bool is_multiple_ btn->Bind(EVT_LOCK_ENABLE, [this, btn](auto &e) { btn->SetBitmap(m_bmp_reset_focus.bmp()); }); #endif - btn->Bind(wxEVT_BUTTON, [btn, opt_key, this, is_object, object, config, group_category](wxEvent &event) { + btn->Bind(wxEVT_BUTTON, [opt_key, this, is_object, object, config, group_category](wxEvent &event) { //wxGetApp().plater()->take_snapshot(from_u8((boost::format(_utf8(L("Reset Option %s"))) % opt_key).str())); config->erase(opt_key); //btn->Hide(); @@ -204,10 +204,13 @@ bool ObjectTableSettings::update_settings_list(bool is_object, bool is_multiple_ this->m_parent->Thaw(); #ifdef __WXOSX_MAC__ - if (!btn->IsEnabled()) { - btn->SetBitmap(m_bmp_reset_disable.bmp()); - } else { - btn->SetBitmap(m_bmp_reset_focus.bmp()); + // The handler is bound on the button, so the event source is that button. + if (auto *btn = dynamic_cast<ScalableButton *>(event.GetEventObject())) { + if (!btn->IsEnabled()) { + btn->SetBitmap(m_bmp_reset_disable.bmp()); + } else { + btn->SetBitmap(m_bmp_reset_focus.bmp()); + } } #endif }); @@ -284,13 +287,13 @@ bool ObjectTableSettings::update_settings_list(bool is_object, bool is_multiple_ m_settings_list_sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 0); m_og_settings.push_back(optgroup); - auto toggle_field = [this, optgroup](const t_config_option_key & opt_key, bool toggle, int opt_index) + auto toggle_field = [optgroup](const t_config_option_key & opt_key, bool toggle, int opt_index) { Field* field = optgroup->get_fieldc(opt_key, opt_index);; if (field) field->toggle(toggle); }; - auto toggle_line = [this, optgroup](const t_config_option_key &opt_key, bool toggle, int opt_index) + auto toggle_line = [optgroup](const t_config_option_key &opt_key, bool toggle, int opt_index) { Line* line = optgroup->get_line(opt_key); if (line) line->toggle_visible = toggle; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index b5273e3024..273bb94b90 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -3596,7 +3596,7 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) // model_name failing reason std::vector<std::pair<std::string, std::string>> failed_models; auto plater = wxGetApp().plater(); - auto fix_and_update_progress = [this, plater, keep_painting](ModelObject *model_object, const int vol_idx, const string &model_name, ProgressDialog &progress_dlg, + auto fix_and_update_progress = [keep_painting](ModelObject *model_object, const int vol_idx, const string &model_name, ProgressDialog &progress_dlg, std::vector<std::string> &succes_models, std::vector<std::pair<std::string, std::string>> &failed_models) { wxString msg = _L("Repairing model object"); msg += ": " + from_u8(model_name) + "\n"; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp index c7186e5d80..8b12da14f9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp @@ -223,7 +223,7 @@ void GLGizmoMeshBoolean::on_render_input_window(float x, float y, float bottom_l const int select_btn_length = 2 * ImGui::GetStyle().FramePadding.x + std::max(ImGui::CalcTextSize(("1 " + _u8L("selected")).c_str()).x, ImGui::CalcTextSize(_u8L("Select").c_str()).x); - auto selectable = [this](const std::string& label, bool selected, const ImVec2& size_arg) { + auto selectable = [](const std::string& label, bool selected, const ImVec2& size_arg) { ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 0,0 }); ImGuiWindow* window = ImGui::GetCurrentWindow(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 8f0cd9a43d..3dcf51cbb5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -1456,7 +1456,7 @@ void TriangleSelectorPatch::update_triangles_per_patch() return touching_triangles; }; - auto calc_fragment_area = [this](const TrianglePatch& patch, float max_limit_area, int stride) { + auto calc_fragment_area = [](const TrianglePatch& patch, float max_limit_area, int stride) { double total_area = 0.f; const std::vector<int>& ti = patch.triangle_indices; /*for (int i = 0; i < ti.size() / 3; i++) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 7882cf2269..9cff834346 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -1003,7 +1003,7 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) // number waits briefly for a second one. const int digit = keyCode - '0'; const int shortcut_max = int(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT); - auto can_start_two_digit = [shortcut_max](int d) { return d > 0 && d * 10 <= shortcut_max; }; + auto can_start_two_digit = [](int d) { return d > 0 && d * 10 <= shortcut_max; }; auto select = [mmu_seg](int number) { return number > 0 && mmu_seg->on_number_key_down(number); }; if (m_timer_set_color.IsRunning() && m_pending_color_shortcut_tens > 0) { diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp index d7b082426c..7c4a2afd38 100644 --- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp +++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp @@ -239,7 +239,7 @@ void GizmoObjectManipulation::update_if_dirty() }; for (int i = 0; i < 3; ++ i) { - auto update = [this, i](Vec3d &cached, Vec3d &cached_rounded, const Vec3d &new_value) { + auto update = [i](Vec3d &cached, Vec3d &cached_rounded, const Vec3d &new_value) { //wxString new_text = double_to_string(new_value(i), 2); double new_rounded = round(new_value(i)*100)/100.0; //new_text.ToDouble(&new_rounded); diff --git a/src/slic3r/GUI/HMS.cpp b/src/slic3r/GUI/HMS.cpp index 5471c16064..f00e661df2 100644 --- a/src/slic3r/GUI/HMS.cpp +++ b/src/slic3r/GUI/HMS.cpp @@ -46,7 +46,7 @@ int get_hms_info_version(std::string& version) std::string url = (boost::format("https://%1%/GetVersion.php?%2%") % hms_host % query_params).str(); Slic3r::Http http = Slic3r::Http::get(url); http.timeout_max(10) - .on_complete([&result, &version](std::string body, unsigned status){ + .on_complete([&version](std::string body, unsigned status){ try { json j = json::parse(body); if (j.contains("ver")) { @@ -95,7 +95,7 @@ int HMSQuery::download_hms_related(const std::string& hms_type, const std::strin BOOST_LOG_TRIVIAL(info) << "hms: download url = " << url; Slic3r::Http http = Slic3r::Http::get(url); - http.on_complete([this, receive_json, hms_type, &to_save_local, &j, & local_version](std::string body, unsigned status) { + http.on_complete([receive_json, hms_type, &to_save_local, &j, & local_version](std::string body, unsigned status) { try { j = json::parse(body); if (j.contains("result")) { diff --git a/src/slic3r/GUI/Jobs/FillBedJob.cpp b/src/slic3r/GUI/Jobs/FillBedJob.cpp index a9a66cb96f..5364cb5648 100644 --- a/src/slic3r/GUI/Jobs/FillBedJob.cpp +++ b/src/slic3r/GUI/Jobs/FillBedJob.cpp @@ -184,7 +184,7 @@ void FillBedJob::prepare() ap.poly = m_selected.front().poly; ap.bed_idx = PartPlateList::MAX_PLATES_COUNT; ap.itemid = -1; - ap.setter = [this, mi, offset](const ArrangePolygon &p) { + ap.setter = [this, offset](const ArrangePolygon &p) { ModelObject *mo = m_plater->model().objects[m_object_idx]; ModelObject *obj; if (m_instances) { diff --git a/src/slic3r/GUI/Jobs/PrintJob.cpp b/src/slic3r/GUI/Jobs/PrintJob.cpp index d79deb955b..dae05494e3 100644 --- a/src/slic3r/GUI/Jobs/PrintJob.cpp +++ b/src/slic3r/GUI/Jobs/PrintJob.cpp @@ -135,7 +135,6 @@ void PrintJob::process(Ctl &ctl) { /* display info */ std::string msg; - wxString error_str; int curr_percent = 10; NetworkAgent* m_agent = wxGetApp().getAgent(); AppConfig* config = wxGetApp().app_config; @@ -402,9 +401,7 @@ void PrintJob::process(Ctl &ctl) &is_try_lan_mode, &is_try_lan_mode_failed, &msg, - &error_str, &curr_percent, - &error_text, StagePercentPoint ](int stage, int code, std::string info) { @@ -491,7 +488,7 @@ void PrintJob::process(Ctl &ctl) DeviceManager* dev = wxGetApp().getDeviceManager(); MachineObject* obj = dev->get_selected_machine(); - auto wait_fn = [this, &ctl, curr_percent, &obj](int state, std::string job_info) { + auto wait_fn = [&ctl, &obj](int state, std::string job_info) { BOOST_LOG_TRIVIAL(info) << "print_job: get_job_info = " << job_info; if (!obj->is_support_wait_sending_finish) { diff --git a/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp b/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp index f97b03bf62..7f8219008f 100644 --- a/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp +++ b/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp @@ -55,7 +55,7 @@ void RotoptimizeJob::process(Ctl &ctl) sla::RotOptimizeParams{} .accuracy(m_accuracy) .print_config(&m_default_print_cfg) - .statucb([this, &prev_status, &ctl/*, &statustxt*/](int s) + .statucb([&ctl/*, &statustxt*/](int s) { return !ctl.was_canceled(); }); diff --git a/src/slic3r/GUI/Jobs/SendJob.cpp b/src/slic3r/GUI/Jobs/SendJob.cpp index bb52367188..67ce02b476 100644 --- a/src/slic3r/GUI/Jobs/SendJob.cpp +++ b/src/slic3r/GUI/Jobs/SendJob.cpp @@ -213,7 +213,6 @@ void SendJob::process(Ctl &ctl) params.password = m_access_code; params.use_ssl_for_ftp = m_local_use_ssl_for_ftp; params.use_ssl_for_mqtt = m_local_use_ssl; - wxString error_text; std::string msg_text; const int StagePercentPoint[(int)PrintingStageFinished + 1] = { @@ -227,7 +226,7 @@ void SendJob::process(Ctl &ctl) }; auto update_fn = [this, &ctl, - &msg, &curr_percent, &error_text, StagePercentPoint](int stage, int code, std::string info) { + &msg, &curr_percent, StagePercentPoint](int stage, int code, std::string info) { if (stage == SendingPrintJobStage::PrintingStageCreate) { if (this->connection_type == "lan") { msg = _u8L("Sending G-code file over LAN"); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 5f7d69244e..a81cb72ab9 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -746,7 +746,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ evt.Skip(); }); - Bind(wxEVT_SHOW, [this](wxShowEvent &evt) { + Bind(wxEVT_SHOW, [](wxShowEvent &evt) { DeviceManager *manger = wxGetApp().getDeviceManager(); if (manger) { evt.IsShown() ? manger->start_refresher() : manger->stop_refresher(); @@ -2855,7 +2855,7 @@ void MainFrame::init_menubar_as_editor() [this]() { return can_add_models(); }); append_menu_item(import_menu, wxID_ANY, _L("Import Configs") + dots /*+ "\t" + ctrl + "I"*/, _L("Load configs"), [this](wxCommandEvent&) { load_config_file(); }, "menu_import", nullptr, - [this](){return true; }, this); + [](){return true; }, this); append_submenu(fileMenu, import_menu, wxID_ANY, _L("Import"), ""); @@ -2968,7 +2968,7 @@ void MainFrame::init_menubar_as_editor() _L("Duplicate the current plate"),[this](wxCommandEvent&) { m_plater->duplicate_plate(); }, - "menu_remove", nullptr, [this](){return true;}, this); + "menu_remove", nullptr, [](){return true;}, this); editMenu->AppendSeparator(); #else // BBS undo @@ -3135,13 +3135,13 @@ void MainFrame::init_menubar_as_editor() //BBS perspective view wxWindowID camera_id_base = wxWindow::NewControlId(int(wxID_CAMERA_COUNT)); auto perspective_item = append_menu_radio_item(viewMenu, wxID_CAMERA_PERSPECTIVE + camera_id_base, _L("Use Perspective View"), _L("Use Perspective View"), - [this](wxCommandEvent&) { + [](wxCommandEvent&) { wxGetApp().app_config->set_bool("use_perspective_camera", true); wxGetApp().update_ui_from_settings(); }, nullptr); //BBS orthogonal view auto orthogonal_item = append_menu_radio_item(viewMenu, wxID_CAMERA_ORTHOGONAL + camera_id_base, _L("Use Orthogonal View"), _L("Use Orthogonal View"), - [this](wxCommandEvent&) { + [](wxCommandEvent&) { wxGetApp().app_config->set_bool("use_perspective_camera", false); wxGetApp().update_ui_from_settings(); }, nullptr); @@ -3157,7 +3157,7 @@ void MainFrame::init_menubar_as_editor() m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); }, this, [this]() { return is_prepare_or_preview_tab(); }, - [this]() { return wxGetApp().app_config->get_bool("auto_perspective"); }, this); + []() { return wxGetApp().app_config->get_bool("auto_perspective"); }, this); viewMenu->AppendSeparator(); append_menu_check_item(viewMenu, wxID_ANY, _L("Show &G-code Window") + sep + "C", _L("Show G-code window in Preview scene."), @@ -3166,7 +3166,7 @@ void MainFrame::init_menubar_as_editor() m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); }, this, [this]() { return m_tabpanel->GetSelectedPageName() == TAB_ID_PREVIEW; }, - [this]() { return wxGetApp().show_gcode_window(); }, this); + []() { return wxGetApp().show_gcode_window(); }, this); append_menu_check_item( viewMenu, wxID_ANY, _L("Show 3D Navigator"), _L("Show 3D navigator in Prepare and Preview scene."), @@ -3175,7 +3175,7 @@ void MainFrame::init_menubar_as_editor() m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); }, this, [this]() { return is_prepare_or_preview_tab(); }, - [this]() { return wxGetApp().show_3d_navigator(); }, this); + []() { return wxGetApp().show_3d_navigator(); }, this); append_menu_check_item(viewMenu, wxID_ANY, _L("Show Gridlines"), _L("Show Gridlines on plate"), [this](wxCommandEvent&) { @@ -3183,7 +3183,7 @@ void MainFrame::init_menubar_as_editor() m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); }, this, [this]() { return is_prepare_or_preview_tab(); }, - [this]() { return wxGetApp().show_plate_gridlines(); }, this); + []() { return wxGetApp().show_plate_gridlines(); }, this); append_menu_item( viewMenu, wxID_ANY, _L("Reset Window Layout"), _L("Reset to default window layout"), @@ -3212,7 +3212,7 @@ void MainFrame::init_menubar_as_editor() m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); }, this, [this]() { return m_tabpanel->GetSelectedPageName() == TAB_ID_PREPARE; }, - [this]() { return wxGetApp().show_outline(); }, this); + []() { return wxGetApp().show_outline(); }, this); /*viewMenu->AppendSeparator(); append_menu_check_item(viewMenu, wxID_ANY, _L("Show &Wireframe") + "\t" + ctrl + shift + _L("Enter"), _L("Show wireframes in 3D scene."), @@ -3361,7 +3361,7 @@ void MainFrame::init_menubar_as_editor() append_menu_item( m_topbar->GetTopMenu(), wxID_ANY, _L("Preferences") + "\t" + ctrl + "P", "", - [this](wxCommandEvent &) { + [](wxCommandEvent &) { // Orca: Use GUI_App::open_preferences instead of direct call so windows associations are updated on exit wxGetApp().open_preferences(); }, @@ -3393,14 +3393,14 @@ void MainFrame::init_menubar_as_editor() into_u8(_L("Syncing presets from cloud\u2026"))); wxGetApp().restart_sync_user_preset(); }, "", nullptr, - [this]() { + []() { return wxGetApp().is_user_login() && !wxGetApp().app_config->get_stealth_mode(); }, this); top_menu->AppendSeparator(); append_menu_item( top_menu, wxID_ANY, _L("Plugins") + "\t", "", - [this](wxCommandEvent &) { + [](wxCommandEvent &) { wxGetApp().open_plugins_dialog(); }, "", nullptr, []() { return true; }, this); @@ -3501,7 +3501,7 @@ void MainFrame::init_menubar_as_editor() [this]() {return m_plater->is_view3D_shown();; }, this); // help - append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("Calibration Guide"), _L("Calibration Guide"), [this](wxCommandEvent &) + append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("Calibration Guide"), _L("Calibration Guide"), [](wxCommandEvent &) { wxLaunchDefaultBrowser("https://www.orcaslicer.com/wiki/calibration_guide", wxBROWSER_NEW_WINDOW); }, "", nullptr, [this]() {return m_plater->is_view3D_shown();; }, this); diff --git a/src/slic3r/GUI/MultiMachine.cpp b/src/slic3r/GUI/MultiMachine.cpp index f5ffd1319f..c0e84f40e9 100644 --- a/src/slic3r/GUI/MultiMachine.cpp +++ b/src/slic3r/GUI/MultiMachine.cpp @@ -217,7 +217,7 @@ std::vector<DeviceItem*> selected_machines(const std::vector<DeviceItem*>& dev_i SortItem::SortItem() { - sort_map.emplace(std::make_pair(SortRule::SR_None, [this](const DeviceItem* d1, const DeviceItem* d2) { + sort_map.emplace(std::make_pair(SortRule::SR_None, [](const DeviceItem* d1, const DeviceItem* d2) { return d1->state_dev_name > d2->state_dev_name; })); sort_map.emplace(std::make_pair(SortRule::SR_DEV_NAME, [this](const DeviceItem* d1, const DeviceItem* d2) { diff --git a/src/slic3r/GUI/MultiMachineManagerPage.cpp b/src/slic3r/GUI/MultiMachineManagerPage.cpp index d6531cc8d4..792c23fb13 100644 --- a/src/slic3r/GUI/MultiMachineManagerPage.cpp +++ b/src/slic3r/GUI/MultiMachineManagerPage.cpp @@ -19,7 +19,7 @@ MultiMachineItem::MultiMachineItem(wxWindow* parent, MachineObject* obj) Bind(wxEVT_LEAVE_WINDOW, &MultiMachineItem::OnLeaveWindow, this); Bind(wxEVT_LEFT_DOWN, &MultiMachineItem::OnLeftDown, this); Bind(wxEVT_MOTION, &MultiMachineItem::OnMove, this); - Bind(EVT_MULTI_DEVICE_VIEW, [this, obj](auto& e) { + Bind(EVT_MULTI_DEVICE_VIEW, [obj](auto& e) { wxGetApp().mainframe->jump_to_monitor(obj->get_dev_id()); if (wxGetApp().mainframe->m_monitor->get_status_panel()->get_media_play_ctrl()) { wxGetApp().mainframe->m_monitor->get_status_panel()->get_media_play_ctrl()->jump_to_play(); diff --git a/src/slic3r/GUI/MultiMachinePage.cpp b/src/slic3r/GUI/MultiMachinePage.cpp index 88d03007b9..dd67e099a0 100644 --- a/src/slic3r/GUI/MultiMachinePage.cpp +++ b/src/slic3r/GUI/MultiMachinePage.cpp @@ -80,7 +80,7 @@ void MultiMachinePage::init_tabpanel() sizer_side_tools->Add(m_side_tools, 1, wxEXPAND, 0); m_tabpanel = new Tabbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, sizer_side_tools, wxNB_LEFT | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME); m_tabpanel->SetBackgroundColour(wxColour("#FEFFFF")); - m_tabpanel->Bind(wxEVT_BOOKCTRL_PAGE_CHANGED, [this](wxBookCtrlEvent& e) {; }); + m_tabpanel->Bind(wxEVT_BOOKCTRL_PAGE_CHANGED, [](wxBookCtrlEvent& e) {; }); m_local_task_manager = new LocalTaskManagerPage(m_tabpanel); m_cloud_task_manager = new CloudTaskManagerPage(m_tabpanel); diff --git a/src/slic3r/GUI/MultiTaskManagerPage.cpp b/src/slic3r/GUI/MultiTaskManagerPage.cpp index bca2de8761..48a7fbe43e 100644 --- a/src/slic3r/GUI/MultiTaskManagerPage.cpp +++ b/src/slic3r/GUI/MultiTaskManagerPage.cpp @@ -783,7 +783,7 @@ void LocalTaskManagerPage::refresh_user_device(bool clear) mtitem->m_send_time = task_state_info->get_sent_time(); mtitem->state_local_task = task_state_info->state(); - task_state_info->set_state_changed_fn([this, mtitem](TaskState state, int percent) { + task_state_info->set_state_changed_fn([mtitem](TaskState state, int percent) { mtitem->state_local_task = state; if (state == TaskState::TS_SEND_COMPLETED) { diff --git a/src/slic3r/GUI/NetworkPluginDialog.cpp b/src/slic3r/GUI/NetworkPluginDialog.cpp index bc898d0d24..42e1fc5fc5 100644 --- a/src/slic3r/GUI/NetworkPluginDialog.cpp +++ b/src/slic3r/GUI/NetworkPluginDialog.cpp @@ -156,14 +156,14 @@ void NetworkPluginDownloadDialog::create_update_available_ui(const std::string& auto daa_chk = new CheckBox(this); daa_chk->SetValue(cfg->is_network_update_prompt_disabled()); - daa_chk->Bind(wxEVT_TOGGLEBUTTON, [this](wxCommandEvent& e){ + daa_chk->Bind(wxEVT_TOGGLEBUTTON, [](wxCommandEvent& e){ auto cfg = wxGetApp().app_config; cfg->set_network_update_prompt_disabled(e.IsChecked()); cfg->save(); }); auto daa_str = new Label(this, _L("Don't Ask Again")); - auto on_toggle = [this, daa_chk]() { + auto on_toggle = [daa_chk]() { daa_chk->SetValue(!daa_chk->GetValue()); wxCommandEvent evt(wxEVT_TOGGLEBUTTON, daa_chk->GetId()); evt.SetEventObject(daa_chk); diff --git a/src/slic3r/GUI/NetworkTestDialog.cpp b/src/slic3r/GUI/NetworkTestDialog.cpp index 78f395febc..53876d9f97 100644 --- a/src/slic3r/GUI/NetworkTestDialog.cpp +++ b/src/slic3r/GUI/NetworkTestDialog.cpp @@ -268,7 +268,7 @@ void NetworkTestDialog::start_test_url(TestJob job, wxString name, wxString url) int result = -1; http.timeout_max(10) - .on_complete([this, &result](std::string body, unsigned status) { + .on_complete([&result](std::string body, unsigned status) { try { if (status == 200) { result = 0; diff --git a/src/slic3r/GUI/Notebook.cpp b/src/slic3r/GUI/Notebook.cpp index 673508454a..67c1831e4d 100644 --- a/src/slic3r/GUI/Notebook.cpp +++ b/src/slic3r/GUI/Notebook.cpp @@ -56,7 +56,7 @@ ButtonsListCtrl::ButtonsListCtrl(wxWindow *parent, wxBoxSizer* side_tools) : // BBS: disable custom paint //this->Bind(wxEVT_PAINT, &ButtonsListCtrl::OnPaint, this); - Bind(wxEVT_SYS_COLOUR_CHANGED, [this](auto& e){ + Bind(wxEVT_SYS_COLOUR_CHANGED, [](auto& e){ }); } diff --git a/src/slic3r/GUI/OG_CustomCtrl.cpp b/src/slic3r/GUI/OG_CustomCtrl.cpp index 2ee94dbeeb..4fce046162 100644 --- a/src/slic3r/GUI/OG_CustomCtrl.cpp +++ b/src/slic3r/GUI/OG_CustomCtrl.cpp @@ -158,7 +158,7 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) ctrl_line.height = size.y; }; - auto add_buttons_width = [&h_pos, this] (int blinking_button_width) { + auto add_buttons_width = [&h_pos] (int blinking_button_width) { #ifndef DISABLE_BLINKING # ifndef DISABLE_UNDO_SYS h_pos += 3 * blinking_button_width; diff --git a/src/slic3r/GUI/ObjColorDialog.cpp b/src/slic3r/GUI/ObjColorDialog.cpp index 47f62aa168..d5a37fc9a7 100644 --- a/src/slic3r/GUI/ObjColorDialog.cpp +++ b/src/slic3r/GUI/ObjColorDialog.cpp @@ -254,7 +254,7 @@ ObjColorPanel::ObjColorPanel(wxWindow *parent, Slic3r::ObjDialogInOut &in_out, c m_color_cluster_num_by_user_ebox->Bind(wxEVT_TEXT_ENTER, on_apply_color_cluster_text_modify); m_color_cluster_num_by_user_ebox->Bind(wxEVT_SPINCTRL, on_apply_color_cluster_text_modify); - m_color_cluster_num_by_user_ebox->Bind(wxEVT_CHAR, [this](wxKeyEvent &e) { + m_color_cluster_num_by_user_ebox->Bind(wxEVT_CHAR, [](wxKeyEvent &e) { int keycode = e.GetKeyCode(); wxString input_char = wxString::Format("%c", keycode); long value; diff --git a/src/slic3r/GUI/ParamsPanel.cpp b/src/slic3r/GUI/ParamsPanel.cpp index 7d054d8a1b..a0834666ad 100644 --- a/src/slic3r/GUI/ParamsPanel.cpp +++ b/src/slic3r/GUI/ParamsPanel.cpp @@ -128,7 +128,7 @@ wxBoxSizer *TipsDialog::create_item_checkbox(wxString title, wxWindow *parent, w m_show_again = wxGetApp().app_config->has(param); checkbox->SetValue(m_show_again); - checkbox->Bind(wxEVT_TOGGLEBUTTON, [this, checkbox, param](wxCommandEvent &e) { + checkbox->Bind(wxEVT_TOGGLEBUTTON, [this, param](wxCommandEvent &e) { m_show_again = m_show_again ? false : true; e.Skip(); }); @@ -290,11 +290,11 @@ ParamsPanel::ParamsPanel( wxWindow* parent, wxWindowID id, const wxPoint& pos, c m_compare_btn = new ScalableButton(m_top_panel, wxID_ANY, "compare", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true); m_compare_btn->SetToolTip(_L("Compare presets")); - m_compare_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) { wxGetApp().mainframe->diff_dialog.show(); })); + m_compare_btn->Bind(wxEVT_BUTTON, ([](wxCommandEvent e) { wxGetApp().mainframe->diff_dialog.show(); })); m_setting_btn = new ScalableButton(m_top_panel, wxID_ANY, "table", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true); m_setting_btn->SetToolTip(_L("View all object's settings")); - m_setting_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { wxGetApp().plater()->PopupObjectTable(-1, -1, {0, 0}); }); + m_setting_btn->Bind(wxEVT_BUTTON, [](wxCommandEvent &) { wxGetApp().plater()->PopupObjectTable(-1, -1, {0, 0}); }); m_highlighter.set_timer_owner(this, 0); this->Bind(wxEVT_TIMER, [this](wxTimerEvent &) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 2b1a558fe9..067b1fcd04 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1340,7 +1340,7 @@ ExtruderGroup::ExtruderGroup(wxWindow * parent, int index, wxString const &title if (index >= 0) label_flow->SetMinSize({FromDIP(80), -1}); auto combo_flow = new ComboBox(this, wxID_ANY, wxString(""), wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_READONLY); combo_flow->GetDropDown().SetUseContentWidth(true); - combo_flow->Bind(wxEVT_COMBOBOX, [this, index, combo_flow](wxCommandEvent &evt) { + combo_flow->Bind(wxEVT_COMBOBOX, [index, combo_flow](wxCommandEvent &evt) { auto printer_tab = dynamic_cast<TabPrinter *>(wxGetApp().get_tab(Preset::TYPE_PRINTER)); NozzleVolumeType volume_type = NozzleVolumeType(intptr_t(combo_flow->GetClientData(evt.GetInt()))); printer_tab->set_extruder_volume_type(index, volume_type); @@ -1400,7 +1400,7 @@ ExtruderGroup::ExtruderGroup(wxWindow * parent, int index, wxString const &title btn_up = new ScalableButton(this, wxID_ANY, "page_up", "", {FromDIP(14), FromDIP(14)}, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, false, 14); btn_up->SetBackgroundColour(*wxWHITE); - btn_up->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this, index](auto &evt) { + btn_up->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](auto &evt) { if (page_cur > 0) --page_cur; update_ams(); @@ -1408,7 +1408,7 @@ ExtruderGroup::ExtruderGroup(wxWindow * parent, int index, wxString const &title btn_up->Hide(); btn_down = new ScalableButton(this, wxID_ANY, "page_down", "", {FromDIP(14), FromDIP(14)}, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, false, 14); btn_down->SetBackgroundColour(*wxWHITE); - btn_down->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this, index](auto &evt) { + btn_down->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](auto &evt) { if (page_cur + 1 < page_num) ++page_cur; update_ams(); @@ -2025,7 +2025,7 @@ bool Sidebar::priv::sync_extruder_list(bool &only_external_material, bool is_man if (!this->plater) return false; - this->plater->update_objects_position_when_select_preset([&obj, machine_preset]() { + this->plater->update_objects_position_when_select_preset([machine_preset]() { Tab *printer_tab = GUI::wxGetApp().get_tab(Preset::Type::TYPE_PRINTER); printer_tab->select_preset(machine_preset->name); }); @@ -2170,7 +2170,7 @@ bool Sidebar::priv::sync_extruder_list(bool &only_external_material, bool is_man void Sidebar::priv::update_sync_status(const MachineObject *obj) { StateColor not_synced_colour(std::pair<wxColour, int>(wxColour("#009688"), StateColor::Normal)); - auto clear_all_sync_status = [this, ¬_synced_colour]() { + auto clear_all_sync_status = [this]() { panel_printer_preset->ShowBadge(false); panel_printer_bed->ShowBadge(false); panel_nozzle_dia->ShowBadge(false); // ORCA add support for nozzle sync @@ -2474,7 +2474,7 @@ Sidebar::Sidebar(Plater *parent) p->m_printer_icon = new ScalableButton(p->m_panel_printer_title, wxID_ANY, "printer"); p->m_text_printer_settings = new Label(p->m_panel_printer_title, _L("Printer"), LB_PROPAGATE_MOUSE_EVENT | wxST_ELLIPSIZE_END); - p->m_printer_icon->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) { + p->m_printer_icon->Bind(wxEVT_BUTTON, [](wxCommandEvent& e) { //auto wizard_t = new ConfigWizard(wxGetApp().mainframe); //wizard_t->run(ConfigWizard::RR_USER, ConfigWizard::SP_CUSTOM); }); @@ -2495,7 +2495,7 @@ Sidebar::Sidebar(Plater *parent) }); p->m_printer_setting = new ScalableButton(p->m_panel_printer_title, wxID_ANY, "settings"); - p->m_printer_setting->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { + p->m_printer_setting->Bind(wxEVT_BUTTON, [](wxCommandEvent &e) { // p->editing_filament = -1; // wxGetApp().params_dialog()->Popup(); // wxGetApp().get_tab(Preset::TYPE_FILAMENT)->restore_last_select_item(); @@ -2610,8 +2610,8 @@ Sidebar::Sidebar(Plater *parent) p->image_printer->SetBackgroundColour(bg_color); p->combo_printer->SetBackgroundColour(bg_color); // paints margins instead combo background }; - p->combo_printer->Bind(wxEVT_SET_FOCUS, [this, printer_focus_bg](auto& e) {printer_focus_bg(true ); e.Skip();}); - p->combo_printer->Bind(wxEVT_KILL_FOCUS, [this, printer_focus_bg](auto& e) {printer_focus_bg(false); e.Skip();}); + p->combo_printer->Bind(wxEVT_SET_FOCUS, [printer_focus_bg](auto& e) {printer_focus_bg(true ); e.Skip();}); + p->combo_printer->Bind(wxEVT_KILL_FOCUS, [printer_focus_bg](auto& e) {printer_focus_bg(false); e.Skip();}); /* ORCA This part moved to titlebar p->btn_connect_printer = new ScalableButton(p->panel_printer_preset, wxID_ANY, "monitor_signal_strong"); @@ -2688,8 +2688,8 @@ Sidebar::Sidebar(Plater *parent) p->label_nozzle_type->SetBackgroundColour(bg_color); p->combo_nozzle_dia->SetBackgroundColour(bg_color); // paints margins instead combo background }; - p->combo_nozzle_dia->Bind(wxEVT_SET_FOCUS, [this, nozzle_focus_bg](auto& e) {nozzle_focus_bg(true ); e.Skip();}); - p->combo_nozzle_dia->Bind(wxEVT_KILL_FOCUS, [this, nozzle_focus_bg](auto& e) {nozzle_focus_bg(false); e.Skip();}); + p->combo_nozzle_dia->Bind(wxEVT_SET_FOCUS, [nozzle_focus_bg](auto& e) {nozzle_focus_bg(true ); e.Skip();}); + p->combo_nozzle_dia->Bind(wxEVT_KILL_FOCUS, [nozzle_focus_bg](auto& e) {nozzle_focus_bg(false); e.Skip();}); p->label_nozzle_type = new Label(p->panel_nozzle_dia, "Brass", LB_PROPAGATE_MOUSE_EVENT | wxST_ELLIPSIZE_END | wxALIGN_CENTRE_HORIZONTAL); p->label_nozzle_type->SetFont(Label::Body_10); @@ -2763,8 +2763,8 @@ Sidebar::Sidebar(Plater *parent) p->image_printer_bed->SetBackgroundColour(bg_color); p->combo_printer_bed->SetBackgroundColour(bg_color); // paints margins instead combo background }; - p->combo_printer_bed->Bind(wxEVT_SET_FOCUS, [this, bed_focus_bg](auto& e) {bed_focus_bg(true ); e.Skip();}); - p->combo_printer_bed->Bind(wxEVT_KILL_FOCUS, [this, bed_focus_bg](auto& e) {bed_focus_bg(false); e.Skip();}); + p->combo_printer_bed->Bind(wxEVT_SET_FOCUS, [bed_focus_bg](auto& e) {bed_focus_bg(true ); e.Skip();}); + p->combo_printer_bed->Bind(wxEVT_KILL_FOCUS, [bed_focus_bg](auto& e) {bed_focus_bg(false); e.Skip();}); // highlight border on hover auto printer_bed_hovered = std::make_shared<std::unordered_set<wxWindow*>>(); @@ -2978,7 +2978,7 @@ Sidebar::Sidebar(Plater *parent) ScalableButton* add_btn = new ScalableButton(p->m_panel_filament_title, wxID_ANY, "add_filament"); add_btn->SetToolTip(_L("Add one filament")); - add_btn->Bind(wxEVT_BUTTON, [this, scrolled_sizer](wxCommandEvent& e){ + add_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e){ add_filament(); update_filaments_counter(); }); @@ -2988,7 +2988,7 @@ Sidebar::Sidebar(Plater *parent) ScalableButton* del_btn = new ScalableButton(p->m_panel_filament_title, wxID_ANY, "delete_filament"); del_btn->SetToolTip(_L("Remove last filament")); - del_btn->Bind(wxEVT_BUTTON, [this, scrolled_sizer](wxCommandEvent &e) { + del_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { delete_filament(); update_filaments_counter(); }); @@ -3002,7 +3002,7 @@ Sidebar::Sidebar(Plater *parent) ams_btn = new ScalableButton(p->m_panel_filament_title, wxID_ANY, "ams_fila_sync", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, false, 16); // ORCA match icon size with other icons as 16x16 ams_btn->SetToolTip(_L("Synchronize filament list from AMS")); - ams_btn->Bind(wxEVT_BUTTON, [this, scrolled_sizer](wxCommandEvent &e) { + ams_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { sync_ams_list(); }); @@ -3682,7 +3682,7 @@ void Sidebar::update_presets(Preset::Type preset_type) extruder.combo_flow->SetSelection(select); }; - auto update_extruder_diameter = [&diameters, &diameter, &nozzle_diameter](int extruder_index,ExtruderGroup & extruder) { + auto update_extruder_diameter = [&diameters, &nozzle_diameter](int extruder_index,ExtruderGroup & extruder) { extruder.combo_diameter->Clear(); int select = -1; // ORCA get the actual nozzle diameter from printer config @@ -7497,7 +7497,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) // Keep tracking the current sidebar size, by storing it using `best_size`, which will be stored // in the config and re-applied when the app is opened again. - this->sidebar->Bind(wxEVT_IDLE, [&sidebar, this](wxIdleEvent& e) { + this->sidebar->Bind(wxEVT_IDLE, [&sidebar](wxIdleEvent& e) { if (sidebar.IsShown() && sidebar.IsDocked() && sidebar.rect.GetWidth() > 0) { sidebar.BestSize(sidebar.rect.GetWidth(), sidebar.best_size.GetHeight()); } @@ -7796,8 +7796,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) wxGetApp().removable_drive_manager()->init(this->q); #ifdef _WIN32 //Trigger enumeration of removable media on Win32 notification. - this->q->Bind(EVT_VOLUME_ATTACHED, [this](VolumeAttachedEvent &evt) { wxGetApp().removable_drive_manager()->volumes_changed(); }); - this->q->Bind(EVT_VOLUME_DETACHED, [this](VolumeDetachedEvent &evt) { wxGetApp().removable_drive_manager()->volumes_changed(); }); + this->q->Bind(EVT_VOLUME_ATTACHED, [](VolumeAttachedEvent &evt) { wxGetApp().removable_drive_manager()->volumes_changed(); }); + this->q->Bind(EVT_VOLUME_DETACHED, [](VolumeDetachedEvent &evt) { wxGetApp().removable_drive_manager()->volumes_changed(); }); #endif /* _WIN32 */ } @@ -8354,7 +8354,6 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_ const float LOAD_MODEL_RATIO = 0.9; for (size_t i = 0; i < input_files.size(); ++i) { - int file_percent = 0; #ifdef _WIN32 auto path = input_files[i]; @@ -8403,7 +8402,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_ q->skip_thumbnail_invalid = true; model = Slic3r::Model::read_from_archive(path.string(), &config_loaded, &config_substitutions, en_3mf_file_type, strategy, &plate_data, &project_presets, &file_version, - [this, &dlg, real_filename, &progress_percent, &file_percent, stage_percent, INPUT_FILES_RATIO, total_files, i, + [&dlg, real_filename, &progress_percent, stage_percent, INPUT_FILES_RATIO, total_files, i, &is_user_cancel](int import_stage, int current, int total, bool &cancel) { bool cont = true; float percent_float = (100.0f * (float)i / (float)total_files) + INPUT_FILES_RATIO * ((float)stage_percent[import_stage] + (float)current * (float)(stage_percent[import_stage + 1] - stage_percent[import_stage]) /(float) total) / (float)total_files; @@ -8986,7 +8985,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_ Semver file_version; //ObjImportColorFn obj_color_fun=nullptr; - auto obj_color_fun = [this, &path](ObjDialogInOut &in_out) { + auto obj_color_fun = [&path](ObjDialogInOut &in_out) { if (!boost::iends_with(path.string(), ".obj")) { return; } const std::vector<std::string> extruder_colours = wxGetApp().plater()->get_extruder_colors_from_plater_config(); @@ -9003,7 +9002,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_ if (angle <= 0) angle = 0.5; bool split_compound = wxGetApp().app_config->get_bool("is_split_compound"); model = Slic3r::Model:: read_from_step(path.string(), strategy, - [this, &dlg, real_filename, &progress_percent, &file_percent, step_percent, INPUT_FILES_RATIO, total_files, i](int load_stage, int current, int total, bool &cancel) + [&dlg, real_filename, &progress_percent, step_percent, INPUT_FILES_RATIO, total_files, i](int load_stage, int current, int total, bool &cancel) { bool cont = true; float percent_float = (100.0f * (float)i / (float)total_files) + INPUT_FILES_RATIO * ((float)step_percent[load_stage] + (float)current * (float)(step_percent[load_stage + 1] - step_percent[load_stage]) / (float)total) / (float)total_files; @@ -9027,7 +9026,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_ } } }, - [this, &path, &is_user_cancel, &linear, &angle, &split_compound](Slic3r::Step& file, double& linear_value, double& angle_value, bool& is_split)-> int { + [&is_user_cancel, &linear, &angle, &split_compound](Slic3r::Step& file, double& linear_value, double& angle_value, bool& is_split)-> int { if (wxGetApp().app_config->get_bool("enable_step_mesh_setting")) { StepMeshDialog mesh_dlg(nullptr, file, linear, angle); if (mesh_dlg.ShowModal() == wxID_OK) { @@ -9048,7 +9047,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_ }else { model = Slic3r::Model:: read_from_file( path.string(), nullptr, nullptr, strategy, &plate_data, &project_presets, &is_xxx, &file_version, nullptr, - [this, &dlg, real_filename, &progress_percent, &file_percent, INPUT_FILES_RATIO, total_files, i, &designer_model_id, &designer_country_code](int current, int total, bool &cancel, std::string &mode_id, std::string &code) + [&dlg, real_filename, &progress_percent, INPUT_FILES_RATIO, total_files, i, &designer_model_id, &designer_country_code](int current, int total, bool &cancel, std::string &mode_id, std::string &code) { designer_model_id = mode_id; designer_country_code = code; @@ -11294,7 +11293,7 @@ void Plater::priv::reload_from_disk() // load one file at a time for (size_t i = 0; i < input_paths.size(); ++i) { const auto& path = input_paths[i].string(); - auto obj_color_fun = [this, &path](ObjDialogInOut &in_out) { + auto obj_color_fun = [&path](ObjDialogInOut &in_out) { if (!boost::iends_with(path, ".obj")) { return; } const std::vector<std::string> extruder_colours = wxGetApp().plater()->get_extruder_colors_from_plater_config(); ObjColorDialog color_dlg(nullptr, in_out, extruder_colours, Sidebar::should_show_SEMM_buttons()); @@ -15265,7 +15264,7 @@ void Plater::import_model_id(wxString download_info) p->project.reset(); /* prepare project and profile */ - boost::thread import_thread = Slic3r::create_thread([&percent, &cont, &cancel, &retry_count, max_retries, &msg, &target_path, &download_ok, download_url, &filename] { + boost::thread import_thread = Slic3r::create_thread([&percent, &cont, &retry_count, &msg, &target_path, &download_ok, download_url, &filename] { // Orca: NetworkAgent is not needed and only prevents this from running // NetworkAgent* m_agent = Slic3r::GUI::wxGetApp().getAgent(); @@ -15372,7 +15371,7 @@ void Plater::import_model_id(wxString download_info) msg = wxString::Format(_L("Project downloaded %d%%"), percent); } }) - .on_error([&msg, &cont, &retry_count, max_retries](std::string body, std::string error, unsigned http_status) { + .on_error([&msg, &cont, &retry_count](std::string body, std::string error, unsigned http_status) { (void)body; BOOST_LOG_TRIVIAL(error) << format("Error getting: `%1%`: HTTP %2%, %3%", body, diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 8f3ac17f7c..355c4a26a8 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -519,7 +519,7 @@ wxBoxSizer *PreferencesDialog::create_item_language_combobox(wxString title, wxS } } - auto check = [this](bool yes_or_no) { + auto check = [](bool yes_or_no) { // if (yes_or_no) // return true; int act_btns = ActionButtons::SAVE; @@ -1200,7 +1200,7 @@ wxBoxSizer* PreferencesDialog::create_item_button(wxString title, wxString title m_button_download->SetStyle(title2 == _L("Clear") ? ButtonStyle::Alert : ButtonStyle::Regular, ButtonType::Parameter); m_button_download->SetToolTip(tooltip2.IsEmpty() ? tooltip : tooltip2); // use label tooltip if button tooltip empty - m_button_download->Bind(wxEVT_BUTTON, [this, onclick](auto &e) { onclick(); }); + m_button_download->Bind(wxEVT_BUTTON, [onclick](auto &e) { onclick(); }); m_sizer->Add(m_button_download, 0, wxALIGN_CENTER_VERTICAL); @@ -1490,7 +1490,7 @@ void PreferencesDialog::create() m_sizer_body = new wxBoxSizer(wxVERTICAL); m_pref_tabs = new TabCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_NO_BUTTONS | wxTR_HIDE_ROOT | wxTR_SINGLE | wxTR_NO_LINES | wxBORDER_NONE | wxWANTS_CHARS | wxTR_FULL_ROW_HIGHLIGHT); - m_pref_tabs->Bind(wxEVT_RIGHT_DOWN, [this](auto &e) {}); // disable right select + m_pref_tabs->Bind(wxEVT_RIGHT_DOWN, [](auto &e) {}); // disable right select m_pref_tabs->SetFont(Label::Body_14); create_items(); diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index f78af21a99..837f4ebe0c 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -1653,7 +1653,7 @@ void TabPresetComboBox::OnSelect(wxCommandEvent &evt) default: break; } if (sp != ConfigWizard::SP_WELCOME) { - wxTheApp->CallAfter([this, sp]() { + wxTheApp->CallAfter([sp]() { run_wizard(sp); }); } @@ -1949,7 +1949,7 @@ GUI::CalibrateFilamentComboBox::CalibrateFilamentComboBox(wxWindow *parent) { clr_picker->SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); clr_picker->SetToolTip(""); - clr_picker->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {}); + clr_picker->Bind(wxEVT_BUTTON, [](wxCommandEvent& e) {}); } GUI::CalibrateFilamentComboBox::~CalibrateFilamentComboBox() diff --git a/src/slic3r/GUI/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp index 669468d852..2b4d212d0f 100644 --- a/src/slic3r/GUI/PrintHostDialogs.cpp +++ b/src/slic3r/GUI/PrintHostDialogs.cpp @@ -2062,7 +2062,7 @@ void CrealityPrintHostSendDialog::init() } for (auto* c : m_slot_combos) { - c->Bind(wxEVT_COMBOBOX, [this, ext_slot_idx](wxCommandEvent& e) { + c->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& e) { int sel = e.GetSelection(); if (sel >= 0 && sel < (int)m_printer_slots.size() && m_printer_slots[sel].box_id == 0) { diff --git a/src/slic3r/GUI/Printer/PrinterFileSystem.cpp b/src/slic3r/GUI/Printer/PrinterFileSystem.cpp index 0b280fe923..8ec6909c8c 100644 --- a/src/slic3r/GUI/Printer/PrinterFileSystem.cpp +++ b/src/slic3r/GUI/Printer/PrinterFileSystem.cpp @@ -164,7 +164,7 @@ void PrinterFileSystem::ListAllFiles() req["storage"] = m_file_storage; req["api_version"] = 2; req["notify"] = "DETAIL"; - SendRequest<FileList>(LIST_INFO, req, [this, type = m_file_type](json const& resp, FileList & list, auto) -> int { + SendRequest<FileList>(LIST_INFO, req, [type = m_file_type](json const& resp, FileList & list, auto) -> int { json files = resp["file_lists"]; for (auto& f : files) { std::string name = f["name"]; @@ -1230,7 +1230,7 @@ boost::uint32_t PrinterFileSystem::RequestMediaAbility(int api_version) req["api_version"] = api_version; return SendRequest<MediaAbilityList>( - REQUEST_MEDIA_ABILITY, req, [this](const json &resp, MediaAbilityList &list, auto) -> int { + REQUEST_MEDIA_ABILITY, req, [](const json &resp, MediaAbilityList &list, auto) -> int { json abliity_list = resp["storage"]; list = abliity_list.get<MediaAbilityList>(); return 0; diff --git a/src/slic3r/GUI/PrivacyUpdateDialog.cpp b/src/slic3r/GUI/PrivacyUpdateDialog.cpp index ef4dac9b13..92d6d6c8c7 100644 --- a/src/slic3r/GUI/PrivacyUpdateDialog.cpp +++ b/src/slic3r/GUI/PrivacyUpdateDialog.cpp @@ -97,7 +97,7 @@ PrivacyUpdateDialog::PrivacyUpdateDialog(wxWindow* parent, wxWindowID id, const this->on_hide(); }); - Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) {e.Veto(); }); + Bind(wxEVT_CLOSE_WINDOW, [](wxCloseEvent& e) {e.Veto(); }); if (btn_style != CONFIRM_AND_CANCEL) m_button_cancel->Hide(); diff --git a/src/slic3r/GUI/ReleaseNote.cpp b/src/slic3r/GUI/ReleaseNote.cpp index 7b2d091176..029310faf9 100644 --- a/src/slic3r/GUI/ReleaseNote.cpp +++ b/src/slic3r/GUI/ReleaseNote.cpp @@ -1250,7 +1250,7 @@ void ConfirmBeforeSendDialog::update_text(std::vector<ConfirmBeforeSendInfo> tex else { label_item = new Label(m_vebview_release_note, text.text + " " + _L("Please refer to Wiki before use->"), LB_AUTO_WRAP); - label_item->Bind(wxEVT_LEFT_DOWN, [this, text](wxMouseEvent& e) { wxLaunchDefaultBrowser(text.wiki_url);}); + label_item->Bind(wxEVT_LEFT_DOWN, [text](wxMouseEvent& e) { wxLaunchDefaultBrowser(text.wiki_url);}); label_item->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) { SetCursor(wxCURSOR_HAND); }); label_item->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) { SetCursor(wxCURSOR_ARROW); }); } diff --git a/src/slic3r/GUI/SavePresetDialog.cpp b/src/slic3r/GUI/SavePresetDialog.cpp index 0b33e48ec4..b3f34a8cb9 100644 --- a/src/slic3r/GUI/SavePresetDialog.cpp +++ b/src/slic3r/GUI/SavePresetDialog.cpp @@ -153,7 +153,7 @@ SavePresetDialog::Item::Item(Preset::Type type, const std::string &suffix, wxBox detach_label->SetForegroundColour(wxColour("#363636")); - auto on_toggle = [this, detach_checkbox]() { + auto on_toggle = [detach_checkbox]() { detach_checkbox->SetValue(!detach_checkbox->GetValue()); wxCommandEvent ev(wxEVT_TOGGLEBUTTON, detach_checkbox->GetId()); ev.SetEventObject(detach_checkbox); diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index ac56e35ac3..199de9236e 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -3428,7 +3428,7 @@ void SelectMachineDialog::show_timelapse_storage_dialog(MachineObject* obj) if (show_cleanup_btn) { auto* btn_cleanup = new Button(&dlg, _L("Clean Up")); - btn_cleanup->Bind(wxEVT_BUTTON, [&dlg, ID_CLEANUP](wxCommandEvent&) { dlg.EndModal(ID_CLEANUP); }); + btn_cleanup->Bind(wxEVT_BUTTON, [&dlg](wxCommandEvent&) { dlg.EndModal(ID_CLEANUP); }); btn_sizer->Add(btn_cleanup, 0, wxEXPAND); } @@ -5497,7 +5497,7 @@ void SelectMachineDialog::reset_and_sync_ams_list() first_enabled_id = extruder; } - item->Bind(wxEVT_LEFT_UP, [this, item, materials, extruder](wxMouseEvent &e) {}); + item->Bind(wxEVT_LEFT_UP, [materials](wxMouseEvent &e) {}); item->Bind(wxEVT_LEFT_DOWN, [this, item, materials, extruder](wxMouseEvent &e) { if (!item->m_enable) {return;} if (!m_check_flag || m_print_status == PrintDialogStatus::PrintStatusUnsupportedPrinter) { return; } /*STUDIO-11301*/ @@ -6128,8 +6128,8 @@ void SelectMachineDialog::set_default_from_sdcard() first_enabled_id = fo.id; } - item->Bind(wxEVT_LEFT_UP, [this, item, materials](wxMouseEvent& e) {}); - item->Bind(wxEVT_LEFT_DOWN, [this, obj_, item, materials, diameters_count, fo](wxMouseEvent& e) { + item->Bind(wxEVT_LEFT_UP, [materials](wxMouseEvent& e) {}); + item->Bind(wxEVT_LEFT_DOWN, [this, obj_, item, materials, fo](wxMouseEvent& e) { if (!item->m_enable) {return;} if (!m_check_flag || m_print_status == PrintDialogStatus::PrintStatusUnsupportedPrinter) { return; } /*STUDIO-11301*/ diff --git a/src/slic3r/GUI/SelectMachinePop.cpp b/src/slic3r/GUI/SelectMachinePop.cpp index df0a566917..9b34e74f23 100644 --- a/src/slic3r/GUI/SelectMachinePop.cpp +++ b/src/slic3r/GUI/SelectMachinePop.cpp @@ -567,7 +567,7 @@ void SelectMachinePopup::update_other_devices() } } - op->Bind(EVT_CONNECT_LAN_PRINT, [this, mobj](wxCommandEvent &e) { + op->Bind(EVT_CONNECT_LAN_PRINT, [mobj](wxCommandEvent &e) { if (mobj) { if (mobj->is_lan_mode_printer()) { ConnectPrinterDialog dlg(wxGetApp().mainframe, wxID_ANY, _L("Input access code")); @@ -579,7 +579,7 @@ void SelectMachinePopup::update_other_devices() } }); - op->Bind(EVT_BIND_MACHINE, [this, mobj](wxCommandEvent &e) { + op->Bind(EVT_BIND_MACHINE, [mobj](wxCommandEvent &e) { BindMachineDialog dlg; dlg.update_machine_info(mobj); int dlg_result = wxID_CANCEL; @@ -700,7 +700,7 @@ void SelectMachinePopup::update_user_devices() op->set_printer_state(PrinterState::LOCK); } } - op->Bind(EVT_UNBIND_MACHINE, [this, dev, mobj](wxCommandEvent& e) { + op->Bind(EVT_UNBIND_MACHINE, [dev, mobj](wxCommandEvent& e) { dev->set_selected_machine(""); if (mobj) { AppConfig* config = wxGetApp().app_config; @@ -720,7 +720,7 @@ void SelectMachinePopup::update_user_devices() } else { op->show_printer_bind(true, PrinterBindState::ALLOW_UNBIND); - op->Bind(EVT_UNBIND_MACHINE, [this, mobj, dev](wxCommandEvent& e) { + op->Bind(EVT_UNBIND_MACHINE, [mobj, dev](wxCommandEvent& e) { // show_unbind_dialog UnBindMachineDialog dlg; dlg.update_machine_info(mobj); @@ -747,7 +747,7 @@ void SelectMachinePopup::update_user_devices() } } - op->Bind(EVT_CONNECT_LAN_PRINT, [this, mobj](wxCommandEvent &e) { + op->Bind(EVT_CONNECT_LAN_PRINT, [mobj](wxCommandEvent &e) { if (mobj) { if (mobj->is_lan_mode_printer()) { ConnectPrinterDialog dlg(wxGetApp().mainframe, wxID_ANY, _L("Input access code")); @@ -759,7 +759,7 @@ void SelectMachinePopup::update_user_devices() } }); - op->Bind(EVT_EDIT_PRINT_NAME, [this, mobj](wxCommandEvent &e) { + op->Bind(EVT_EDIT_PRINT_NAME, [mobj](wxCommandEvent &e) { EditDevNameDialog dlg; dlg.set_machine_obj(mobj); dlg.ShowModal(); diff --git a/src/slic3r/GUI/SendMultiMachinePage.cpp b/src/slic3r/GUI/SendMultiMachinePage.cpp index 7b7c42922f..3a52caec3f 100644 --- a/src/slic3r/GUI/SendMultiMachinePage.cpp +++ b/src/slic3r/GUI/SendMultiMachinePage.cpp @@ -1468,7 +1468,7 @@ void SendMultiMachinePage::sync_ams_list() item->set_ams_info(wxColour("#CECECE"), "Ext", 0, std::vector<wxColour>()); m_ams_list_sizer->Add(item, 0, wxALL, FromDIP(4)); - item->Bind(wxEVT_LEFT_UP, [this, item, materials, extruder](wxMouseEvent& e) {}); + item->Bind(wxEVT_LEFT_UP, [materials](wxMouseEvent& e) {}); item->Bind(wxEVT_LEFT_DOWN, [this, item, materials, extruder](wxMouseEvent& e) { MaterialHash::iterator iter = m_material_list.begin(); while (iter != m_material_list.end()) { diff --git a/src/slic3r/GUI/SkipPartCanvas.cpp b/src/slic3r/GUI/SkipPartCanvas.cpp index 5e01b8140f..7b7db213b1 100644 --- a/src/slic3r/GUI/SkipPartCanvas.cpp +++ b/src/slic3r/GUI/SkipPartCanvas.cpp @@ -287,7 +287,7 @@ void SkipPartCanvas::Render() glDisable(GL_CULL_FACE); glEnable(GL_STENCIL_TEST); - auto draw_shape = [this, border_w](const int stencil, const PartState part_type, const ColorRGB& rgb) { + auto draw_shape = [this](const int stencil, const PartState part_type, const ColorRGB& rgb) { glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_ALWAYS, stencil, 0xFF); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); @@ -335,7 +335,7 @@ void SkipPartCanvas::Render() // stencil3 => skipped draw_shape(skipped_stencil, psSkipped, ColorRGB{95 / 255.f, 95 / 255.f, 95 / 255.f}); - auto draw_mask = [this, view_rect, border_w, w, h](const int stencil, const PartState part_type, + auto draw_mask = [this, view_rect](const int stencil, const PartState part_type, const ColorRGB& background, const ColorRGB& line, const ColorRGB& bound) { glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_EQUAL, stencil, 0xFF); diff --git a/src/slic3r/GUI/SliceInfoPanel.cpp b/src/slic3r/GUI/SliceInfoPanel.cpp index 37a3ba698d..a7e436c0ff 100644 --- a/src/slic3r/GUI/SliceInfoPanel.cpp +++ b/src/slic3r/GUI/SliceInfoPanel.cpp @@ -115,7 +115,7 @@ SliceInfoPopup::SliceInfoPopup(wxWindow *parent, wxBitmap bmp, BBLSliceInfo *inf f_sizer->Add(f_type, 0, wxEXPAND | wxALL, FromDIP(5)); f_sizer->Add(f_used_g, 0, wxEXPAND | wxALL, FromDIP(5)); grid_sizer->Add(f_sizer, 0, wxEXPAND, 0); - f_type->Bind(wxEVT_LEFT_DOWN, [this](auto &e) {}); + f_type->Bind(wxEVT_LEFT_DOWN, [](auto &e) {}); } } topSizer->Add(grid_sizer, 0, wxALL, FromDIP(5)); diff --git a/src/slic3r/GUI/StepMeshDialog.cpp b/src/slic3r/GUI/StepMeshDialog.cpp index b1a8e2319a..c6131b7bfa 100644 --- a/src/slic3r/GUI/StepMeshDialog.cpp +++ b/src/slic3r/GUI/StepMeshDialog.cpp @@ -167,7 +167,7 @@ StepMeshDialog::StepMeshDialog(wxWindow* parent, Slic3r::Step& file, double line e.Skip(); })); // textctrl bind slider - linear_input->Bind(wxEVT_TEXT, ([this, linear_slider, linear_input](wxCommandEvent& e) { + linear_input->Bind(wxEVT_TEXT, ([linear_slider, linear_input](wxCommandEvent& e) { double slider_value_long; int slider_value; wxString value = linear_input->GetTextCtrl()->GetValue(); @@ -222,7 +222,7 @@ StepMeshDialog::StepMeshDialog(wxWindow* parent, Slic3r::Step& file, double line e.Skip(); })); // textctrl bind slider - angle_input->Bind(wxEVT_TEXT, ([this, angle_slider, angle_input](wxCommandEvent& e) { + angle_input->Bind(wxEVT_TEXT, ([angle_slider, angle_input](wxCommandEvent& e) { double slider_value_long; int slider_value; wxString value = angle_input->GetTextCtrl()->GetValue(); diff --git a/src/slic3r/GUI/SyncAmsInfoDialog.cpp b/src/slic3r/GUI/SyncAmsInfoDialog.cpp index 9515ecc116..7ae48008c8 100644 --- a/src/slic3r/GUI/SyncAmsInfoDialog.cpp +++ b/src/slic3r/GUI/SyncAmsInfoDialog.cpp @@ -1113,7 +1113,7 @@ void SyncAmsInfoDialog::init_bind() e.Skip(); }); - Bind(EVT_CONNECT_LAN_MODE_PRINT, [this](wxCommandEvent &e) { + Bind(EVT_CONNECT_LAN_MODE_PRINT, [](wxCommandEvent &e) { if (e.GetInt() == 0) { DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager(); if (!dev) return; @@ -2644,7 +2644,7 @@ void SyncAmsInfoDialog::reset_and_sync_ams_list() item_index++; contronal_index++; - item->Bind(wxEVT_LEFT_UP, [this, item, materials, extruder](wxMouseEvent &e) {}); + item->Bind(wxEVT_LEFT_UP, [materials](wxMouseEvent &e) {}); item->Bind(wxEVT_LEFT_DOWN, [this, item, materials, extruder, item_index_str](wxMouseEvent &e) { MaterialHash::iterator iter = m_materialList.begin(); while (iter != m_materialList.end()) { diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 0eb5c9281d..d65d7f68bd 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -459,7 +459,7 @@ void Tab::create_preset_tab() // tree m_tabctrl = new TabCtrl(panel, wxID_ANY, wxDefaultPosition, wxSize(20 * m_em_unit, -1), wxTR_NO_BUTTONS | wxTR_HIDE_ROOT | wxTR_SINGLE | wxTR_NO_LINES | wxBORDER_NONE | wxWANTS_CHARS | wxTR_FULL_ROW_HIGHLIGHT); - m_tabctrl->Bind(wxEVT_RIGHT_DOWN, [this](auto &e) {}); // disable right select + m_tabctrl->Bind(wxEVT_RIGHT_DOWN, [](auto &e) {}); // disable right select m_tabctrl->SetFont(Label::Body_14); //m_left_sizer->Add(m_tabctrl, 1, wxEXPAND); const int img_sz = int(32 * scale_factor + 0.5f); @@ -6075,7 +6075,7 @@ void TabPrinter::toggle_options() auto nozzle_volumes = m_preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type"); auto extruders = m_config->option<ConfigOptionEnumsGeneric>("extruder_type"); auto get_index_for_extruder = - [this, &extruders, &nozzle_volumes](int extruder_id, int stride = 1) { + [this, &extruders](int extruder_id, int stride = 1) { return m_config->get_index_for_extruder(extruder_id + 1, "printer_extruder_id", ExtruderType(extruders->values[extruder_id]), get_actual_nozzle_volume_type(extruder_id), "printer_extruder_variant", stride); }; @@ -7713,18 +7713,18 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep this->update_changed_ui(); }; - deps.checkbox_title->Bind(wxEVT_LEFT_DOWN,([this, &deps, on_toggle](wxMouseEvent& e) { + deps.checkbox_title->Bind(wxEVT_LEFT_DOWN,([&deps, on_toggle](wxMouseEvent& e) { if (e.GetEventType() == wxEVT_LEFT_DCLICK) return; on_toggle(!deps.checkbox->GetValue()); e.Skip(); })); - deps.checkbox_title->Bind(wxEVT_LEFT_DCLICK,([this, &deps, on_toggle](wxMouseEvent& e) { + deps.checkbox_title->Bind(wxEVT_LEFT_DCLICK,([&deps, on_toggle](wxMouseEvent& e) { on_toggle(!deps.checkbox->GetValue()); e.Skip(); })); - deps.checkbox->Bind(wxEVT_TOGGLEBUTTON, ([this, on_toggle](wxCommandEvent& e) { + deps.checkbox->Bind(wxEVT_TOGGLEBUTTON, ([on_toggle](wxCommandEvent& e) { on_toggle(e.IsChecked()); e.Skip(); }), deps.checkbox->GetId()); @@ -8306,7 +8306,7 @@ void Tab::switch_excluder(int extruder_id, bool reload) return; } auto get_index_for_extruder = - [this, &extruders, &nozzle_volumes, variant_keys = extruder_variant_keys[m_type >= Preset::TYPE_COUNT ? Preset::TYPE_PRINT : m_type]](int extruder_id, int stride = 1) { + [this, &extruders, variant_keys = extruder_variant_keys[m_type >= Preset::TYPE_COUNT ? Preset::TYPE_PRINT : m_type]](int extruder_id, int stride = 1) { return m_config->get_index_for_extruder(extruder_id + 1, variant_keys.first, ExtruderType(extruders->values[extruder_id]), get_actual_nozzle_volume_type(extruder_id), variant_keys.second, stride); }; @@ -8363,7 +8363,7 @@ void Tab::sync_excluder() auto nozzle_volumes = m_preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type"); auto extruders = printer_preset.config.option<ConfigOptionEnumsGeneric>("extruder_type"); auto get_index_for_extruder = - [this, &extruders, &nozzle_volumes, variant_keys = extruder_variant_keys[m_type >= Preset::TYPE_COUNT ? Preset::TYPE_PRINT : m_type]](int extruder_id, NozzleVolumeType nozzle_type) { + [this, &extruders, variant_keys = extruder_variant_keys[m_type >= Preset::TYPE_COUNT ? Preset::TYPE_PRINT : m_type]](int extruder_id, NozzleVolumeType nozzle_type) { return m_config->get_index_for_extruder(extruder_id + 1, variant_keys.first, ExtruderType(extruders->values[extruder_id]), nozzle_type, variant_keys.second); }; diff --git a/src/slic3r/GUI/TroubleshootDialog.cpp b/src/slic3r/GUI/TroubleshootDialog.cpp index b0a8f71930..c1dee7ca5c 100644 --- a/src/slic3r/GUI/TroubleshootDialog.cpp +++ b/src/slic3r/GUI/TroubleshootDialog.cpp @@ -71,7 +71,7 @@ wxFlexGridSizer* TroubleshootDialog::create_item_loaded_profiles() auto gen_stats = GetProfilesOverview(); gen_stats = ""; // clear mem. not needed after generating m_..._act, m_..._usr variables - auto add_sizer = [this, g_sizer, create_label](PresetCollection* col, wxString label, int in_use, int user) { + auto add_sizer = [g_sizer, create_label](PresetCollection* col, wxString label, int in_use, int user) { int sys = 0; for (auto it = col->begin(); it != col->end(); it++) { if (it->is_system) @@ -178,7 +178,7 @@ TroubleshootDialog::TroubleshootDialog() return wxTheClipboard->SetData(new wxTextDataObject(GetSysInfoAll())); }); - sys_less_btn->Bind(wxEVT_BUTTON, [this, sys_panel, sys_less_btn, sys_info_lines, sys_copy_btn](wxCommandEvent &e) { + sys_less_btn->Bind(wxEVT_BUTTON, [this, sys_panel, sys_less_btn, sys_info_lines](wxCommandEvent &e) { m_sys_panel_mode = !m_sys_panel_mode; sys_panel->SetText(sys_info_lines(m_sys_panel_mode)); sys_less_btn->SetLabel(m_sys_panel_mode ? _L("Hide") : _L("Show")); diff --git a/src/slic3r/GUI/WebGuideDialog.cpp b/src/slic3r/GUI/WebGuideDialog.cpp index 6b58fffead..ae259f23d1 100644 --- a/src/slic3r/GUI/WebGuideDialog.cpp +++ b/src/slic3r/GUI/WebGuideDialog.cpp @@ -588,7 +588,7 @@ void GuideFrame::OnScriptMessage(wxWebViewEvent &evt) else if (strCmd == "user_guide_create_printer") { this->EndModal(wxID_CANCEL); this->Close(); - GUI::wxGetApp().CallAfter([this] {GUI::wxGetApp().sidebar().create_printer_preset();}); + GUI::wxGetApp().CallAfter([] {GUI::wxGetApp().sidebar().create_printer_preset();}); } else if (strCmd == "user_guide_cancel") { this->EndModal(wxID_CANCEL); @@ -871,7 +871,7 @@ bool GuideFrame::apply_config(AppConfig *app_config, PresetBundle *preset_bundle std::string preferred_model; std::string preferred_variant; PrinterTechnology preferred_pt = ptFFF; - auto get_preferred_printer_model = [preset_bundle, enabled_vendors, old_enabled_vendors, preferred_pt](const std::string& bundle_name, std::string& variant) { + auto get_preferred_printer_model = [preset_bundle, enabled_vendors, old_enabled_vendors](const std::string& bundle_name, std::string& variant) { const auto config = enabled_vendors.find(bundle_name); if (config == enabled_vendors.end()) return std::string(); diff --git a/src/slic3r/GUI/WebUserLoginDialog.cpp b/src/slic3r/GUI/WebUserLoginDialog.cpp index 4222ce745b..829e7ef106 100644 --- a/src/slic3r/GUI/WebUserLoginDialog.cpp +++ b/src/slic3r/GUI/WebUserLoginDialog.cpp @@ -489,7 +489,7 @@ void ZUserLogin::OnScriptMessage(wxWebViewEvent &evt) std::string jump_url = j["data"]["url"].get<std::string>(); int loopback_port = ensure_loopback_port(); jump_url = rewrite_loopback_url(jump_url, loopback_port); - CallAfter([this, jump_url] { + CallAfter([jump_url] { wxString url = wxString::FromUTF8(jump_url); wxLaunchDefaultBrowser(url); }); @@ -498,7 +498,7 @@ void ZUserLogin::OnScriptMessage(wxWebViewEvent &evt) else if (strCmd == "new_webpage") { if (j["data"].contains("url")) { std::string jump_url = j["data"]["url"].get<std::string>(); - CallAfter([this, jump_url] { + CallAfter([jump_url] { wxString url = wxString::FromUTF8(jump_url); wxLaunchDefaultBrowser(url); }); diff --git a/src/slic3r/Utils/3DPrinterOS.cpp b/src/slic3r/Utils/3DPrinterOS.cpp index 79c8a62700..b177e37e38 100755 --- a/src/slic3r/Utils/3DPrinterOS.cpp +++ b/src/slic3r/Utils/3DPrinterOS.cpp @@ -627,7 +627,7 @@ void C3DPrinterOS::send_form( responseTree.put("result", false); responseTree.put("message", error); }) - .on_complete([&, this](std::string body, unsigned) { + .on_complete([&](std::string body, unsigned) { std::stringstream ss(body); try { pt::read_json(ss, responseTree); diff --git a/src/slic3r/Utils/Moonraker.cpp b/src/slic3r/Utils/Moonraker.cpp index f1ca432390..73fdb8486a 100644 --- a/src/slic3r/Utils/Moonraker.cpp +++ b/src/slic3r/Utils/Moonraker.cpp @@ -80,7 +80,7 @@ bool Moonraker::test(wxString &msg) const res = false; msg = format_error(body, error, status); }) - .on_complete([&, this](std::string body, unsigned) { + .on_complete([&](std::string body, unsigned) { BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: /server/info body: %2%") % name % body; try { std::stringstream ss(body); @@ -141,7 +141,7 @@ bool Moonraker::get_storage(wxArrayString &storage_path, wxArrayString &storage_ % name % error % status % body; } }) - .on_complete([&, this](std::string body, unsigned) { + .on_complete([&](std::string body, unsigned) { BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: /server/files/roots body: %2%") % name % body; try { std::stringstream ss(body); diff --git a/src/slic3r/Utils/Obico.cpp b/src/slic3r/Utils/Obico.cpp index 5541d1c683..92d748b496 100644 --- a/src/slic3r/Utils/Obico.cpp +++ b/src/slic3r/Utils/Obico.cpp @@ -86,7 +86,7 @@ bool Obico::test(wxString& msg) const res = false; msg = format_error(body, error, status); }) - .on_complete([&, this](std::string body, unsigned) { + .on_complete([&](std::string body, unsigned) { BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got version: %2%") % name % body; }) #ifdef WIN32 diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 56a2b66b49..663a4ce8c3 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -513,7 +513,7 @@ void PresetUpdater::priv::sync_resources(std::string http_url, std::map<std::str cancel_http = true; } }) - .on_complete([this, &resource_list, resources](std::string body, unsigned) { + .on_complete([&resource_list, resources](std::string body, unsigned) { try { BOOST_LOG_TRIVIAL(info) << "[Orca Updater]: request_resources, body=" << body; diff --git a/src/slic3r/Utils/Repetier.cpp b/src/slic3r/Utils/Repetier.cpp index 0d269e1cd5..a524f29b71 100644 --- a/src/slic3r/Utils/Repetier.cpp +++ b/src/slic3r/Utils/Repetier.cpp @@ -73,7 +73,7 @@ bool Repetier::test(wxString &msg) const res = false; msg = format_error(body, error, status); }) - .on_complete([&, this](std::string body, unsigned) { + .on_complete([&](std::string body, unsigned) { BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got version: %2%") % name % body; try { diff --git a/src/slic3r/Utils/SimplyPrint.cpp b/src/slic3r/Utils/SimplyPrint.cpp index bbfd5209c9..a3edfd98ee 100644 --- a/src/slic3r/Utils/SimplyPrint.cpp +++ b/src/slic3r/Utils/SimplyPrint.cpp @@ -192,7 +192,7 @@ bool SimplyPrint::do_api_call(std::function<Http(bool)> bool res = true; - const auto create_request = [this, &build_request, &res, &on_complete](const std::string& access_token, bool is_retry) { + const auto create_request = [&build_request, &res, &on_complete](const std::string& access_token, bool is_retry) { auto http = build_request(is_retry); set_auth(http, access_token); http.header("User-Agent", "SimplyPrint Orca Plugin") @@ -300,7 +300,7 @@ bool SimplyPrint::do_temp_upload(const boost::filesystem::path& file_path, return http; }, - [&error_fn, &filename, this](std::string body, unsigned status) { + [&error_fn, &filename](std::string body, unsigned status) { BOOST_LOG_TRIVIAL(info) << boost::format("SimplyPrint: File uploaded: HTTP %1%: %2%") % status % body; // Get file UUID @@ -423,7 +423,7 @@ bool SimplyPrint::do_chunk_upload(const boost::filesystem::path& file_path, cons return http; }, - [&error_fn, i, chunk_amount, this, &chunk_id, &delete_token](std::string body, unsigned status) { + [&error_fn, i, chunk_amount, &chunk_id, &delete_token](std::string body, unsigned status) { BOOST_LOG_TRIVIAL(info) << boost::format("SimplyPrint: File chunk [%1%/%2%] uploaded: HTTP %3%: %4%") % (i + 1) % chunk_amount % status % body; if (i == 0) { // First chunk, parse chunk id From 640fd9f454d26ca6ef37f16b72ed60f39d8559ed Mon Sep 17 00:00:00 2001 From: Alexandre Folle de Menezes <afmenez@terra.com.br> Date: Wed, 2 Sep 2026 09:36:54 -0300 Subject: [PATCH 25/51] Fix misc. errors on GUI strings (#15468) * Fix misc. errors on GUI strings * Adding context to single-letter unit strings * Fix duplicate strings on po files --- localization/i18n/OrcaSlicer.pot | 33 +++++----- localization/i18n/ca/OrcaSlicer_ca.po | 38 ++++++------ localization/i18n/cs/OrcaSlicer_cs.po | 36 +++++------ localization/i18n/de/OrcaSlicer_de.po | 36 +++++------ localization/i18n/en/OrcaSlicer_en.po | 32 +++++----- localization/i18n/es/OrcaSlicer_es.po | 42 ++++++------- localization/i18n/eu/OrcaSlicer_eu.po | 69 +++++++-------------- localization/i18n/fr/OrcaSlicer_fr.po | 44 +++++++------ localization/i18n/hu/OrcaSlicer_hu.po | 34 +++++----- localization/i18n/it/OrcaSlicer_it.po | 38 ++++++------ localization/i18n/ja/OrcaSlicer_ja.po | 46 +++++++------- localization/i18n/ko/OrcaSlicer_ko.po | 41 ++++++------ localization/i18n/lt/OrcaSlicer_lt.po | 58 +++++------------ localization/i18n/nl/OrcaSlicer_nl.po | 48 +++++++------- localization/i18n/pl/OrcaSlicer_pl.po | 45 ++++++++------ localization/i18n/pt_BR/OrcaSlicer_pt_BR.po | 48 +++++++------- localization/i18n/ru/OrcaSlicer_ru.po | 34 +++++----- localization/i18n/sv/OrcaSlicer_sv.po | 44 +++++++------ localization/i18n/th/OrcaSlicer_th.po | 36 +++++------ localization/i18n/tr/OrcaSlicer_tr.po | 42 ++++++------- localization/i18n/uk/OrcaSlicer_uk.po | 37 ++++++----- localization/i18n/vi/OrcaSlicer_vi.po | 38 ++++++------ localization/i18n/zh_CN/OrcaSlicer_zh_CN.po | 35 ++++++----- localization/i18n/zh_TW/OrcaSlicer_zh_TW.po | 33 +++++----- src/libslic3r/PrintConfig.cpp | 39 ++++++------ src/libslic3r/calib.cpp | 4 +- src/slic3r/GUI/CreatePresetsDialog.cpp | 6 +- src/slic3r/GUI/FilamentMapDialog.cpp | 2 +- src/slic3r/GUI/MainFrame.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 6 +- src/slic3r/GUI/Tab.cpp | 4 +- src/slic3r/GUI/TroubleshootDialog.cpp | 4 +- src/slic3r/Utils/3DPrinterOS.cpp | 2 +- 33 files changed, 513 insertions(+), 543 deletions(-) diff --git a/localization/i18n/OrcaSlicer.pot b/localization/i18n/OrcaSlicer.pot index b183df098b..4f4e5079da 100644 --- a/localization/i18n/OrcaSlicer.pot +++ b/localization/i18n/OrcaSlicer.pot @@ -3,7 +3,6 @@ # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # -#, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" @@ -5951,10 +5950,10 @@ msgstr "" msgid "Load a model" msgstr "" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "" msgid "Import Configs" @@ -7663,7 +7662,7 @@ msgstr "" msgid "Customized Preset" msgstr "" -msgid "Component name(s) inside step file not in UTF8 format!" +msgid "Component name(s) inside step file not in UTF-8 format!" msgstr "" msgid "Because of unsupported text encoding, garbage characters may appear!" @@ -7685,7 +7684,7 @@ msgstr "" #, possible-c-format, possible-boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" msgid "Object too small" @@ -10329,11 +10328,11 @@ msgstr "" msgid "No modifications need to be copied." msgstr "" -msgid "Copy paramters" +msgid "Copy parameters" msgstr "" #, possible-c-format, possible-boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "" #, possible-c-format, possible-boost-format @@ -11874,7 +11873,7 @@ msgstr "" msgid "Other layers" msgstr "" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "" msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." @@ -14675,7 +14674,7 @@ msgstr "" msgid "Reduce infill retraction" msgstr "" -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "" msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -14831,7 +14830,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" @@ -14874,7 +14873,7 @@ msgstr "" msgid "Z-hop height" msgstr "" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "" msgid "Z-hop lower boundary" @@ -18191,17 +18190,17 @@ msgstr "" msgid "Only display the filament names with changes to filament presets." msgstr "" -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "" msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" msgid "Please select at least one printer or filament." @@ -18416,7 +18415,7 @@ msgstr "" msgid "We need information for diagnosing source of the issue. Check wiki page for detailed guide." msgstr "" -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "" msgid "Any additional visual examples like images or screen recordings might be helpful while reporting the issue." @@ -18458,7 +18457,7 @@ msgstr "" msgid "Stored logs" msgstr "" -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "" msgid "Profiles" @@ -18523,7 +18522,7 @@ msgstr "" msgid "Authorizing..." msgstr "" -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "" msgid "Could not parse server response." diff --git a/localization/i18n/ca/OrcaSlicer_ca.po b/localization/i18n/ca/OrcaSlicer_ca.po index d78487b947..873cf0d7fb 100644 --- a/localization/i18n/ca/OrcaSlicer_ca.po +++ b/localization/i18n/ca/OrcaSlicer_ca.po @@ -6419,10 +6419,10 @@ msgstr "Importar 3MF STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "Carregar un model" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "Importar fitxer ZIP" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Carregar models continguts dins d'un arxiu zip" msgid "Import Configs" @@ -8232,8 +8232,8 @@ msgid "Customized Preset" msgstr "Perfil personalitzat" # AI Translated -msgid "Component name(s) inside step file not in UTF8 format!" -msgstr "Els noms dels components dins del fitxer STEP no tenen format UTF8!" +msgid "Component name(s) inside step file not in UTF-8 format!" +msgstr "Els noms dels components dins del fitxer STEP no tenen format UTF-8!" # AI Translated msgid "Because of unsupported text encoding, garbage characters may appear!" @@ -8255,10 +8255,10 @@ msgstr "El volum de l'objecte és zero" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "L'objecte del fitxer %s és massa petit, i potser en metres o polzades.\n" -" Vols escalar a mil·límetres?" +"Vols escalar a mil·límetres?" msgid "Object too small" msgstr "Objecte massa petit" @@ -11189,12 +11189,12 @@ msgid "No modifications need to be copied." msgstr "No cal copiar cap modificació." # AI Translated -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Copiar els paràmetres" # AI Translated #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "Modificar els paràmetres de %s" # AI Translated @@ -12868,8 +12868,8 @@ msgstr "mm o %" msgid "Other layers" msgstr "Altres capes" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." -msgstr "Temperatura del llit per a les capes excepte la primera. Un valor de 0 significa que el filament no admet la impressió sobre el Cool Plate SuperTack." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgstr "Temperatura del llit de les capes excepte la inicial. Un valor de 0 significa que el filament no admet la impressió sobre el Cool Plate SuperTack." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "Temperatura del llit de les capes excepte la inicial. El valor 0 significa que el filament no admet imprimir a una Base Freda." @@ -16197,7 +16197,7 @@ msgid "Reduce infill retraction" msgstr "Reduir la retracció de farciment" # AI Translated -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "No retrau quan el desplaçament està totalment a la zona de farciment. Això vol dir que l'oozing( goteig ) queda amagat. Això pot reduir els temps de retracció per a models complexos i estalviar temps d'impressió, però fer que el laminat i la generació de Codi-G siguin més lents. Tingueu en compte que el salt en Z tampoc es realitza a les zones on s'omet la retracció." msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -16373,7 +16373,7 @@ msgstr "Quantitat de retracció després de netejar" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "Longitud de la retracció ràpida després de netejar, relativa a la longitud de retracció.\n" @@ -16420,7 +16420,7 @@ msgstr "Quan s'activa la retracció abans d'un canvi d'eina, el filament es reti msgid "Z-hop height" msgstr "Alçada Z-hop" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "Cade vegada que es fa una retracció, s'aixeca una mica el broquet per crear espai lliure entre el broquet i la impressió. Evita que el broquet colpegi la impressió en els desplaçaments. L'ús de la línia espiral per aixecar z pot evitar l'aparició de fils" msgid "Z-hop lower boundary" @@ -20071,19 +20071,19 @@ msgstr "Mostrar només els noms de les impressores amb canvis als perfils d'impr msgid "Only display the filament names with changes to filament presets." msgstr "Mostrar només els noms dels filaments amb canvis en els perfils de filament." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "Només es mostraran els noms de les impressores amb perfils d'impressora d'usuari i cada perfil que trieu s'exportarà com a fitxer zip." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Només es mostraran els noms dels filaments amb perfils de filament d'usuari, \n" "i tots els perfils de filament d'usuari de cada nom de filament que seleccioneu s'exportaran com a zip." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Només es mostraran els noms de les impressores amb perfils de processament modificats, \n" "I tots els valors perfils del procés d'usuari de cada nom d'impressora que seleccioneu s'exportaran com a ZIP." @@ -20328,7 +20328,7 @@ msgid "We need information for diagnosing source of the issue. Check wiki page f msgstr "Necessitem informació per diagnosticar l'origen del problema. Consulteu la pàgina wiki per a una guia detallada." # AI Translated -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "El botó Empaquetar recull el fitxer del projecte i els registres de la sessió actual en un fitxer zip." # AI Translated @@ -20384,7 +20384,7 @@ msgid "Stored logs" msgstr "Registres emmagatzemats" # AI Translated -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Empaqueta tots els registres emmagatzemats en un fitxer zip." # AI Translated @@ -20472,7 +20472,7 @@ msgid "Authorizing..." msgstr "Autoritzant..." # AI Translated -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Error. No es pot obtenir el testimoni d'api per a l'autorització" # AI Translated diff --git a/localization/i18n/cs/OrcaSlicer_cs.po b/localization/i18n/cs/OrcaSlicer_cs.po index 7eeb1072c0..f51c5dc3e2 100644 --- a/localization/i18n/cs/OrcaSlicer_cs.po +++ b/localization/i18n/cs/OrcaSlicer_cs.po @@ -6380,10 +6380,10 @@ msgstr "Importovat 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "Načíst model" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "Importovat ZIP archiv" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Načíst modely obsažené v zip archivu" msgid "Import Configs" @@ -8193,7 +8193,7 @@ msgstr "Potvrďte prosím, že je G-code v těchto předvolbách bezpečný, aby msgid "Customized Preset" msgstr "Přizpůsobená předvolba" -msgid "Component name(s) inside step file not in UTF8 format!" +msgid "Component name(s) inside step file not in UTF-8 format!" msgstr "Názvy komponent v souboru STEP nejsou ve formátu UTF-8!" # AI Translated @@ -8216,7 +8216,7 @@ msgstr "Objem objektu je nula." #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "Objekt ze souboru %s je příliš malý a může být v metrech nebo palcích.\n" "Chcete převést měřítko na milimetry?" @@ -11133,12 +11133,12 @@ msgid "No modifications need to be copied." msgstr "Není třeba kopírovat žádné úpravy." # AI Translated -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Kopírovat parametry" # AI Translated #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "Upravit parametry %s" # AI Translated @@ -12853,7 +12853,7 @@ msgstr "mm nebo %" msgid "Other layers" msgstr "Ostatní vrstvy" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "Teplota desky pro vrstvy kromě počáteční. Hodnota 0 znamená, že filament nepodporuje tisk na chladicí podložce SuperTack." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." @@ -16143,8 +16143,8 @@ msgstr "Počáteční a koncové body, které vedou z oblasti řezače do odpadk msgid "Reduce infill retraction" msgstr "Snížit retrakci při výplni" -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." -msgstr "Neprovádět retrakci, pokud se přejezd nachází zcela uvnitř oblasti výplně. Případné vytékání materiálu tak nebude viditelné. To může snížit počet retrakčních pohybů u složitých modelů a zkrátit dobu tisku, ale zároveň zpomalit slicování a generování G-code. V oblastech, kde je retrakce přeskočena, se zároveň neprovádí ani z-hop." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." +msgstr "Neprovádět retrakci, pokud se přejezd nachází zcela uvnitř oblasti výplně. Případné vytékání materiálu tak nebude viditelné. To může snížit počet retrakčních pohybů u složitých modelů a zkrátit dobu tisku, ale zároveň zpomalit slicování a generování G-code. V oblastech, kde je retrakce přeskočena, se zároveň neprovádí ani Z-hop." msgid "This option will drop the temperature of the inactive extruders to prevent oozing." msgstr "Tato možnost sníží teplotu neaktivních extruderů, aby se zabránilo vytékání." @@ -16317,7 +16317,7 @@ msgstr "Délka retrakce po očištění" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "Délka rychlé retrakce po očištění, vztažená k délce retrakce.\n" @@ -16364,7 +16364,7 @@ msgstr "Když je retrakce spuštěna před změnou nástroje, filament se zatáh msgid "Z-hop height" msgstr "Výška Z-hopu" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "Po každém stažení filamentu se tryska mírně zvedne, aby vznikla mezera mezi tryskou a tiskem. Zabrání kolizi trysky s tiskem při přesunu. Použití spirálových linií pro zvedání v ose Z může zabránit vytahování vláken." msgid "Z-hop lower boundary" @@ -19992,19 +19992,19 @@ msgstr "Zobrazit pouze názvy tiskáren se změnami v předvolbách tiskárny, f msgid "Only display the filament names with changes to filament presets." msgstr "Zobrazit pouze názvy filamentů se změnami ve filamentových profilech." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "Zobrazí se pouze názvy tiskáren s uživatelskými předvolbami tiskárny, každá vybraná předvolba bude exportována jako zip archiv." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Zobrazí se pouze názvy filamentů s uživatelskými filamentovými profily. \n" "Všechny uživatelské filamentové profily ve vybraných filamentech budou exportovány jako zip archiv." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Zobrazí se pouze názvy tiskáren se změněnými procesními předvolbami. \n" "Všechny uživatelské procesní předvolby ve vybraných tiskárnách budou exportovány jako zip archiv." @@ -20250,7 +20250,7 @@ msgid "We need information for diagnosing source of the issue. Check wiki page f msgstr "Pro diagnostiku zdroje problému potřebujeme informace. Podrobný návod najdete na stránce wiki." # AI Translated -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "Tlačítko Zabalit shromáždí soubor projektu a protokoly aktuální relace do souboru zip." # AI Translated @@ -20306,7 +20306,7 @@ msgid "Stored logs" msgstr "Uložené protokoly" # AI Translated -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Zabalí všechny uložené protokoly do souboru zip." # AI Translated @@ -20394,8 +20394,8 @@ msgid "Authorizing..." msgstr "Probíhá autorizace..." # AI Translated -msgid "Error. Can't get api token for authorization" -msgstr "Chyba. Nelze získat api token pro autorizaci" +msgid "Error. Can't get API token for authorization" +msgstr "Chyba. Nelze získat API token pro autorizaci" # AI Translated msgid "Could not parse server response." diff --git a/localization/i18n/de/OrcaSlicer_de.po b/localization/i18n/de/OrcaSlicer_de.po index 92143b907b..8b27148a03 100644 --- a/localization/i18n/de/OrcaSlicer_de.po +++ b/localization/i18n/de/OrcaSlicer_de.po @@ -6272,10 +6272,10 @@ msgstr "Importiere 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "Lade ein Modell" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "Zip-Archiv importieren" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Modelle aus einem Zip-Archiv laden" msgid "Import Configs" @@ -8063,8 +8063,8 @@ msgstr "Bitte bestätigen Sie, dass die G-Codes innerhalb dieser Profile sicher msgid "Customized Preset" msgstr "Benutzerdefinierte Profile" -msgid "Component name(s) inside step file not in UTF8 format!" -msgstr "Der Name der Komponenten in der Step-Datei ist nicht im UTF8-Format!" +msgid "Component name(s) inside step file not in UTF-8 format!" +msgstr "Der Name der Komponenten in der Step-Datei ist nicht im UTF-8-Format!" msgid "Because of unsupported text encoding, garbage characters may appear!" msgstr "Aufgrund der nicht unterstützten Textkodierung können unbrauchbare Zeichen erscheinen!" @@ -8085,10 +8085,10 @@ msgstr "Das Volumen des Objekts ist Null" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "Das Objekt aus der Datei %s ist zu klein und vielleicht in Metern oder Zoll angeben.\n" -" Möchten Sie auf Millimeter skalieren?" +"Möchten Sie auf Millimeter skalieren?" msgid "Object too small" msgstr "Objekt zu klein" @@ -10940,11 +10940,11 @@ msgstr "%s: %s" msgid "No modifications need to be copied." msgstr "Es müssen keine Änderungen kopiert werden." -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Parameter kopieren" #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "Parameter von %s ändern" #, c-format, boost-format @@ -12570,7 +12570,7 @@ msgstr "mm o. %" msgid "Other layers" msgstr "Andere Schichten" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "Dies ist die Betttemperatur für Schichten mit Ausnahme der Ersten. Ein Wert von 0 bedeutet, dass das Filament auf der kalten Druckplatte SuperTack nicht unterstützt wird." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." @@ -15802,7 +15802,7 @@ msgstr "Die Start- und Endpunkte, vom Schnittbereich bis zum Auswurfschacht." msgid "Reduce infill retraction" msgstr "Rückzug bei der Füllung verringern" -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "Kein Rückzug, wenn sich die Bewegung des Druckkopfes vollständig in einem Füllbereich befindet. Das bedeutet, dass das herauslaufen des Filaments nicht zu sehen ist. Dies kann die Zeit für das zurückziehen des Filaments bei komplexeren Modellen verkürzen und Druckzeit sparen, verlangsamt aber das Slicen und die G-Code Generierung." msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -15972,7 +15972,7 @@ msgstr "Rückzugsmenge nach dem Wischen" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "Die Länge des schnellen Rückzugs nach dem Wischen, relativ zur Rückzugslänge.\n" @@ -16019,7 +16019,7 @@ msgstr "Wenn vor einem Werkzeugwechsel ein Rückzug ausgelöst wird, wird das Fi msgid "Z-hop height" msgstr "Z-Hub-Höhe" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "Bei jedem Rückzug wird die Düse ein wenig angehoben, um einen Abstand zwischen Düse und Druck zu schaffen. Dadurch wird verhindert, dass die Düse bei der Verfahrbewegung gegen den Druck stößt. Die Verwendung einer Spirallinie zum Anheben von z kann Fadenbildung verhindern." msgid "Z-hop lower boundary" @@ -19600,19 +19600,19 @@ msgstr "Nur Druckernamen mit Änderungen an Drucker-, Filament- und Prozessprofi msgid "Only display the filament names with changes to filament presets." msgstr "Nur die Filamentnamen mit Änderungen an den Filamentprofilen werden angezeigt." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "Nur Druckernamen mit Benutzerdruckerprofilen werden angezeigt, und jedes Profil, das Sie auswählen, wird als ZIP exportiert." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Nur die Filamentnamen mit Benutzerfilamentvorlagen werden angezeigt, \n" "und alle Benutzerfilamentvorlagen in jedem Filamentnamen, den Sie auswählen, " msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Nur Druckernamen mit geänderten Prozessvorlagen werden angezeigt, \n" "und alle Benutzerprozessvorlagen in jedem Druckernamen, den Sie auswählen, werden als ZIP exportiert." @@ -19841,7 +19841,7 @@ msgstr "Systeminformationen in die Zwischenablage kopieren" msgid "We need information for diagnosing source of the issue. Check wiki page for detailed guide." msgstr "Wir benötigen Informationen zur Diagnose der Ursache des Problems. Überprüfen Sie die Wiki-Seite für eine detaillierte Anleitung." -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "Die Schaltfläche „Packen“ sammelt die Projektdatei und Protokolle der aktuellen Sitzung in einer ZIP-Datei." msgid "Any additional visual examples like images or screen recordings might be helpful while reporting the issue." @@ -19883,7 +19883,7 @@ msgstr "Protokollstufe" msgid "Stored logs" msgstr "Gespeicherte Protokolle" -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Packt alle gespeicherten Protokolle in eine ZIP-Datei." msgid "Profiles" @@ -19950,7 +19950,7 @@ msgstr "Druckertyp nicht gefunden, bitte manuell auswählen." msgid "Authorizing..." msgstr "Autorisierung..." -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Fehler. Kann kein API-Token für die Autorisierung erhalten" msgid "Could not parse server response." diff --git a/localization/i18n/en/OrcaSlicer_en.po b/localization/i18n/en/OrcaSlicer_en.po index eb0a7d774c..0d0d0e2ddb 100644 --- a/localization/i18n/en/OrcaSlicer_en.po +++ b/localization/i18n/en/OrcaSlicer_en.po @@ -5947,10 +5947,10 @@ msgstr "" msgid "Load a model" msgstr "" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "" msgid "Import Configs" @@ -7659,7 +7659,7 @@ msgstr "" msgid "Customized Preset" msgstr "" -msgid "Component name(s) inside step file not in UTF8 format!" +msgid "Component name(s) inside step file not in UTF-8 format!" msgstr "" msgid "Because of unsupported text encoding, garbage characters may appear!" @@ -7681,7 +7681,7 @@ msgstr "" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" msgid "Object too small" @@ -10325,11 +10325,11 @@ msgstr "" msgid "No modifications need to be copied." msgstr "" -msgid "Copy paramters" +msgid "Copy parameters" msgstr "" #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "" #, c-format, boost-format @@ -11870,7 +11870,7 @@ msgstr "" msgid "Other layers" msgstr "" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "" msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." @@ -14671,7 +14671,7 @@ msgstr "" msgid "Reduce infill retraction" msgstr "" -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "" msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -14827,7 +14827,7 @@ msgstr "" #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" @@ -14870,7 +14870,7 @@ msgstr "" msgid "Z-hop height" msgstr "" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "" msgid "Z-hop lower boundary" @@ -18187,17 +18187,17 @@ msgstr "" msgid "Only display the filament names with changes to filament presets." msgstr "" -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "" msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" msgid "Please select at least one printer or filament." @@ -18412,7 +18412,7 @@ msgstr "" msgid "We need information for diagnosing source of the issue. Check wiki page for detailed guide." msgstr "" -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "" msgid "Any additional visual examples like images or screen recordings might be helpful while reporting the issue." @@ -18454,7 +18454,7 @@ msgstr "" msgid "Stored logs" msgstr "" -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "" msgid "Profiles" @@ -18519,7 +18519,7 @@ msgstr "" msgid "Authorizing..." msgstr "" -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "" msgid "Could not parse server response." diff --git a/localization/i18n/es/OrcaSlicer_es.po b/localization/i18n/es/OrcaSlicer_es.po index 23294fddbd..032516c978 100644 --- a/localization/i18n/es/OrcaSlicer_es.po +++ b/localization/i18n/es/OrcaSlicer_es.po @@ -6129,10 +6129,10 @@ msgstr "Importar 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "Cargar un modelo" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "Importar archivo Zip" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Cargar modelos contenidos en un archivo zip" msgid "Import Configs" @@ -7877,8 +7877,8 @@ msgstr "¡Por favor, confirme que el G-Code dentro de los perfiles son seguros p msgid "Customized Preset" msgstr "Perfil Personalizado" -msgid "Component name(s) inside step file not in UTF8 format!" -msgstr "¡El nombre de los componentes dentro del archivo de pasos no tiene formato UTF8!" +msgid "Component name(s) inside step file not in UTF-8 format!" +msgstr "¡El nombre de los componentes dentro del archivo de pasos no tiene formato UTF-8!" msgid "Because of unsupported text encoding, garbage characters may appear!" msgstr "¡El nombre puede mostrar caracteres no válidos!" @@ -7899,10 +7899,10 @@ msgstr "El volumen del objeto es cero" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "El objeto del archivo %s es demasiado pequeño, tal vez en metros o pulgadas.\n" -" ¿Quiere escalar a milímetros?" +"¿Quiere escalar a milímetros?" msgid "Object too small" msgstr "Objeto demasiado pequeño" @@ -10670,11 +10670,11 @@ msgstr "%s: %s" msgid "No modifications need to be copied." msgstr "No hay modificaciones que copiar." -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Copiar parámetros" #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "Modificar parámetros de %s" #, c-format, boost-format @@ -12267,8 +12267,8 @@ msgstr "mm o %" msgid "Other layers" msgstr "Otras capas" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." -msgstr "Temperatura de la cama para las capas, excepto la inicial. Un valor de 0 significa que el filamento no es compatible con la Cama Fría SuperTack." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgstr "Esta es la temperatura de la cama para las capas excepto la inicial. Un valor de 0 significa que el filamento no es compatible con la Cama Fría SuperTack." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "Esta es la temperatura de la cama para las capas excepto la inicial. Un valor de 0 significa que el filamento no admite la impresión en la Cama Fría." @@ -15470,7 +15470,7 @@ msgstr "Los puntos de inicio y fin, desde la zona de corte al cubo de basura." msgid "Reduce infill retraction" msgstr "Reducir la retracción del relleno" -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "Desactiva la retracción cuando el desplazamiento se realiza en su totalidad dentro de un área de relleno, donde los artefactos causados por un rezumado no son visibles. Puede reducir el número de retracciones y por ende el tiempo total de retracción al imprimir modelos complejos, reduciendo el tiempo total de impresión. Sin embargo, puede que las operaciones de laminado y de generación del archivo G-Code sean más lentas." msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -15635,7 +15635,7 @@ msgstr "Cantidad de retracción después de la limpieza" #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "La longitud de la retracción rápida después de la limpieza, relativa a la longitud de retracción.\n" @@ -15682,7 +15682,7 @@ msgstr "Cuando se activa la retracción antes de un cambio de herramienta, el fi msgid "Z-hop height" msgstr "Altura de Salto en Z" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "Cada vez que se realiza una retracción, la boquilla se levanta un poco para crear un pequeño margen entre la boquilla y la impresión. Esto evita que la boquilla golpee la pieza cuando se desplaza. El uso de la línea espiral para levantar z puede evitar la aparición de hilos." msgid "Z-hop lower boundary" @@ -17423,7 +17423,7 @@ msgid "Current Z-hop" msgstr "Z-Hop actual" msgid "Contains Z-hop present at the beginning of the custom G-code block." -msgstr "Contiene el z-hop presente al principio del bloque de G-Code personalizado." +msgstr "Contiene el Z-hop presente al principio del bloque de G-Code personalizado." msgid "Position of the extruder at the beginning of the custom G-code block. If the custom G-code travels somewhere else, it should write to this variable so OrcaSlicer knows where it travels from when it gets control back." msgstr "Posición del extrusor al comienzo del bloque de G-Code personalizado. Si el G-Code personalizado viaja a otro lugar, debe escribir en esta variable para que OrcaSlicer sepa desde dónde viaja cuando recupere el control." @@ -19233,17 +19233,17 @@ msgstr "Mostrar sólo los nombres de impresora con cambios en los perfiles de im msgid "Only display the filament names with changes to filament presets." msgstr "Mostrar sólo los nombres de impresora con cambios en los perfiles de filamento." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "Sólo se mostrarán los nombres de impresoras con perfiles de impresora de usuario, y cada perfil que elija se exportará como un archivo zip." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "Sólo se mostrarán los nombres de filamento con perfiles de filamento de usuario, y todos los perfiles de filamento de usuario de cada nombre de filamento que seleccione se exportarán como un archivo zip." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Sólo se mostrarán los nombres de impresoras con perfiles de procesos modificados, \n" "y todos los perfiles de procesos de usuario de cada nombre de impresora que seleccione se exportarán como un archivo zip." @@ -19472,7 +19472,7 @@ msgstr "Copiar información del sistema al portapapeles" msgid "We need information for diagnosing source of the issue. Check wiki page for detailed guide." msgstr "Necesitamos información para diagnosticar el origen del problema. Consulta la página wiki para una guía detallada." -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "El botón Empaquetar recopila el archivo del proyecto y los registros de la sesión actual en un archivo zip." msgid "Any additional visual examples like images or screen recordings might be helpful while reporting the issue." @@ -19514,7 +19514,7 @@ msgstr "Nivel de registro" msgid "Stored logs" msgstr "Registros almacenados" -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Empaqueta todos los registros almacenados en un archivo zip." msgid "Profiles" @@ -19581,7 +19581,7 @@ msgstr "No se ha encontrado el tipo de impresora; selecciónelo manualmente." msgid "Authorizing..." msgstr "Autorizando..." -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Error. No se puede obtener el token de la API para la autorización" msgid "Could not parse server response." @@ -21042,7 +21042,7 @@ msgstr "" #~ msgid "Select Filament && Hotends" #~ msgstr "Seleccionar Filamento && Hotends" -#~ msgid "External spools is not supported since Filament Track Switch has been installed. If you want to use external spool, please uninstall it." +#~ msgid "External spools are not supported since Filament Track Switch has been installed. If you want to use external spool, please uninstall it." #~ msgstr "Los carretes externos no son compatibles porque se ha instalado el Filament Track Switch. Si desea utilizar un carrete externo, desinstálelo." #, c-format, boost-format diff --git a/localization/i18n/eu/OrcaSlicer_eu.po b/localization/i18n/eu/OrcaSlicer_eu.po index a5a49e8325..26185f6514 100644 --- a/localization/i18n/eu/OrcaSlicer_eu.po +++ b/localization/i18n/eu/OrcaSlicer_eu.po @@ -3,7 +3,6 @@ # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # -#, fuzzy msgid "" msgstr "" "Project-Id-Version: \n" @@ -6174,10 +6173,10 @@ msgstr "Inportatu 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "Modeloa kargatu" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "Inportatu ZIP fitxategia" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Kargatu ZIP fitxategi baten barnean dauden modeloak" msgid "Import Configs" @@ -7945,7 +7944,7 @@ msgstr "Berretsi aurrezarpen hauetako G-codea segurua dela, makinari kalterik ez msgid "Customized Preset" msgstr "Aurrezarpen pertsonalizatua" -msgid "Component name(s) inside step file not in UTF8 format!" +msgid "Component name(s) inside step file not in UTF-8 format!" msgstr "STEP fitxategiko osagai-izena(k) ez dago/daude UTF-8 formatuan!" msgid "Because of unsupported text encoding, garbage characters may appear!" @@ -7967,10 +7966,10 @@ msgstr "Objektuaren bolumena zero da" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "%s fitxategiko objektua txikiegia da, eta baliteke metrotan edo hazbetetan egotea.\n" -" Milimetroetara eskalatu nahi duzu?" +"Milimetroetara eskalatu nahi duzu?" msgid "Object too small" msgstr "Objektua txikiegia da" @@ -10765,11 +10764,11 @@ msgstr "%s: %s" msgid "No modifications need to be copied." msgstr "Ez dago kopiatu beharreko aldaketarik." -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Kopiatu parametroak" #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "Aldatu %s-(r)en parametroak" #, c-format, boost-format @@ -12379,8 +12378,8 @@ msgstr "mm edo %" msgid "Other layers" msgstr "Beste geruzak" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." -msgstr "Hasierakoa ez den geruzetarako ohearen tenperatura. 0 balioak filamentuak SuperTack Plaka hotzaren gainean inprimatzea ez duela onartzen esan nahi du." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgstr "Hau da lehenengoa ez den geruzetarako ohearen tenperatura. 0 balioak filamentuak SuperTack Plaka hotzaren gainean inprimatzea ez duela onartzen esan nahi du." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "Hau da lehenengoa ez den geruzetarako ohearen tenperatura. 0 balioak filamentuak Plaka hotzaren gainean inprimatzea ez duela onartzen esan nahi du." @@ -15606,8 +15605,8 @@ msgstr "Mozteko eremutik hondakin-ontzira doazen hasierako eta amaierako puntuak msgid "Reduce infill retraction" msgstr "Murriztu betegarriaren atzera-egitea" -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." -msgstr "Ez egin atzera-egiterik mugimendua guztiz betegarriaren eremuan dagoenean. Horrek esan nahi du jarioa ez dela ikusiko. Honek modelo konplexuetan atzera-egite kopurua murriztu eta inprimatze-denbora aurreztu dezake, baina xerraketa eta G-codearen sorrera motelduko ditu. Kontuan izan z-hop mugimendua ez dela egiten atzera-egitea saihesten den eremuetan." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." +msgstr "Ez egin atzera-egiterik mugimendua guztiz betegarriaren eremuan dagoenean. Horrek esan nahi du jarioa ez dela ikusiko. Honek modelo konplexuetan atzera-egite kopurua murriztu eta inprimatze-denbora aurreztu dezake, baina xerraketa eta G-codearen sorrera motelduko ditu. Kontuan izan Z-hop mugimendua ez dela egiten atzera-egitea saihesten den eremuetan." msgid "This option will drop the temperature of the inactive extruders to prevent oozing." msgstr "Aukera honek aktibo ez dauden estrusoreen tenperatura jaitsiko du, jarioa saihesteko." @@ -15771,7 +15770,7 @@ msgstr "Garbitu ondorengo atzera-egite kantitatea" #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "Garbiketa-mugimenduaren ondorengo atzera-egite azkarraren luzera, atzera-egitearen luzerari dagokionez.\n" @@ -15818,7 +15817,7 @@ msgstr "Erreminta aldatu aurretik atzera-egitea abiarazten denean, filamentua ze msgid "Z-hop height" msgstr "Z jauziaren altuera" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "Atzera-egite bakoitzean pita apur bat altxatzen da pitaren eta inprimaketaren artean tartea sortzeko. Horrela, mugimenduetan pitak pieza jotzea saihesten da. Z altxatzeko espiral-lerroak erabiltzeak hariak sortzea murriztu dezake." msgid "Z-hop lower boundary" @@ -19379,19 +19378,19 @@ msgstr "Inprimagailuaren, filamentuen edo prozesuen aurrezarpenetan aldaketak di msgid "Only display the filament names with changes to filament presets." msgstr "Bistaratu soilik filamentu-aurrezarpenetan aldaketak dituzten filamentu-izenak." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "Erabiltzailearen inprimagailu-aurrezarpenak dituzten inprimagailu-izenak soilik bistaratuko dira, eta hautatzen duzun aurrezarpen bakoitza zip gisa esportatuko da." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Erabiltzailearen filamentu-aurrezarpenak dituzten filamentu-izenak soilik bistaratuko dira, \n" "eta hautatzen duzun filamentu-izen bakoitzeko erabiltzailearen filamentu-aurrezarpen guztiak zip gisa esportatuko dira." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Prozesu-aurrezarpen aldatuak dituzten inprimagailu-izenak soilik bistaratuko dira, \n" "eta hautatzen duzun inprimagailu-izen bakoitzeko erabiltzailearen prozesu-aurrezarpen guztiak zip gisa esportatuko dira." @@ -19620,7 +19619,7 @@ msgstr "Kopiatu sistemaren informazioa arbelera" msgid "We need information for diagnosing source of the issue. Check wiki page for detailed guide." msgstr "Arazoaren jatorria diagnostikatzeko informazioa behar dugu. Begiratu wiki-orria gida xehatua ikusteko." -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "Paketatu botoiak proiektu-fitxategia eta uneko saioko erregistroak ZIP fitxategi batean biltzen ditu." msgid "Any additional visual examples like images or screen recordings might be helpful while reporting the issue." @@ -19662,7 +19661,7 @@ msgstr "Erregistro-maila" msgid "Stored logs" msgstr "Gordetako erregistroak" -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Gordetako erregistro guztiak ZIP fitxategi batean paketatzen ditu." msgid "Profiles" @@ -19729,7 +19728,7 @@ msgstr "Ez da inprimagailu mota aurkitu; hautatu eskuz." msgid "Authorizing..." msgstr "Baimena ematen..." -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Errorea. Ezin da baimenerako API tokena lortu" msgid "Could not parse server response." @@ -22259,20 +22258,12 @@ msgstr "" #~ msgid "The 3mf has the following customized filament or printer presets:" #~ msgstr "3mf-ak pertsonalizatutako filamentuen edo inprimagailuaren aurrezarpen hauek dauzka:" -#~ msgid "Name of components inside step file is not UTF8 format!" -#~ msgstr "Step fitxategiko osagaien izena ez dago UTF8 formatuan!" +#~ msgid "Name of components inside step file is not UTF-8 format!" +#~ msgstr "Step fitxategiko osagaien izena ez dago UTF-8 formatuan!" #~ msgid "The name may show garbage characters!" #~ msgstr "Izenak karaktere ulergaitzak erakuts ditzake!" -#, c-format, boost-format -#~ msgid "" -#~ "The object from file %s is too small, and maybe in meters or inches.\n" -#~ " Do you want to scale to millimeters?" -#~ msgstr "" -#~ "%s fitxategiko objektua txikiegia da, eta baliteke metroetan edo hazbetetan egotea.\n" -#~ " Milimetrotara eskalatu nahi duzu?" - #~ msgid "" #~ "This file contains several objects positioned at multiple heights.\n" #~ "Instead of considering them as multiple objects, should \n" @@ -23123,24 +23114,6 @@ msgstr "" #~ msgid "Maximum detour distance for avoiding crossing wall. Don't detour if the detour distance is larger than this value. Detour length could be specified either as an absolute value or as percentage (for example 50%) of a direct travel path. Zero to disable." #~ msgstr "Hormak gurutzatzea saihesteko gehieneko desbideratze-distantzia. Ez desbideratu distantzia balio hau baino handiagoa bada. Desbideratze-luzera balio absolutu gisa edo lekualdatze-ibilbide zuzenaren ehuneko gisa zehaztu daiteke (adibidez, 50%). Zero, desgaitzeko." -#~ msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate." -#~ msgstr "Ohearen tenperatura hasierakoa ez diren geruzetarako. 0 balioak esan nahi du filamentuak ez duela plaka hotzean inprimatzea onartzen." - -#~ msgid "°C" -#~ msgstr "°C" - -#~ msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Textured Cool Plate." -#~ msgstr "Ohearen tenperatura hasierakoa ez diren geruzetarako. 0 balioak esan nahi du filamentuak ez duela testuradun plaka hotzean inprimatzea onartzen." - -#~ msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Engineering Plate." -#~ msgstr "Ohearen tenperatura hasierakoa ez diren geruzetarako. 0 balioak esan nahi du filamentuak ez duela ingeniaritza-plakan inprimatzea onartzen." - -#~ msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the High Temp Plate." -#~ msgstr "Ohearen tenperatura hasierakoa ez diren geruzetarako. 0 balioak esan nahi du filamentuak ez duela tenperatura altuko plakan inprimatzea onartzen." - -#~ msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Textured PEI Plate." -#~ msgstr "Ohearen tenperatura hasierakoa ez diren geruzetarako. 0 balioak esan nahi du filamentuak ez duela testuradun PEI plakan inprimatzea onartzen." - #~ msgid "Initial layer" #~ msgstr "Hasierako geruza" diff --git a/localization/i18n/fr/OrcaSlicer_fr.po b/localization/i18n/fr/OrcaSlicer_fr.po index 65589bc5ff..28a2e27a01 100644 --- a/localization/i18n/fr/OrcaSlicer_fr.po +++ b/localization/i18n/fr/OrcaSlicer_fr.po @@ -6221,10 +6221,10 @@ msgstr "Importer des fichiers 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "Charger un modèle" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "Importer une archive Zip" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Charger les modèles contenus dans une archive zip" msgid "Import Configs" @@ -8000,7 +8000,7 @@ msgstr "Veuillez vous assurer que les G-codes de ces préréglages sont sûrs af msgid "Customized Preset" msgstr "Préréglage personnalisé" -msgid "Component name(s) inside step file not in UTF8 format!" +msgid "Component name(s) inside step file not in UTF-8 format!" msgstr "Le nom des composants dans le fichier STEP n'est pas au format UTF-8 !" msgid "Because of unsupported text encoding, garbage characters may appear!" @@ -8022,10 +8022,10 @@ msgstr "Le volume de l'objet est nul" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "L’objet du fichier %s est trop petit, et est peut-être en mètres ou en pouces.\n" -" Voulez-vous le mettre à l’échelle en millimètres ?" +"Voulez-vous le mettre à l’échelle en millimètres ?" msgid "Object too small" msgstr "Objet trop petit" @@ -10854,11 +10854,11 @@ msgstr "%s : %s" msgid "No modifications need to be copied." msgstr "Aucune modification à copier." -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Copier les paramètres" #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "Modifier les paramètres de %s" #, c-format, boost-format @@ -12475,21 +12475,27 @@ msgstr "mm ou %" msgid "Other layers" msgstr "Autres couches" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +#, fuzzy +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "Température du plateau pour les couches sauf la première. Une valeur de 0 signifie que le filament ne prend pas en charge l'impression sur la Cool Plate SuperTack." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "Il s'agit de la température du plateau pour toutes les couches à l'exception de la première. Une valeur à 0 signifie que ce filament ne peut pas être imprimé sur la plaque \"Cool plate\"." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured Cool Plate." msgstr "Température du plateau pour les couches à l’exception de la couche initiale. La valeur 0 signifie que le filament ne peut pas être imprimé sur la plaque Cool Plate texturée." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Engineering Plate." msgstr "Il s'agit de la température du plateau pour toutes les couches à l'exception de la première. Une valeur à 0 signifie que ce filament ne peut pas être imprimé sur la plaque Engineering." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the High Temp Plate." msgstr "Il s'agit de la température du plateau pour toutes les couches à l'exception de la première. Une valeur à 0 signifie que ce filament ne peut pas être imprimé sur le plateau haute température (\"High Temp plate\")." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured PEI Plate." msgstr "Température du plateau après la première couche. 0 signifie que le filament ne peut pas être imprimé sur la plaque PEI texturée." @@ -15703,7 +15709,7 @@ msgstr "Les points de départ et d'arrivée qui se situent entre la zone de coup msgid "Reduce infill retraction" msgstr "Réduire la rétraction du remplissage" -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "Ne pas effectuer de rétraction lors de déplacement en zone de remplissage car même si l’extrudeur suinte, les coulures ne seraient pas visibles. Cela peut réduire les rétractions pour les modèles complexes et économiser du temps d’impression, mais ralentit la découpe et la génération du G-code" msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -15873,7 +15879,7 @@ msgstr "Quantité de rétraction après essuyage" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "La longueur de la rétraction rapide après l'essuyage, relative à la longueur de rétraction.\n" @@ -15920,7 +15926,7 @@ msgstr "Lorsque la rétraction est déclenchée avant un changement d’outil, l msgid "Z-hop height" msgstr "Hauteur du saut en Z" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "Chaque fois que la rétraction est effectuée, la buse est légèrement soulevée pour créer un espace entre la buse et l'impression. Il empêche la buse de toucher l'impression lors du déplacement. L'utilisation d'une ligne en spirale pour soulever z peut empêcher l'enfilage" msgid "Z-hop lower boundary" @@ -19492,19 +19498,19 @@ msgstr "N’afficher que les noms d’imprimantes avec les modifications apport msgid "Only display the filament names with changes to filament presets." msgstr "N’affichez que les noms des filaments lorsque vous modifiez les préréglages des filaments." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "Seuls les noms d’imprimantes avec des préréglages d’imprimante utilisateur seront affichés, et chaque préréglage que vous choisissez sera exporté sous forme de fichier zip." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Seuls les noms de filaments contenant des préréglages de filaments utilisateur seront affichés, \n" "et tous les préréglages de filament d’utilisateur dans chaque nom de filament que vous sélectionnez seront exportés sous forme de fichier zip." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Seuls les noms d’imprimantes dont les préréglages de traitement ont été modifiés seront affichés, \n" "et tous les préréglages de processus de l’utilisateur dans chaque nom d’imprimante que vous sélectionnez seront exportés sous forme de fichier zip." @@ -19733,7 +19739,7 @@ msgstr "Copier les informations système dans le presse-papiers" msgid "We need information for diagnosing source of the issue. Check wiki page for detailed guide." msgstr "Nous avons besoin d’informations pour diagnostiquer l’origine du problème. Consultez la page wiki pour un guide détaillé." -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "Le bouton Compresser rassemble le fichier de projet et les journaux de la session actuelle dans un fichier ZIP." msgid "Any additional visual examples like images or screen recordings might be helpful while reporting the issue." @@ -19775,7 +19781,7 @@ msgstr "Niveau de journalisation" msgid "Stored logs" msgstr "Journaux stockés" -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Compresse tous les journaux stockés dans un fichier ZIP." msgid "Profiles" @@ -19842,7 +19848,7 @@ msgstr "Type d’imprimante introuvable, veuillez le sélectionner manuellement. msgid "Authorizing..." msgstr "Autorisation en cours…" -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Erreur : impossible d’obtenir le jeton d’API pour l’autorisation" msgid "Could not parse server response." @@ -22159,8 +22165,8 @@ msgstr "" #~ msgid "The 3mf has the following customized filament or printer presets:" #~ msgstr "Le 3mf dispose de filaments personnalisés ou de préréglages d'imprimante :" -#~ msgid "Name of components inside step file is not UTF8 format!" -#~ msgstr "Le nom des composants à l'intérieur du fichier .step n'est pas au format UTF8 !" +#~ msgid "Name of components inside step file is not UTF-8 format!" +#~ msgstr "Le nom des composants à l'intérieur du fichier .step n'est pas au format UTF-8 !" #~ msgid "Should printer/filament/process settings be loaded when opening a .3mf?" #~ msgstr "Les paramètres de l’imprimante/du filament/du processus doivent-ils être chargés lors de l’ouverture d’un fichier .3mf ?" diff --git a/localization/i18n/hu/OrcaSlicer_hu.po b/localization/i18n/hu/OrcaSlicer_hu.po index 9d966bf80a..1dbfe0b1b7 100644 --- a/localization/i18n/hu/OrcaSlicer_hu.po +++ b/localization/i18n/hu/OrcaSlicer_hu.po @@ -6323,10 +6323,10 @@ msgstr "Importálás 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "Modell betöltése" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "Zip archívum importálása" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Zip archívumban található modellek betöltése" msgid "Import Configs" @@ -8115,7 +8115,7 @@ msgstr "Kérlek, győződj meg arról, hogy a beállításokban található G-k msgid "Customized Preset" msgstr "Egyedi beállítás" -msgid "Component name(s) inside step file not in UTF8 format!" +msgid "Component name(s) inside step file not in UTF-8 format!" msgstr "A STEP fájlon belüli komponens neve nem UTF-8 formátumban van!" # AI Translated @@ -8139,10 +8139,10 @@ msgstr "Az objektum térfogata nulla" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "A(z) %s fájlból származó objektum túl kicsi, lehet, hogy méterben vagy hüvelykben lett létrehozva.\n" -" Szeretnéd milliméterre méretezni?" +"Szeretnéd milliméterre méretezni?" msgid "Object too small" msgstr "Objektum túl kicsi" @@ -11030,12 +11030,12 @@ msgid "No modifications need to be copied." msgstr "Nincs másolandó módosítás." # AI Translated -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Paraméterek másolása" # AI Translated #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "A(z) %s paramétereinek módosítása" # AI Translated @@ -12685,7 +12685,7 @@ msgstr "mm vagy %" msgid "Other layers" msgstr "Többi réteg" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "A kezdőréteg utáni asztalhőmérséklet. A 0 azt jelenti, hogy a filament nem nyomtatható a SuperTack hűvös tálcára." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." @@ -15957,7 +15957,7 @@ msgid "Reduce infill retraction" msgstr "Csökkentett visszahúzás kitöltésnél" # AI Translated -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "Nem történik visszahúzás, amikor a fej csak kitöltés felett halad el, mert az itt történő szivárgás egyébként sem látható. Ez az opció lerövidítheti a nyomtatási időt a visszahúzások csökkentésével komplex modelleknél, de egyúttal lassabbá teszi a szeletelést és a G-kód generálást. Vedd figyelembe, hogy a Z-emelés sem történik meg azokon a területeken, ahol a visszahúzás ki van hagyva." msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -16131,7 +16131,7 @@ msgstr "Visszahúzás mértéke törlés után" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "A törlés utáni gyors visszahúzás hossza a visszahúzási hosszhoz viszonyítva.\n" @@ -16178,7 +16178,7 @@ msgstr "Amikor a visszahúzás eszközváltás előtt aktiválódik, a filament msgid "Z-hop height" msgstr "Z-emelés magassága" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "Visszahúzáskor a fúvóka egy kicsit megemelkedik, hogy a fúvóka és a nyomtatott tárgy között rés keletkezzen. Ez megakadályozza, hogy a fúvóka nagyobb mozgás közben a tárgynak ütközzön. A Z tengely emelésekor használt körkörös mozgás megelőzheti a szálazást." msgid "Z-hop lower boundary" @@ -19796,19 +19796,19 @@ msgstr "Csak azok a nyomtatók jelennek meg, amelyeknél változtak a nyomtató- msgid "Only display the filament names with changes to filament presets." msgstr "Csak azok a filamentnevek jelennek meg, ahol változtak a filamentbeállítások." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "Csak azok a nyomtatónevek jelennek meg, amelyekhez tartoznak felhasználói beállítások. A kiválasztott beállítások ZIP fájlként kerülnek exportálásra." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Csak azok a filamentnevek jelennek meg, amelyekhez tartoznak felhasználói filamentbeállítások,\n" "és a kiválasztott filamentnevekhez tartozó összes felhasználói filamentbeállítás ZIP-fájlként lesz exportálva." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Csak azok a nyomtatónevek jelennek meg, amelyekhez módosított folyamatbeállítások tartoznak,\n" "és a kiválasztott nyomtatónevekhez tartozó összes felhasználói folyamatbeállítás ZIP-fájlként lesz exportálva." @@ -20054,7 +20054,7 @@ msgid "We need information for diagnosing source of the issue. Check wiki page f msgstr "Információra van szükségünk a probléma forrásának feltárásához. A részletes útmutatót a wiki oldalon találod." # AI Translated -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "A Csomagolás gomb egy zip fájlba gyűjti a projektfájlt és az aktuális munkamenet naplóit." # AI Translated @@ -20110,7 +20110,7 @@ msgid "Stored logs" msgstr "Tárolt naplók" # AI Translated -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Az összes tárolt naplót egy zip fájlba csomagolja." # AI Translated @@ -20198,7 +20198,7 @@ msgid "Authorizing..." msgstr "Engedélyezés..." # AI Translated -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Hiba. Nem sikerült API-tokent szerezni az engedélyezéshez" # AI Translated diff --git a/localization/i18n/it/OrcaSlicer_it.po b/localization/i18n/it/OrcaSlicer_it.po index 6190d2ab44..f9d31456bf 100644 --- a/localization/i18n/it/OrcaSlicer_it.po +++ b/localization/i18n/it/OrcaSlicer_it.po @@ -6325,10 +6325,10 @@ msgstr "Importa 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "Carica modello" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "Importa archivio Zip" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Carica i modelli contenuti in un archivio zip" msgid "Import Configs" @@ -8119,8 +8119,8 @@ msgstr "Si prega di confermare che i G-code all'interno di questi profili sono s msgid "Customized Preset" msgstr "Profilo personalizzato" -msgid "Component name(s) inside step file not in UTF8 format!" -msgstr "Il nome dei componenti all'interno del file STEP non è in formato UTF8!" +msgid "Component name(s) inside step file not in UTF-8 format!" +msgstr "Il nome dei componenti all'interno del file STEP non è in formato UTF-8!" msgid "Because of unsupported text encoding, garbage characters may appear!" msgstr "A causa di una codifica del testo non supportata, potrebbero apparire caratteri inutili!" @@ -8141,10 +8141,10 @@ msgstr "Il volume dell'oggetto è zero" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "L'oggetto del file %s è troppo piccolo e può essere in metri o pollici.\n" -" Si desidera scalare in millimetri?" +"Si desidera scalare in millimetri?" msgid "Object too small" msgstr "Oggetto troppo piccolo" @@ -11044,12 +11044,12 @@ msgid "No modifications need to be copied." msgstr "Non è necessario copiare alcuna modifica." # AI Translated -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Copia parametri" # AI Translated #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "Modifica i parametri di %s" # AI Translated @@ -12705,8 +12705,8 @@ msgstr "mm o %" msgid "Other layers" msgstr "Altri strati" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." -msgstr "Temperatura del piatto per gli strati diversi dal primo. Un valore di 0 significa che il filamento non supporta la stampa su Cool Plate SuperTack." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgstr "Indica la temperatura del piatto per tutti gli strati eccetto il primo. Un valore di 0 significa che il filamento non supporta la stampa su Cool Plate SuperTack." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "Indica la temperatura del piatto per tutti gli strati eccetto il primo. Un valore pari a 0 indica che il filamento non supporta la stampa su Piatto a bassa temperatura." @@ -15976,7 +15976,7 @@ msgid "Reduce infill retraction" msgstr "Evita retrazione nel riempimento" # AI Translated -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "Non ritrarre quando gli spostamenti si trovano interamente in un'area di riempimento. Ciò significa che il trasudo del materiale non è visibile. Questo può ridurre i tempi di retrazione per i modelli complessi e far risparmiare tempo di stampa, ma rende più lente l'elaborazione e la generazione del G-code. Nota che anche il sollevamento Z non viene eseguito nelle aree in cui la retrazione viene saltata." msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -16150,7 +16150,7 @@ msgstr "Quantità di retrazione dopo la pulizia" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "La lunghezza della retrazione rapida dopo la pulizia, relativa alla lunghezza di retrazione.\n" @@ -16197,7 +16197,7 @@ msgstr "Quando la retrazione viene attivata prima di un cambio testina, il filam msgid "Z-hop height" msgstr "Altezza sollevamento Z" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "Ogni volta che si verifica una retrazione, l'ugello viene sollevato leggermente per creare spazio tra ugello e stampa. Ciò impedisce all'ugello di colpire la stampa negli spostamenti. L'uso di linee a spirale per il sollevamento sull'asse Z può evitare gli sfilacciamenti sulla stampa." msgid "Z-hop lower boundary" @@ -19813,21 +19813,21 @@ msgstr "Vengono visualizzate solo le stampanti con modifiche ai profili di stamp msgid "Only display the filament names with changes to filament presets." msgstr "Nomi dei filamenti con modifiche ai profili di filamento." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "" "Nomi delle stampanti con profili creati dell'utente.\n" "Tutti i profili selezionati saranno esportati come file zip." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Nomi dei filamenti con profili creati dell'utente.\n" "Tutti i profili selezionati saranno esportati come file zip." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Nomi delle stampanti con profili di processo modificati.\n" "Tutti i profili selezionati saranno esportati come file zip." @@ -20072,7 +20072,7 @@ msgid "We need information for diagnosing source of the issue. Check wiki page f msgstr "Abbiamo bisogno di informazioni per diagnosticare l'origine del problema. Consulta la pagina wiki per una guida dettagliata." # AI Translated -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "Il pulsante Comprimi raccoglie il file di progetto e i log della sessione corrente in un file zip." # AI Translated @@ -20128,7 +20128,7 @@ msgid "Stored logs" msgstr "Log memorizzati" # AI Translated -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Comprime tutti i log memorizzati in un file zip." # AI Translated @@ -20216,7 +20216,7 @@ msgid "Authorizing..." msgstr "Autorizzazione in corso..." # AI Translated -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Errore. Impossibile ottenere il token API per l'autorizzazione" # AI Translated diff --git a/localization/i18n/ja/OrcaSlicer_ja.po b/localization/i18n/ja/OrcaSlicer_ja.po index d67a39463d..9c819dd7c1 100644 --- a/localization/i18n/ja/OrcaSlicer_ja.po +++ b/localization/i18n/ja/OrcaSlicer_ja.po @@ -6334,10 +6334,10 @@ msgstr "3MF/STL/STEP/SVG/OBJ/AMFをインポート" msgid "Load a model" msgstr "モデルを読み込む" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "ZIPアーカイブをインポート" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "ZIPアーカイブ内のモデルをロード" msgid "Import Configs" @@ -8133,8 +8133,8 @@ msgstr "これらのプリセット内のG-codeがマシンに損傷を与えな msgid "Customized Preset" msgstr "カスタマイズされたプリセット" -msgid "Component name(s) inside step file not in UTF8 format!" -msgstr "ファイルのエンコーディング方式はUTF8形式ではありません" +msgid "Component name(s) inside step file not in UTF-8 format!" +msgstr "ファイルのエンコーディング方式はUTF-8形式ではありません" msgid "Because of unsupported text encoding, garbage characters may appear!" msgstr "文字化けがあるようです、ご確認ください" @@ -8155,7 +8155,7 @@ msgstr "オブジェクトの体積が0です" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "ファイル %s 中のオブジェクトが小さいすぎます、ファイルの単位をご確認ください。\n" "mm単位に変換しますか?" @@ -11068,12 +11068,12 @@ msgid "No modifications need to be copied." msgstr "コピーが必要な変更はありません。" # AI Translated -msgid "Copy paramters" +msgid "Copy parameters" msgstr "パラメータをコピー" # AI Translated #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "%sのパラメータを変更" # AI Translated @@ -12756,23 +12756,27 @@ msgstr "mm 或は %" msgid "Other layers" msgstr "他の層" -# AI Translated -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +#, fuzzy +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "1層目を除く各層のベッド温度です。0の場合、そのフィラメントはCool Plate SuperTackでの印刷に対応していません。" +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "ベッドの温度です(1層目以外)。値が0の場合、フィラメントが常温プレートで使用できないという意味です。" -# AI Translated +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured Cool Plate." msgstr "1層目を除く各層のベッド温度です。0の場合、そのフィラメントはTextured Cool Plateでの印刷に対応していません。" +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Engineering Plate." msgstr "ベッドの温度です(1層目以外)。値が0の場合、フィラメントがエンジニアリング プレートで使用できないという意味です。" +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the High Temp Plate." msgstr "ベッドの温度です(1層目以外)。値が0の場合、フィラメントが高温プレートで使用できないという意味です。" +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured PEI Plate." msgstr "1層目以外のベッド温度。値が0の場合、フィラメントがPEIプレートをサポートしない意味をします。" @@ -16238,7 +16242,7 @@ msgstr "カッター領域から廃料排出口までの終始点" msgid "Reduce infill retraction" msgstr "インフィルのリトラクション低減" -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "インフィル領域内の移動はリトラクションしません。造形時間を節約できます。" msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -16423,7 +16427,7 @@ msgstr "ワイプ後のリトラクション量" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "ワイプ後の高速リトラクションの長さで、リトラクション長に対する割合です。\n" @@ -16474,7 +16478,7 @@ msgstr "ツール交換の前にリトラクションが行われるとき、指 msgid "Z-hop height" msgstr "Zホップの高さ" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "リトラクション時に、ノズルを少し上げてから移動します。この動作でモデルとの衝突を回避できます。" # AI Translated @@ -18439,10 +18443,10 @@ msgid "Allow 3MF with newer version to be sliced." msgstr "新しいバージョンの3MFのスライスを許可します。" msgid "Current Z-hop" -msgstr "現在のz-hop" +msgstr "現在のZ-hop" msgid "Contains Z-hop present at the beginning of the custom G-code block." -msgstr "カスタムGコードブロックの先頭に存在するz-hopを含む。" +msgstr "カスタムGコードブロックの先頭に存在するZ-hopを含む。" msgid "Position of the extruder at the beginning of the custom G-code block. If the custom G-code travels somewhere else, it should write to this variable so OrcaSlicer knows where it travels from when it gets control back." msgstr "カスタム G コード ブロックの先頭のエクストルーダーのモーターの位置。 カスタム G コードで動かしたとき、PrusaSlicer が制御を取り戻したときにどこから移動したかを認識できるように、この変数に書き込む必要があります。" @@ -20340,19 +20344,19 @@ msgstr "プリンタ、フィラメント、加工プリセットに変更があ msgid "Only display the filament names with changes to filament presets." msgstr "フィラメントプリセットを変更したフィラメント名のみを表示します。" -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "ユーザープリンタプリセットを持つプリンタ名のみが表示され、選択した各プリセットがZIPとしてエクスポートされます。" msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "ユーザーフィラメントプリセットを含むフィラメント名のみが表示されます、 \n" "選択した各フィラメント名に含まれるすべてのユーザーフィラメントプリセットがZIP形式でエクスポートされます。" msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "変更されたプロセスプリセットがあるプリンタ名のみが表示され、選択した各プリンタ名にあるすべてのユーザープロセスプリセットがZIP形式でエクスポートされます。" msgid "Please select at least one printer or filament." @@ -20596,7 +20600,7 @@ msgid "We need information for diagnosing source of the issue. Check wiki page f msgstr "問題の原因を特定するために情報が必要です。詳しい手順はWikiページをご覧ください。" # AI Translated -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "「パック」ボタンは、現在のセッションのプロジェクトファイルとログをzipファイルにまとめます。" # AI Translated @@ -20652,7 +20656,7 @@ msgid "Stored logs" msgstr "保存されたログ" # AI Translated -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "保存されたすべてのログをzipファイルにまとめます。" # AI Translated @@ -20740,7 +20744,7 @@ msgid "Authorizing..." msgstr "認証中..." # AI Translated -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "エラー。認証用のAPIトークンを取得できません" # AI Translated diff --git a/localization/i18n/ko/OrcaSlicer_ko.po b/localization/i18n/ko/OrcaSlicer_ko.po index e8dfca968f..61d785ef2e 100644 --- a/localization/i18n/ko/OrcaSlicer_ko.po +++ b/localization/i18n/ko/OrcaSlicer_ko.po @@ -6348,10 +6348,10 @@ msgstr "3MF/STL/STEP/SVG/OBJ/AMF 가져오기" msgid "Load a model" msgstr "모델 불러오기" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "ZIP 압축파일 가져오기" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "ZIP 압축파일에 포함된 모델 로드" msgid "Import Configs" @@ -8152,8 +8152,8 @@ msgid "Customized Preset" msgstr "사용자 정의 프리셋" # AI Translated -msgid "Component name(s) inside step file not in UTF8 format!" -msgstr "STEP 파일 내부의 구성 요소 이름이 UTF8 형식이 아닙니다!" +msgid "Component name(s) inside step file not in UTF-8 format!" +msgstr "STEP 파일 내부의 구성 요소 이름이 UTF-8 형식이 아닙니다!" # AI Translated msgid "Because of unsupported text encoding, garbage characters may appear!" @@ -8175,7 +8175,7 @@ msgstr "물체의 부피는 0입니다" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "%s 파일의 객체가 너무 작습니다. 단위가 미터나 인치일 수 있습니다.\n" " mm 단위로 확장하시겠습니까?" @@ -11188,12 +11188,12 @@ msgid "No modifications need to be copied." msgstr "복사할 변경 사항이 없습니다." # AI Translated -msgid "Copy paramters" +msgid "Copy parameters" msgstr "매개변수 복사" # AI Translated #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "%s의 매개변수 수정" # AI Translated @@ -12889,22 +12889,27 @@ msgstr "mm 또는 %" msgid "Other layers" msgstr "다른 레이어" -# AI Translated -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +#, fuzzy +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "초기 레이어를 제외한 레이어의 베드 온도입니다. 값이 0이면 해당 필라멘트가 쿨 플레이트 슈퍼택에서의 출력을 지원하지 않음을 의미합니다." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "초기 레이어를 제외한 레이어의 베드 온도. 값 0은 필라멘트가 쿨 플레이트 출력을 지원하지 않음을 의미합니다." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured Cool Plate." msgstr "초기 레이어를 제외한 레이어의 베드 온도입니다. 값 0은 필라멘트가 텍스처드 쿨 플레이트에서 출력를 지원하지 않음을 의미합니다." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Engineering Plate." msgstr "초기 레이어를 제외한 레이어의 베드 온도. 값 0은 필라멘트가 엔지니어링 플레이트 출력을 지원하지 않음을 의미합니다." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the High Temp Plate." msgstr "초기 레이어를 제외한 레이어의 베드 온도. 값 0은 필라멘트가 고온 플레이트 출력을 지원하지 않음을 의미합니다." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured PEI Plate." msgstr "초기 레이어를 제외한 레이어의 베드 온도. 값 0은 필라멘트가 텍스처 PEI 플레이트 출력을 지원하지 않음을 의미합니다." @@ -16276,7 +16281,7 @@ msgid "Reduce infill retraction" msgstr "채우기 후퇴 감소" # AI Translated -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "이동 경로가 완전히 채우기 영역 안에 있으면 후퇴하지 않습니다. 흘러내림이 보이지 않기 때문입니다. 복잡한 모델에서 후퇴 횟수를 줄여 출력 시간을 절약할 수 있지만 슬라이싱과 G-code 생성 속도는 느려집니다. 후퇴를 건너뛴 영역에서는 Z 올리기도 수행되지 않습니다." msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -16453,7 +16458,7 @@ msgstr "노즐 청소 후 후퇴량" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "노즐 청소 후 빠른 후퇴의 길이로, 후퇴 길이를 기준으로 합니다.\n" @@ -16500,7 +16505,7 @@ msgstr "툴 체인지 전에 후퇴가 실행되면 지정한 양만큼 필라 msgid "Z-hop height" msgstr "Z올리기 높이" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "후퇴가 완료될 때마다 노즐이 약간 올라가서 노즐과 출력물 사이에 간격이 생깁니다. 이동 시 노즐이 출력물에 닿는 것을 방지합니다. 나선형 선을 사용하여 z를 들어 올리면 스트링 현상을 방지할 수 있습니다" msgid "Z-hop lower boundary" @@ -20213,19 +20218,19 @@ msgstr "프린터, 필라멘트 및 프로세스 사전 설정이 변경된 경 msgid "Only display the filament names with changes to filament presets." msgstr "필라멘트 사전 설정이 변경된 경우에만 필라멘트 이름을 표시합니다." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "사용자 프린터 사전 설정이 있는 프린터 이름만 표시되며, 선택한 각 사전 설정은 zip으로 내보내집니다." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "사용자 필라멘트 사전 설정이 있는 필라멘트 이름만 표시됩니다.\n" "선택한 각 필라멘트 이름의 모든 사용자 필라멘트 사전 설정은 zip으로 내보내집니다." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "프로세스 사전 설정이 변경된 프린터 이름만 표시됩니다.\n" "선택한 각 프린터 이름의 모든 사용자 프로세스 사전 설정은 zip으로 내보내집니다." @@ -20469,7 +20474,7 @@ msgid "We need information for diagnosing source of the issue. Check wiki page f msgstr "문제의 원인을 진단하려면 정보가 필요합니다. 자세한 안내는 위키 페이지를 확인하십시오." # AI Translated -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "패키지 버튼은 현재 세션의 프로젝트 파일과 로그를 zip 파일로 모읍니다." # AI Translated @@ -20525,7 +20530,7 @@ msgid "Stored logs" msgstr "저장된 로그" # AI Translated -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "저장된 모든 로그를 zip 파일로 묶습니다." # AI Translated @@ -20613,7 +20618,7 @@ msgid "Authorizing..." msgstr "인증 중..." # AI Translated -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "오류. 인증용 API 토큰을 가져올 수 없습니다" # AI Translated diff --git a/localization/i18n/lt/OrcaSlicer_lt.po b/localization/i18n/lt/OrcaSlicer_lt.po index 8fd32bdd26..e1ce2f18b2 100644 --- a/localization/i18n/lt/OrcaSlicer_lt.po +++ b/localization/i18n/lt/OrcaSlicer_lt.po @@ -3,7 +3,6 @@ # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # -#, fuzzy msgid "" msgstr "" "Project-Id-Version: \n" @@ -6311,10 +6310,10 @@ msgstr "Importuoti 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "Įkelti modelį" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "Importuoti Zip archyvą" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Įkelti modelius iš ZIP archyvo" msgid "Import Configs" @@ -8110,7 +8109,7 @@ msgstr "Patvirtinkite, kad šiuose profiliuose esantis G-kodas yra saugus, kad i msgid "Customized Preset" msgstr "Pritaikytas profilis" -msgid "Component name(s) inside step file not in UTF8 format!" +msgid "Component name(s) inside step file not in UTF-8 format!" msgstr "Komponentų pavadinimai STEP faile nėra UTF-8 formato!" msgid "Because of unsupported text encoding, garbage characters may appear!" @@ -8132,7 +8131,7 @@ msgstr "Objekto tūris nulinis" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "Objektas iš failo „%s“ yra per mažas ir galimai nurodytas metrais arba coliais.\n" "Ar norite mastelį pakeisti į milimetrus?" @@ -10981,11 +10980,11 @@ msgstr "%s: %s" msgid "No modifications need to be copied." msgstr "Nereikia kopijuoti jokių modifikacijų" -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Kopijuoti parametrus" #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "Modifikuoti %s parametrus" #, c-format, boost-format @@ -12609,7 +12608,7 @@ msgstr "mm arba %" msgid "Other layers" msgstr "Kiti sluoksniai" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "Pagrindo temperatūra visiems sluoksniams, išskyrus pirmąjį. Reikšmė 0 reiškia, kad ši gija nepritaikyta spausdinti ant „Cool Plate SuperTack“ pagrindo." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." @@ -15839,7 +15838,7 @@ msgstr "Pradžios ir pabaigos taškai, esantys tarp gijos kirpimo zonos ir atlie msgid "Reduce infill retraction" msgstr "Sumažinti užpildo įtraukimą (Retraction)" -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "Neatlikti gijos įtraukimo, kai tuščioji eiga vyksta tik užpildo zonoje. Tokiu atveju gijos varvėjimas (oozing) išorėje bus nematomas. Tai leidžia sumažinti įtraukimų skaičių sudėtingiems modeliams ir sutaupyti spausdinimo laiko, tačiau sulėtina sluoksniavimą bei G-kodo (G-code) generavimą. Pastaba: zonose, kuriose įtraukimas praleidžiamas, „Z-hop“ judesys taip pat neatliekamas." msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -16005,7 +16004,7 @@ msgstr "Atitraukimo kiekis po nubraukimo" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "Greito atitraukimo ilgis po nubraukimo, atsižvelgiant į atitraukimo ilgį.\n" @@ -16052,7 +16051,7 @@ msgstr "Kai atitraukimas suaktyvinamas prieš įrankio keitimą, gija atitraukia msgid "Z-hop height" msgstr "„Z-hop“ (pakėlimo) aukštis" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "Kaskart atliekant atitraukimą, purkštukas šiek tiek pakeliamas, kad tarp jo ir spaudinio atsirastų tarpas. Tai apsaugo nuo purkštuko užkliudymo už spaudinio judėjimo metu. „Spiralinių“ linijų naudojimas Z ašies kėlimui gali padėti išvengti „tįstančių siūlų“ (angl. \"stringing\")." msgid "Z-hop lower boundary" @@ -19649,19 +19648,19 @@ msgstr "Rodomi tik tie spausdintuvai, kurių spausdintuvo, kaitinamojo siūlo ir msgid "Only display the filament names with changes to filament presets." msgstr "Rodyti tik tuos gijų pavadinimus, kurių gijos profiliai buvo pakeisti." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "Bus rodomi tik tie spausdintuvų pavadinimai, kurie turi naudotojo sukurtų profilių, o kiekvienas pasirinktas profilis bus eksportuotas kaip ZIP failas." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Bus rodomi tik tie gijų pavadinimai, kurie turi naudotojo sukurtų profilių, \n" "o visi pasirinkto pavadinimo naudotojo gijos profiliai bus eksportuoti kaip ZIP failas." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Bus rodomi tik tie spausdintuvų pavadinimai, kurie turi pakeistų proceso profilių, \n" "o visi pasirinkto spausdintuvo naudotojo proceso profiliai bus eksportuoti kaip ZIP failas." @@ -19891,7 +19890,7 @@ msgstr "Kopijuoti sistemos informaciją į iškarpinę" msgid "We need information for diagnosing source of the issue. Check wiki page for detailed guide." msgstr "Mums reikia informacijos problemos šaltiniui diagnozuoti. Išsamų vadovą rasite „Wiki“ puslapyje." -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "Mygtukas „Supakuoti“ (Pack) surenka projekto failą ir dabartinės sesijos žurnalus į ZIP failą." msgid "Any additional visual examples like images or screen recordings might be helpful while reporting the issue." @@ -19933,7 +19932,7 @@ msgstr "Žurnalo lygis" msgid "Stored logs" msgstr "Saugomi žurnalai" -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Supakuoja visus saugomus žurnalus į ZIP failą." msgid "Profiles" @@ -20000,7 +19999,7 @@ msgstr "Spausdintuvo tipas nerastas, pasirinkite rankiniu būdu." msgid "Authorizing..." msgstr "Autorizuojama..." -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Klaida. Nepavyko gauti API žetono (token) autorizacijai" msgid "Could not parse server response." @@ -22206,20 +22205,12 @@ msgstr "" #~ msgid "Please correct them in the param tabs" #~ msgstr "Prašome juos ištaisyti parametrų skirtukuose" -#~ msgid "Name of components inside STEP file is not UTF8 format!" +#~ msgid "Name of components inside STEP file is not UTF-8 format!" #~ msgstr "Komponentų pavadinimai STEP faile nėra UTF-8 formato!" #~ msgid "The name may show garbage characters!" #~ msgstr "Pavadinimas gali rodyti neskaitomus simbolius!" -#, c-format, boost-format -#~ msgid "" -#~ "The object from file %s is too small, and maybe in meters or inches.\n" -#~ " Do you want to scale to millimeters?" -#~ msgstr "" -#~ "Objektas iš failo „%s“ yra per mažas ir galimai nurodytas metrais arba coliais.\n" -#~ "Ar norite mastelį pakeisti į milimetrus?" - #~ msgid "" #~ "This file contains several objects positioned at multiple heights.\n" #~ "Instead of considering them as multiple objects, should \n" @@ -22609,21 +22600,6 @@ msgstr "" #~ msgid "Maximum detour distance for avoiding crossing wall. Don't detour if the detour distance is larger than this value. Detour length could be specified either as an absolute value or as percentage (for example 50%) of a direct travel path. Zero to disable." #~ msgstr "Maksimalus apylankos atstumas sienelių kirtimui išvengti. Apylanka nedaroma, jei jos atstumas viršija šią reikšmę. Apylankos ilgis gali būti nurodomas absoliučia verte arba procentais (pavyzdžiui, 50 %) nuo tiesioginio judėjimo trajektorijos. Įrašius 0 – funkcija išjungiama." -#~ msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate." -#~ msgstr "Pagrindo temperatūra visiems sluoksniams, išskyrus pirmąjį. Reikšmė 0 reiškia, kad ši gija nepritaikyta spausdinti ant šalto pagrindo (Cool Plate)." - -#~ msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Textured Cool Plate." -#~ msgstr "Pagrindo temperatūra visiems sluoksniams, išskyrus pirmąjį. Reikšmė 0 reiškia, kad ši gija nepritaikyta spausdinti ant tekstūruoto šalto pagrindo (Textured Cool Plate)." - -#~ msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Engineering Plate." -#~ msgstr "Pagrindo temperatūra visiems sluoksniams, išskyrus pirmąjį. Reikšmė 0 reiškia, kad ši gija nepritaikyta spausdinti ant inžinerinio pagrindo (Engineering Plate)." - -#~ msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the High Temp Plate." -#~ msgstr "Pagrindo temperatūra visiems sluoksniams, išskyrus pirmąjį. Reikšmė 0 reiškia, kad ši gija nepritaikyta spausdinti ant aukštos temperatūros pagrindo (High Temp Plate)." - -#~ msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Textured PEI Plate." -#~ msgstr "Pagrindo temperatūra visiems sluoksniams, išskyrus pirmąjį. Reikšmė 0 reiškia, kad ši gija nepritaikyta spausdinti ant tekstūruoto PEI pagrindo (Textured PEI Plate)." - #~ msgid "Bed temperature of the first layer. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." #~ msgstr "Pirmojo sluoksnio pagrindo temperatūra. Reikšmė 0 reiškia, kad ši gija nepritaikyta spausdinti ant „Cool Plate SuperTack“ pagrindo." diff --git a/localization/i18n/nl/OrcaSlicer_nl.po b/localization/i18n/nl/OrcaSlicer_nl.po index 96c22fcc8b..4284378cd1 100644 --- a/localization/i18n/nl/OrcaSlicer_nl.po +++ b/localization/i18n/nl/OrcaSlicer_nl.po @@ -6887,11 +6887,11 @@ msgid "Load a model" msgstr "Laad een model" # AI Translated -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "ZIP-archief importeren" # AI Translated -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Laad modellen uit een ZIP-archief" msgid "Import Configs" @@ -8860,8 +8860,8 @@ msgstr "Controleer of de G-codes in deze presets veilig zijn om schade aan de ma msgid "Customized Preset" msgstr "Aangepaste voorinstelling" -msgid "Component name(s) inside step file not in UTF8 format!" -msgstr "Naam van componenten in step-bestand is niet UTF8-formaat!" +msgid "Component name(s) inside step file not in UTF-8 format!" +msgstr "Naam van componenten in step-bestand is niet UTF-8-formaat!" msgid "Because of unsupported text encoding, garbage characters may appear!" msgstr "Vanwege niet-ondersteunde tekstcodering kunnen er onjuiste tekens verschijnen!" @@ -8883,10 +8883,10 @@ msgstr "Het volume van het object is 0" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "Het object uit bestand %s is erg klein, en misschien in meters of inches.\n" -" Wil je schalen naar millimeters?" +"Wil je schalen naar millimeters?" msgid "Object too small" msgstr "He tobject is te klein" @@ -12027,12 +12027,12 @@ msgid "No modifications need to be copied." msgstr "Er hoeven geen wijzigingen te worden gekopieerd." # AI Translated -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Parameters kopiëren" # AI Translated #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "Parameters van %s wijzigen" # AI Translated @@ -13843,23 +13843,27 @@ msgstr "mm of %" msgid "Other layers" msgstr "Andere lagen" -# AI Translated -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +#, fuzzy +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "Bedtemperatuur voor alle lagen behalve de eerste. Een waarde van 0 betekent dat het filament printen op de Cool Plate SuperTack niet ondersteunt." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "Dit is de bedtemperatuur voor alle lagen behalve de eerste. Een waarde van 0 betekent dat het filament het afdrukken op de Cool Plate niet ondersteunt." -# AI Translated +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured Cool Plate." msgstr "Dit is de bedtemperatuur voor alle lagen behalve de eerste. Een waarde van 0 betekent dat het filament printen op de Textured Cool Plate niet ondersteunt." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Engineering Plate." msgstr "Dit is de bedtemperatuur voor lagen, behalve voor de eerste. Een waarde van 0 betekent dat het filament afdrukken op de Engineering Plate niet ondersteunt." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the High Temp Plate." msgstr "Dit is de bedtemperatuur voor lagen, behalve voor de eerste. Een waarde van 0 betekent dat het filament printen op de High Temp Plate niet ondersteunt." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured PEI Plate." msgstr "Bedtemperatuur na de eerste laag. 0 betekent dat het filament niet wordt ondersteund op de getextureerde PEI-plaat." @@ -17510,8 +17514,8 @@ msgid "Reduce infill retraction" msgstr "Reduceer terugtrekken (retraction) bij vulling (infill)" # AI Translated -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." -msgstr "Trek niet terug als de beweging zich volledig in een opvulgebied bevindt. Dat betekent dat het sijpelen niet zichtbaar is. Dit kan de retraction times voor complexe modellen verkorten en printtijd besparen, maar het segmenteren en het genereren van G-codes langzamer maken. Let op: z-hop wordt ook niet uitgevoerd in gebieden waar het terugtrekken wordt overgeslagen." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." +msgstr "Trek niet terug als de beweging zich volledig in een opvulgebied bevindt. Dat betekent dat het sijpelen niet zichtbaar is. Dit kan de retraction times voor complexe modellen verkorten en printtijd besparen, maar het segmenteren en het genereren van G-codes langzamer maken. Let op: Z-hop wordt ook niet uitgevoerd in gebieden waar het terugtrekken wordt overgeslagen." # AI Translated msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -17700,7 +17704,7 @@ msgstr "Terugtrekhoeveelheid na vegen" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "De lengte van de snelle terugtrekking na het vegen, relatief ten opzichte van de terugtreklengte.\n" @@ -17754,7 +17758,7 @@ msgstr "Wanneer het terugtrekken vóór een gereedschapswissel wordt geactiveerd msgid "Z-hop height" msgstr "Z-hop-hoogte" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "Wanneer er een terugtrekking (retraction) is, wordt het mondstuk een beetje opgetild om ruimte te creëren tussen het mondstuk en de print. Dit voorkomt dat het mondstuk de print raakt bij verplaatsen. Het gebruik van spiraallijnen om Z op te tillen kan stringing voorkomen." msgid "Z-hop lower boundary" @@ -19764,7 +19768,7 @@ msgid "Allow 3MF with newer version to be sliced." msgstr "Sta toe dat een 3MF met een nieuwere versie wordt geslicet." msgid "Current Z-hop" -msgstr "Huidige z-hop" +msgstr "Huidige Z-hop" # AI Translated msgid "Contains Z-hop present at the beginning of the custom G-code block." @@ -21801,19 +21805,19 @@ msgstr "Alleen printers met wijzigingen in printer-, filament- en proces presets msgid "Only display the filament names with changes to filament presets." msgstr "Geef alleen de filamentnamen weer met wijzigingen in filament presets." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "Alleen printernamen met gebruikersprinter presets worden weergegeven en elke preset die je kiest, wordt als zip geëxporteerd." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Alleen de filamentnamen met gebruikers presets worden weergegeven, \n" "en alle gebruikers presets in elke filamentnaam die u selecteert, worden geëxporteerd als zip-bestand." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Alleen printernamen met gewijzigde proces presets worden weergegeven, \n" "en alle gebruikersproces presets in elke printernaam die u selecteert, worden als zip geëxporteerd." @@ -22068,7 +22072,7 @@ msgid "We need information for diagnosing source of the issue. Check wiki page f msgstr "We hebben informatie nodig om de oorzaak van het probleem te achterhalen. Raadpleeg de wikipagina voor een uitgebreide handleiding." # AI Translated -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "De knop Inpakken verzamelt het projectbestand en de logboeken van de huidige sessie in een zipbestand." # AI Translated @@ -22124,7 +22128,7 @@ msgid "Stored logs" msgstr "Opgeslagen logboeken" # AI Translated -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Pakt alle opgeslagen logboeken in een zipbestand." # AI Translated @@ -22212,7 +22216,7 @@ msgid "Authorizing..." msgstr "Autoriseren..." # AI Translated -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Fout. Kan geen API-token voor autorisatie ophalen" # AI Translated diff --git a/localization/i18n/pl/OrcaSlicer_pl.po b/localization/i18n/pl/OrcaSlicer_pl.po index 4a21d38a27..cc88aac759 100644 --- a/localization/i18n/pl/OrcaSlicer_pl.po +++ b/localization/i18n/pl/OrcaSlicer_pl.po @@ -6467,10 +6467,10 @@ msgstr "Importuj 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "Wczytaj model" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "Importuj archiwum ZIP" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Wczytaj modele zawarte w archiwum ZIP" msgid "Import Configs" @@ -8309,8 +8309,8 @@ msgstr "Proszę potwierdź, że G-code w tych profilach jest bezpieczny, aby zap msgid "Customized Preset" msgstr "Dostosowany profil" -msgid "Component name(s) inside step file not in UTF8 format!" -msgstr "Nazwa komponentów w pliku step nie jest w formacie UTF8!" +msgid "Component name(s) inside step file not in UTF-8 format!" +msgstr "Nazwa komponentów w pliku step nie jest w formacie UTF-8!" msgid "Because of unsupported text encoding, garbage characters may appear!" msgstr "Nazwa może zawierać nieczytelne znaki!" @@ -8331,10 +8331,10 @@ msgstr "Objętość tego obiektu wynosi zero" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "Obiekt z pliku %s jest zbyt mały i możliwe, że jest określony w metrach lub calach.\n" -" Czy przeskalować na milimetry?" +"Czy przeskalować na milimetry?" msgid "Object too small" msgstr "Zbyt mały obiekt" @@ -11363,12 +11363,12 @@ msgid "No modifications need to be copied." msgstr "Nie ma modyfikacji do skopiowania." # AI Translated -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Kopiuj parametry" # AI Translated #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "Zmodyfikuj parametry %s" # AI Translated @@ -13060,22 +13060,27 @@ msgstr "mm lub %" msgid "Other layers" msgstr "Pozostałe warstwy" -# AI Translated -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +#, fuzzy +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "Temperatura stołu dla warstw poza pierwszą. Wartość 0 oznacza, że filament nie obsługuje druku na Cool Plate SuperTack." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "Temperatura stołu dla warstw poza pierwszą. Wartość 0 oznacza, że filament nie obsługuje drukowania na Cool Plate." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured Cool Plate." msgstr "Temperatura stołu dla warstw, z wyjątkiem pierwszej. Wartość 0 oznacza, że filament nie nadaje się do druku na Textured Cool Plate." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Engineering Plate." msgstr "Temperatura stołu dla warstw poza pierwszą. Wartość 0 oznacza, że filament nie obsługuje drukowania na Engineering Plate." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the High Temp Plate." msgstr "Temperatura stołu dla warstw poza pierwszą. Wartość 0 oznacza, że filament nie obsługuje drukowania na High Temp Plate." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured PEI Plate." msgstr "Temperatura stołu dla warstw poza pierwszą. Wartość 0 oznacza, że filament nie obsługuje drukowania na Textured PEI Plate." @@ -16448,7 +16453,7 @@ msgstr "Punkty początkowe i końcowe, od obszaru cięcia do kanału wyrzutowego msgid "Reduce infill retraction" msgstr "Zmniejszanie retrakcji wypełnienia" -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "Nie wykonuj retrakcji, gdy ruch odbywa się całkowicie w obszarze wypełnienia. Oznacza to, że wyciek nie będzie widoczny. Może to zmniejszyć liczbę retrakcji dla skomplikowanego modelu i zaoszczędzić czas druku, ale spowolnić krojenie i generowanie G-code" msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -16624,7 +16629,7 @@ msgstr "Wartość retrakcji po czyszczeniu" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "Długość szybkiej retrakcji po czyszczeniu, względem długości retrakcji.\n" @@ -16671,7 +16676,7 @@ msgstr "Gdy retrakcja jest wyzwalana przed zmianą narzędzia, filament zostaje msgid "Z-hop height" msgstr "Wysokość Z-hop" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "Zawsze gdy wykonana jest retrakcja, dysza jest nieco podnoszona, aby stworzyć odstęp między dyszą a wydrukiem. Zapobiega to uderzeniu dyszy w wydruk podczas przemieszczania. Użycie linii spiralnej do podniesienia Z może zapobiec powstawaniu strun" msgid "Z-hop lower boundary" @@ -18504,7 +18509,7 @@ msgid "Current Z-hop" msgstr "Bieżący Z-hop" msgid "Contains Z-hop present at the beginning of the custom G-code block." -msgstr "Zawiera z-hop obecny na początku bloku niestandardowego G-code" +msgstr "Zawiera Z-hop obecny na początku bloku niestandardowego G-code" msgid "Position of the extruder at the beginning of the custom G-code block. If the custom G-code travels somewhere else, it should write to this variable so OrcaSlicer knows where it travels from when it gets control back." msgstr "Pozycja ekstrudera na początku bloku niestandardowego G-kodu. Jeśli niestandardowy G-code przemieszcza się gdzieś indziej, powinien zostać zapisany do tej zmiennej, aby OrcaSlicer wiedział, skąd się przemieszcza, gdy odzyska kontrolę." @@ -20394,19 +20399,19 @@ msgstr "Wyświetlane są jedynie drukarki ze zmienionymi profilami drukarki, fil msgid "Only display the filament names with changes to filament presets." msgstr "Wyświetlone są jedynie nazwy filamentów, które zostały zmodyfikowane w ustawieniach." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "Wyświetlane są tylko nazwy drukarek z ustawieniami użytkownika, wybrany zestaw zostanie wyeksportowany jako plik zip." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Na liście widoczne są tylko nazwy filamentów ze zmodyfikowanymi ustawieniami, \n" "a dla każdej wybranej nazwy filamentu zostaną wyeksportowane wszystkie ustawienia jako archiwum zip." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Na liście widoczne są tylko nazwy drukarek ze zmodyfikowanymi ustawieniami procesu, \n" "a dla każdej wybranej nazwy drukarki zostaną wyeksportowane wszystkie \n" @@ -20653,7 +20658,7 @@ msgid "We need information for diagnosing source of the issue. Check wiki page f msgstr "Potrzebujemy informacji do zdiagnozowania źródła problemu. Szczegółowy przewodnik znajdziesz na stronie wiki." # AI Translated -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "Przycisk Spakuj zbiera plik projektu i dzienniki bieżącej sesji do pliku zip." # AI Translated @@ -20709,7 +20714,7 @@ msgid "Stored logs" msgstr "Zapisane dzienniki" # AI Translated -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Pakuje wszystkie zapisane dzienniki do pliku zip." # AI Translated @@ -20797,7 +20802,7 @@ msgid "Authorizing..." msgstr "Autoryzowanie..." # AI Translated -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Błąd. Nie można uzyskać tokenu API do autoryzacji" # AI Translated diff --git a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po index 931d3d510b..5b9b7dcc42 100644 --- a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po +++ b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po @@ -6143,11 +6143,11 @@ msgstr "Importar 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "Carregar um modelo" -msgid "Import Zip Archive" -msgstr "Importar Arquivo Zip" +msgid "Import ZIP Archive" +msgstr "Importar Arquivo ZIP" -msgid "Load models contained within a zip archive" -msgstr "Carregar modelos contidos em um arquivo zip" +msgid "Load models contained within a ZIP archive" +msgstr "Carregar modelos contidos em um arquivo ZIP" msgid "Import Configs" msgstr "Importar Configurações" @@ -7897,7 +7897,7 @@ msgstr "Por favor, confirme se o G-code dentro dessas predefinições é seguro msgid "Customized Preset" msgstr "Predefinição Personalizada" -msgid "Component name(s) inside step file not in UTF8 format!" +msgid "Component name(s) inside step file not in UTF-8 format!" msgstr "Os nomes dos componentes dentro do arquivo STEP não estão no formato UTF-8!" msgid "Because of unsupported text encoding, garbage characters may appear!" @@ -7919,7 +7919,7 @@ msgstr "O volume do objeto é zero" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "O objeto do arquivo %s é muito pequeno, e pode estar em metros ou polegadas.\n" "Deseja redimensioná-lo para milímetros?" @@ -10740,11 +10740,11 @@ msgstr "%s: %s" msgid "No modifications need to be copied." msgstr "Nenhuma modificação precisa ser copiada." -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Copiar parâmetros" #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "Modificar parâmetros de %s" #, c-format, boost-format @@ -12355,7 +12355,7 @@ msgstr "mm ou %" msgid "Other layers" msgstr "Outras camadas" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "Essa é a temperatura da mesa para camadas exceto a inicial. O valor 0 significa que o filamento não suporta a impressão na Placa Fria SuperTack." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." @@ -15252,7 +15252,6 @@ msgstr "Massa da mesa do eixo Y" msgid "The machine bed mass load of Y axis" msgstr "A carga de massa da mesa do equipamento no eixo Y" -# AI Translated msgid "g" msgstr "g" @@ -15565,7 +15564,7 @@ msgstr "Os pontos de início e fim que vão da área do cortador até a calha de msgid "Reduce infill retraction" msgstr "Reduzir retração durante o preenchimento" -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "Não retrair quando o movimento está completamente na área de preenchimento. Isso significa que o vazamento não pode ser visto. Isso pode reduzir o número de retratações para modelos complexos e economizar tempo de impressão, mas torna a geração de fatiamento e G-code mais lenta. Note que o Z-Hop também não é realizado em áreas onde a retração é omitida." msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -15730,7 +15729,7 @@ msgstr "Quantidade de retração depois da limpeza" #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "Este é o comprimento da retração rápida antes de uma limpeza, em relação ao comprimento da retração.\n" @@ -15766,18 +15765,16 @@ msgstr "Retração longa na troca de extrusora" msgid "Retraction distance when extruder change" msgstr "Distância de retração na troca de extrusora" -# AI Translated msgid "Retraction Length (Toolchange)" -msgstr "Comprimento da retração (Troca de ferramenta)" +msgstr "Comprimento da Retração (Troca de ferramenta)" -# AI Translated msgid "When retraction is triggered before changing tool, filament is pulled back by the specified amount (the length is measured on raw filament, before it enters the extruder)." msgstr "Quando a retração é acionada antes da troca de ferramenta, o filamento é puxado de volta na quantidade especificada (o comprimento é medido no filamento bruto, antes de entrar na extrusora)." msgid "Z-hop height" msgstr "Altura de Z-hop" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "Sempre que há uma retração, o bico é levantado um pouco para criar folga entre o bico e a impressão. Isso evita que o bico atinja a impressão ao se mover. Usar linhas em espiral para levantar Z pode evitar stringing." msgid "Z-hop lower boundary" @@ -15867,9 +15864,8 @@ msgstr "Comprimento extra na retração" msgid "When the retraction is compensated after the travel move, the extruder will push this additional amount of filament. This setting is rarely needed." msgstr "Quando a retração é compensada após o movimento de deslocamento, a extrusora empurrará essa quantidade adicional de filamento. Esta configuração é raramente necessária." -# AI Translated msgid "Extra length on restart (Toolchange)" -msgstr "Comprimento extra na retração (Troca de ferramenta)" +msgstr "Comprimento extra no reinício (Troca de ferramenta)" msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament." msgstr "Quando a retração é compensada após a troca de ferramenta, a extrusora empurrará essa quantidade adicional de filamento." @@ -16279,13 +16275,11 @@ msgstr "Troca de ferramenta na torre de purga" msgid "Force the toolhead to travel to the wipe tower before issuing the tool change command (Tx). Only relevant for multi-extruder (multi-toolhead) printers using a Type 2 wipe tower. By default Orca skips the travel on multi-toolhead machines because the firmware handles the head swap, which can result in the Tx command being issued above the printed part. Enable this option if you want the tool change to always be issued above the wipe tower instead." msgstr "Força o cabeçote de impressão a se deslocar até a torre de purga antes de emitir o comando de troca de ferramenta (Tx). Relevante apenas para impressoras com múltiplas extrusoras (múltiplos cabeçotes de impressão) que utilizam uma torre de purga Tipo 2. Por padrão, o Orca ignora o deslocamento em máquinas com múltiplos cabeçotes de impressão, pois o firmware gerencia a troca do cabeçote, o que pode resultar na emissão do comando Tx acima da peça impressa. Habilite esta opção se desejar que a troca de ferramenta seja sempre emitida acima da torre de purga." -# AI Translated msgid "Wait for temperature on wipe tower" msgstr "Aguardar a temperatura na torre de purga" -# AI Translated msgid "Pick up the new tool without waiting for it to reach printing temperature, travel to the wipe tower, and wait for the temperature there, right before purging. Ooze from the heat-up lands on the tower instead of the model, and the travel overlaps with the heating. Only relevant for multi-extruder (multi-toolhead) printers using a Type 2 wipe tower. The firmware or tool change macro must not wait for the temperature itself. When disabled, the temperature wait is issued right after the tool change command." -msgstr "Pega a nova ferramenta sem esperar que ela atinja a temperatura de impressão, desloca-se até a torre de purga e aguarda a temperatura ali, logo antes de purgar. O vazamento causado pelo aquecimento cai na torre em vez do modelo, e o deslocamento acontece durante o aquecimento. Relevante apenas para impressoras multiextrusora (multicabeça) que usam uma torre de purga do tipo 2. O firmware ou a macro de troca de ferramenta não devem aguardar a temperatura por conta própria. Quando desativado, a espera de temperatura é emitida logo após o comando de troca de ferramenta." +msgstr "Pega a nova ferramenta sem esperar que ela atinja a temperatura de impressão, desloca-se até a torre de purga e aguarda a temperatura ali, logo antes de purgar. O vazamento causado pelo aquecimento cai na torre em vez do modelo, e o deslocamento acontece junto com o aquecimento. Relevante apenas para impressoras multiextrusora (multicabeça) que usam uma torre de purga do Tipo 2. O firmware ou a macro de troca de ferramenta não devem aguardar a temperatura por conta própria. Quando desativado, a espera de temperatura é emitida logo após o comando de troca de ferramenta." msgid "No sparse layers (beta)" msgstr "Sem camadas esparsas (beta)" @@ -19315,19 +19309,19 @@ msgstr "Apenas impressoras com alterações nas predefinições de impressora, f msgid "Only display the filament names with changes to filament presets." msgstr "Exibir apenas os nomes dos filamentos com alterações nas predefinições de filamento." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "Apenas os nomes das impressoras com predefinições de impressora do usuário serão exibidos, e cada predefinição escolhida será exportada como um arquivo zip." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Apenas os nomes dos filamentos com predefinições de filamento do usuário serão exibidos, \n" "e todas as predefinições de filamento do usuário em cada nome de filamento selecionadas serão exportadas como um arquivo zip." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Apenas os nomes das impressoras com predefinições de processo alterados serão exibidos, \n" "e todas os predefinições de processo do usuário em cada nome de impressora selecionadas serão exportados como um arquivo zip." @@ -19556,7 +19550,7 @@ msgstr "Copiar informações do sistema para a área de transferência" msgid "We need information for diagnosing source of the issue. Check wiki page for detailed guide." msgstr "Precisamos de informações para diagnosticar a origem do problema. Consulte a página da wiki para obter um guia detalhado." -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "O botão \"Empacotar\" reúne o arquivo do projeto e os logs da sessão atual em um arquivo ZIP." msgid "Any additional visual examples like images or screen recordings might be helpful while reporting the issue." @@ -19598,7 +19592,7 @@ msgstr "Nível de log" msgid "Stored logs" msgstr "Logs armazenados" -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Compacta todos os logs armazenados em um arquivo ZIP." msgid "Profiles" @@ -19665,7 +19659,7 @@ msgstr "Tipo de impressora não encontrado, selecione manualmente." msgid "Authorizing..." msgstr "Autorizando…" -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Erro. ​​Não foi possível obter o token de API para autorização" msgid "Could not parse server response." diff --git a/localization/i18n/ru/OrcaSlicer_ru.po b/localization/i18n/ru/OrcaSlicer_ru.po index eb24ebc759..200d3cbb42 100644 --- a/localization/i18n/ru/OrcaSlicer_ru.po +++ b/localization/i18n/ru/OrcaSlicer_ru.po @@ -6376,10 +6376,10 @@ msgstr "Импорт 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "Загрузка модели" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "Импорт ZIP-архива" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Загрузка моделей, содержащихся в ZIP-архиве" msgid "Import Configs" @@ -8168,8 +8168,8 @@ msgstr "Во избежание повреждения принтера убед msgid "Customized Preset" msgstr "Пользовательский профиль" -msgid "Component name(s) inside step file not in UTF8 format!" -msgstr "Имена компонентов внутри файла STEP не в формате UTF8." +msgid "Component name(s) inside step file not in UTF-8 format!" +msgstr "Имена компонентов внутри файла STEP не в формате UTF-8." msgid "Because of unsupported text encoding, garbage characters may appear!" msgstr "Из-за неподдерживаемой кодировки в названии могут присутствовать ошибочные символы." @@ -8190,7 +8190,7 @@ msgstr "Объём модели равен нулю" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "Модель из файла %s слишком мала. Возможно, её размеры \n" "в метрах или дюймах. Внутренней единицей программы \n" @@ -11072,11 +11072,11 @@ msgstr "%s: %s" msgid "No modifications need to be copied." msgstr "Перенос изменений не требуется." -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Копировать настройки" #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "Изменить настройки %s" #, c-format, boost-format @@ -12694,7 +12694,7 @@ msgstr "мм или %" msgid "Other layers" msgstr "Основная" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "Температура стола для всех остальных слоёв. 0 – материал не поддерживает это покрытие." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." @@ -16223,7 +16223,7 @@ msgstr "Начальная и конечная точки траектории msgid "Reduce infill retraction" msgstr "Откат только при пересечении периметров" -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "" "Отключает откат (и подъём по Z), когда перемещения совершаются полностью над заполнением (где любые подтёки, вероятно, будут скрыты). Это поможет снизить количество откатов при печати сложных моделей и немного сэкономить время, но увеличит время нарезки и генерации G-кода.\n" "\n" @@ -16401,7 +16401,7 @@ msgstr "Вторичный откат" #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "Быстрый откат после очистки, выраженный в процентах от общей длины отката. В некоторых случаях позволяет значительно снизить количество «паутины».\n" @@ -16449,7 +16449,7 @@ msgstr "При срабатывании отката перед сменой и msgid "Z-hop height" msgstr "Высота подъёма" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "При каждом откате печатная голова немного приподнимается, создавая зазор между соплом и моделью. Это предотвращает столкновение сопла с моделью при перемещении. Использование спирального подъёма может помочь сократить образование \"паутины\"." msgid "Z-hop lower boundary" @@ -20306,21 +20306,21 @@ msgstr "Будут отображаться только изменённые п msgid "Only display the filament names with changes to filament presets." msgstr "Будут отображаться только изменённые профили материалов." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "" "Будут отображаться только изменённые профили принтеров.\n" "Все они будут экспортированы в единый zip-файл." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Будут отображаться только изменённые профили материалов.\n" "Все они будут экспортированы в единый zip-файл." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Будут отображаться только профили принтеров с изменёнными настройками печати.\n" "Все изменённые профили настроек будут экспортированы в единый zip-файл." @@ -20560,7 +20560,7 @@ msgstr "Копировать в буфер обмена" msgid "We need information for diagnosing source of the issue. Check wiki page for detailed guide." msgstr "Эта информация требуется для диагностики проблем. Ознакомьтесь с руководством для получения подробностей." -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "Нажмите «Экспорт», чтобы сохранить текущий проект и журнал сессии в ZIP-архив." msgid "Any additional visual examples like images or screen recordings might be helpful while reporting the issue." @@ -20602,7 +20602,7 @@ msgstr "Уровень ведения журнала" msgid "Stored logs" msgstr "Сохранённые журналы" -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Нажмите «Экспорт», чтобы упаковать все сохранённые журналы в единый ZIP-архив" msgid "Profiles" @@ -20669,7 +20669,7 @@ msgstr "Требуется указать принтер вручную" msgid "Authorizing..." msgstr "Авторизация..." -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Ошибка получения токена авторизации" msgid "Could not parse server response." diff --git a/localization/i18n/sv/OrcaSlicer_sv.po b/localization/i18n/sv/OrcaSlicer_sv.po index 52972e241a..fce8c33b10 100644 --- a/localization/i18n/sv/OrcaSlicer_sv.po +++ b/localization/i18n/sv/OrcaSlicer_sv.po @@ -6971,11 +6971,11 @@ msgid "Load a model" msgstr "Ladda modell" # AI Translated -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "Importera ZIP-arkiv" # AI Translated -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Läs in modeller som finns i ett ZIP-arkiv" msgid "Import Configs" @@ -8952,8 +8952,8 @@ msgstr "Bekräfta att G-koderna i dessa inställningar är säkra för att förh msgid "Customized Preset" msgstr "Anpassad inställning" -msgid "Component name(s) inside step file not in UTF8 format!" -msgstr "Komponent namnet i STEP filen är inte UTF8 format!" +msgid "Component name(s) inside step file not in UTF-8 format!" +msgstr "Komponent namnet i STEP filen är inte UTF-8 format!" msgid "Because of unsupported text encoding, garbage characters may appear!" msgstr "På grund av textkodning som inte stöds så kan skräptecken visas!" @@ -8974,7 +8974,7 @@ msgstr "Objektet är utan volym" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "Objektets fil %s är för litet, det är kanske i meter eller inches.\n" "Skala om till millimeter?" @@ -12190,12 +12190,12 @@ msgid "No modifications need to be copied." msgstr "Inga ändringar behöver kopieras." # AI Translated -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Kopiera parametrar" # AI Translated #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "Ändra parametrar för %s" # AI Translated @@ -14012,23 +14012,27 @@ msgstr "mm eller %" msgid "Other layers" msgstr "Andra lager" -# AI Translated -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +#, fuzzy +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "Byggplattans temperatur för alla lager utom det första. Värdet 0 innebär att filamentet inte stöder utskrift på Cool Plate SuperTack." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "Detta är byggplattans temperatur för lager förutom det första. Värdet 0 betyder att filamentet inte stöder utskrift på Cool Plate." -# AI Translated +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured Cool Plate." msgstr "Detta är byggplattans temperatur för lager förutom det första. Värdet 0 betyder att filamentet inte stöder utskrift på Textured Cool Plate." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Engineering Plate." msgstr "Detta är byggplattans temperatur för lager förutom det första. Ett värde på 0 betyder att filamentet inte stöder utskrift på Engineering Plate." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the High Temp Plate." msgstr "Detta är byggplattans temperatur för lager förutom det första. Värdet 0 betyder att filamentet inte stöder utskrift på High Temp Plate." +#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured PEI Plate." msgstr "Byggplattans temperatur efter det första lagret. 0 betyder att filamentet inte stöds på den texturerade PEI-plattan." @@ -17720,8 +17724,8 @@ msgid "Reduce infill retraction" msgstr "Minska ifyllnads retraktionen" # AI Translated -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." -msgstr "Dra inte tillbaka när förflyttningen är helt i ett utfyllnadsområde. Det betyder att läckage av filament inte kan ses. Detta kan minska tiderna för indragning för komplexa modeller och spara utskriftstid, men gör beredning och generering av G-kod långsammare. Observera att z-hop inte heller utförs i områden där retraktionen hoppas över." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." +msgstr "Dra inte tillbaka när förflyttningen är helt i ett utfyllnadsområde. Det betyder att läckage av filament inte kan ses. Detta kan minska tiderna för indragning för komplexa modeller och spara utskriftstid, men gör beredning och generering av G-kod långsammare. Observera att Z-hop inte heller utförs i områden där retraktionen hoppas över." # AI Translated msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -17913,7 +17917,7 @@ msgstr "Reduktionsmängd efter avtorkning" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "Längden på den snabba reduktionen efter avtorkning, i förhållande till reduktionslängden.\n" @@ -17968,7 +17972,7 @@ msgstr "När reduktionen utlöses före ett verktygsbyte dras filamentet tillbak msgid "Z-hop height" msgstr "Z-hop-höjd" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "När det är en retraktion lyfts nozzel en aning för att skapa ett spel mellan nozzel och utskriften. Detta förhindrar att nozzel träffar utskriften när den förflyttas. Att använda spirallinjer för att lyfta z kan förhindra strängning" msgid "Z-hop lower boundary" @@ -22041,19 +22045,19 @@ msgstr "Endast printer med ändringar av inställningar för printer, filament o msgid "Only display the filament names with changes to filament presets." msgstr "Visa endast filament namnen vid ändringar av filament inställningar." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "Endast printer namn med inställningar för printer visas, och varje inställning du väljer exporteras som zip-fil." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Endast filament namn med inställningar för användar filament visas, \n" "och alla inställningar för användar filament i varje filament namn du väljer exporteras som en zip-fil." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Endast printer namn med ändrade process inställningar visas, \n" "och alla användarprocess inställningar i varje printer namn som du väljer exporteras som zip-fil." @@ -22312,7 +22316,7 @@ msgid "We need information for diagnosing source of the issue. Check wiki page f msgstr "Vi behöver information för att diagnostisera orsaken till problemet. Se wiki-sidan för en detaljerad guide." # AI Translated -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "Paketera-knappen samlar projektfilen och loggarna från den aktuella sessionen i en zip-fil." # AI Translated @@ -22368,7 +22372,7 @@ msgid "Stored logs" msgstr "Sparade loggar" # AI Translated -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Paketerar alla sparade loggar i en zip-fil." # AI Translated @@ -22456,7 +22460,7 @@ msgid "Authorizing..." msgstr "Auktoriserar..." # AI Translated -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Fel. Det går inte att hämta api-token för auktorisering" # AI Translated diff --git a/localization/i18n/th/OrcaSlicer_th.po b/localization/i18n/th/OrcaSlicer_th.po index 4c4ac2d25f..ca12a4ced2 100644 --- a/localization/i18n/th/OrcaSlicer_th.po +++ b/localization/i18n/th/OrcaSlicer_th.po @@ -6302,10 +6302,10 @@ msgstr "นำเข้า 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "โหลดโมเดล" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "นำเข้าไฟล์ Zip" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "โหลดโมเดลที่มีอยู่ในไฟล์ zip" msgid "Import Configs" @@ -8074,8 +8074,8 @@ msgstr "โปรดยืนยันว่ารหัส G ภายในค msgid "Customized Preset" msgstr "ค่าที่ตั้งไว้ล่วงหน้าที่กำหนดเอง" -msgid "Component name(s) inside step file not in UTF8 format!" -msgstr "ชื่อของส่วนประกอบภายในไฟล์ STEP ไม่ใช่รูปแบบ UTF8!" +msgid "Component name(s) inside step file not in UTF-8 format!" +msgstr "ชื่อของส่วนประกอบภายในไฟล์ STEP ไม่ใช่รูปแบบ UTF-8!" msgid "Because of unsupported text encoding, garbage characters may appear!" msgstr "ชื่ออาจแสดงตัวอักษรขยะ!" @@ -8096,7 +8096,7 @@ msgstr "ปริมาตรของวัตถุเป็นศูนย์ #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "วัตถุจากไฟล์ %s มีขนาดเล็กเกินไป และอาจมีหน่วยเป็นเมตรหรือนิ้ว\n" " คุณต้องการขยายขนาดเป็นมิลลิเมตรหรือไม่?" @@ -10948,12 +10948,12 @@ msgid "No modifications need to be copied." msgstr "ไม่มีการแก้ไขที่ต้องคัดลอก" # AI Translated -msgid "Copy paramters" +msgid "Copy parameters" msgstr "คัดลอกพารามิเตอร์" # AI Translated #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "แก้ไขพารามิเตอร์ของ %s" # AI Translated @@ -12578,7 +12578,7 @@ msgstr "มม. หรือ %" msgid "Other layers" msgstr "ชั้นอื่นๆ" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "อุณหภูมิฐานพิมพ์สำหรับชั้นต่างๆ ยกเว้นอุณหภูมิเริ่มต้น ค่า 0 หมายความว่าเส้นพลาสติกไม่รองรับการพิมพ์บน Cool Plate SuperTack" msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." @@ -15827,8 +15827,8 @@ msgstr "จุดเริ่มต้นและจุดสิ้นสุด msgid "Reduce infill retraction" msgstr "ลดการดึงกลับในไส้ใน" -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." -msgstr "อย่าถอยกลับเมื่อการเดินทางอยู่ภายในพื้นที่ที่ไส้ในเข้าไปทั้งหมด นั่นหมายความว่าไม่สามารถมองเห็นการรั่วไหลได้ วิธีนี้จะช่วยลดเวลาในการดึงกลับสำหรับโมเดลที่ซับซ้อนและประหยัดเวลาในการพิมพ์ แต่จะทำให้การแบ่งส่วนและการสร้าง G-code ช้าลง โปรดทราบว่า z-hop จะไม่ดำเนินการในพื้นที่ที่มีการข้ามการถอนกลับ" +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." +msgstr "อย่าถอยกลับเมื่อการเดินทางอยู่ภายในพื้นที่ที่ไส้ในเข้าไปทั้งหมด นั่นหมายความว่าไม่สามารถมองเห็นการรั่วไหลได้ วิธีนี้จะช่วยลดเวลาในการดึงกลับสำหรับโมเดลที่ซับซ้อนและประหยัดเวลาในการพิมพ์ แต่จะทำให้การแบ่งส่วนและการสร้าง G-code ช้าลง โปรดทราบว่า Z-hop จะไม่ดำเนินการในพื้นที่ที่มีการข้ามการถอนกลับ" msgid "This option will drop the temperature of the inactive extruders to prevent oozing." msgstr "ตัวเลือกนี้จะทำให้อุณหภูมิของชุดดันเส้นที่ไม่ใช้งานลดลงเพื่อป้องกันการไหลซึม" @@ -15997,7 +15997,7 @@ msgstr "ปริมาณการดึงกลับหลังเช็ด # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "ความยาวของการดึงกลับอย่างเร็วหลังเช็ดหัว สัมพันธ์กับความยาวการดึงกลับ\n" @@ -16044,7 +16044,7 @@ msgstr "เมื่อการดึงกลับทำงานก่อน msgid "Z-hop height" msgstr "ความสูงยกแกน Z" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "เมื่อใดก็ตามที่การดึงกลับเสร็จสิ้น หัวฉีดจะถูกยกขึ้นเล็กน้อยเพื่อสร้างระยะห่างระหว่างหัวฉีดและงานพิมพ์ ป้องกันไม่ให้หัวฉีดชนกับงานพิมพ์ขณะเคลื่อนตัว การใช้เส้นเกลียวเพื่อยก Z สามารถป้องกันการร้อยสายได้" msgid "Z-hop lower boundary" @@ -19632,19 +19632,19 @@ msgstr "แสดงเฉพาะชื่อเครื่องพิมพ msgid "Only display the filament names with changes to filament presets." msgstr "แสดงเฉพาะชื่อเส้นพลาสติกที่มีการเปลี่ยนแปลงการตั้งค่าล่วงหน้าของเส้นพลาสติก" -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "เฉพาะชื่อเครื่องพิมพ์ที่มีการตั้งค่าเครื่องพิมพ์ล่วงหน้าของผู้ใช้เท่านั้นที่จะแสดง และการตั้งค่าล่วงหน้าแต่ละรายการที่คุณเลือกจะถูกส่งออกเป็นไฟล์ ZIP" msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "เฉพาะชื่อเส้นพลาสติกที่มีการตั้งค่าล่วงหน้าของเส้นพลาสติกผู้ใช้เท่านั้นที่จะถูกแสดง \n" "และค่าฟิลาเมนต์ของผู้ใช้ทั้งหมดที่กำหนดไว้ล่วงหน้าในแต่ละชื่อฟิลาเมนต์ที่คุณเลือกจะถูกส่งออกเป็นไฟล์ ZIP" msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "เฉพาะชื่อเครื่องพิมพ์ที่มีการตั้งค่าล่วงหน้าของกระบวนการที่เปลี่ยนแปลงเท่านั้นที่จะปรากฏขึ้น \n" "และกระบวนการของผู้ใช้ที่ตั้งไว้ล่วงหน้าในชื่อเครื่องพิมพ์แต่ละเครื่องที่คุณเลือกจะถูกส่งออกเป็นไฟล์ ZIP" @@ -19885,7 +19885,7 @@ msgid "We need information for diagnosing source of the issue. Check wiki page f msgstr "เราต้องการข้อมูลเพื่อวินิจฉัยแหล่งที่มาของปัญหา ตรวจสอบหน้า wiki สำหรับคำแนะนำโดยละเอียด" # AI Translated -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "ปุ่ม Pack จะรวบรวมไฟล์โปรเจกต์และบันทึกของเซสชันปัจจุบันลงในไฟล์ zip" # AI Translated @@ -19941,7 +19941,7 @@ msgid "Stored logs" msgstr "บันทึกที่จัดเก็บ" # AI Translated -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "รวมบันทึกที่จัดเก็บทั้งหมดลงในไฟล์ zip" # AI Translated @@ -20021,7 +20021,7 @@ msgstr "ไม่พบประเภทเครื่องพิมพ์ msgid "Authorizing..." msgstr "กำลังอนุญาต..." -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "ข้อผิดพลาด ไม่สามารถรับโทเคน API สำหรับการอนุญาตได้" msgid "Could not parse server response." diff --git a/localization/i18n/tr/OrcaSlicer_tr.po b/localization/i18n/tr/OrcaSlicer_tr.po index 833706ad70..b7a2c5b682 100644 --- a/localization/i18n/tr/OrcaSlicer_tr.po +++ b/localization/i18n/tr/OrcaSlicer_tr.po @@ -6370,10 +6370,10 @@ msgstr "3MF/STL/STEP/SVG/OBJ/AMF'yi içe aktar" msgid "Load a model" msgstr "Model yükle" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "Zip Arşivini İçe Aktar" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Zip arşivindeki modelleri yükle" msgid "Import Configs" @@ -8171,8 +8171,8 @@ msgstr "Lütfen bu ön ayarlar içindeki G-code'larının makineye herhangi bir msgid "Customized Preset" msgstr "Özel Ayar" -msgid "Component name(s) inside step file not in UTF8 format!" -msgstr "Step dosyasındaki bileşenlerin adı UTF8 formatında değil!" +msgid "Component name(s) inside step file not in UTF-8 format!" +msgstr "Step dosyasındaki bileşenlerin adı UTF-8 formatında değil!" # AI Translated msgid "Because of unsupported text encoding, garbage characters may appear!" @@ -8194,10 +8194,10 @@ msgstr "Cismin hacmi sıfır" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "%s dosyasındaki nesne çok küçük; metre veya inç cinsinden olabilir.\n" -" Milimetreye ölçeklendirmek istiyor musunuz?" +"Milimetreye ölçeklendirmek istiyor musunuz?" msgid "Object too small" msgstr "Nesne çok küçük" @@ -11128,12 +11128,12 @@ msgid "No modifications need to be copied." msgstr "Kopyalanması gereken değişiklik yok." # AI Translated -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Parametreleri kopyala" # AI Translated #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "%s parametrelerini değiştir" # AI Translated @@ -12805,7 +12805,7 @@ msgstr "mm veya %" msgid "Other layers" msgstr "Diğer katmanlar" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "İlk katman hariç tüm katmanlar için yatak sıcaklığı. 0 değeri, filamentin Cool Plate SuperTack üzerine baskıyı desteklemediği anlamına gelir." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." @@ -16129,8 +16129,8 @@ msgid "Reduce infill retraction" msgstr "Dolguda geri çekmeyi azalt" # AI Translated -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." -msgstr "Hareket tamamen dolgu alanı içindeyken geri çekme yapılmaz. Bu, sızıntının görülemeyeceği anlamına gelir. Bu, karmaşık modellerde geri çekme sayısını azaltabilir ve yazdırma süresinden tasarruf sağlayabilir, ancak dilimlemeyi ve G-code oluşturmayı yavaşlatır. Geri çekmenin atlandığı alanlarda z-hop'un da uygulanmadığını unutmayın." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." +msgstr "Hareket tamamen dolgu alanı içindeyken geri çekme yapılmaz. Bu, sızıntının görülemeyeceği anlamına gelir. Bu, karmaşık modellerde geri çekme sayısını azaltabilir ve yazdırma süresinden tasarruf sağlayabilir, ancak dilimlemeyi ve G-code oluşturmayı yavaşlatır. Geri çekmenin atlandığı alanlarda Z-hop'un da uygulanmadığını unutmayın." msgid "This option will drop the temperature of the inactive extruders to prevent oozing." msgstr "Bu seçenek sızıntıyı önlemek için aktif olmayan ekstrüderlerin sıcaklığını düşürecektir." @@ -16305,7 +16305,7 @@ msgstr "Silme sonrası geri çekme miktarı" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "Silme sonrasındaki hızlı geri çekmenin uzunluğu; geri çekme uzunluğuna göredir.\n" @@ -16352,7 +16352,7 @@ msgstr "Takım değişiminden önce geri çekme tetiklendiğinde, filament belir msgid "Z-hop height" msgstr "Z-Sıçrama yüksekliği" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "Geri çekme işlemi her yapıldığında, nozul ile baskı arasında açıklık oluşturmak için nozul biraz kaldırılır. Hareket halindeyken nozulun baskıya çarpmasını önler. Z'yi kaldırmak için spiral çizgi kullanmak çekmeyi önleyebilir." msgid "Z-hop lower boundary" @@ -18155,10 +18155,10 @@ msgid "Allow 3MF with newer version to be sliced." msgstr "Daha yeni sürüme sahip 3mf’nin dilimlenmesine izin ver." msgid "Current Z-hop" -msgstr "Mevcut z-hop" +msgstr "Mevcut Z-hop" msgid "Contains Z-hop present at the beginning of the custom G-code block." -msgstr "Özel G-code bloğunun başında bulunan z-hop'u içerir." +msgstr "Özel G-code bloğunun başında bulunan Z-hop'u içerir." msgid "Position of the extruder at the beginning of the custom G-code block. If the custom G-code travels somewhere else, it should write to this variable so OrcaSlicer knows where it travels from when it gets control back." msgstr "Ekstruderin özel G-code bloğunun başlangıcındaki konumu. Özel G-code başka bir yere seyahat ederse, Slicer'ın kontrolü geri aldığında nereden seyahat ettiğini bilmesi için bu değişkene yazması gerekir." @@ -20003,19 +20003,19 @@ msgstr "Yazıcı adlarını yalnızca yazıcı, filament ve işlem ön ayarları msgid "Only display the filament names with changes to filament presets." msgstr "Filament adlarını yalnızca filament ön ayarlarında yapılan değişikliklerle görüntüleyin." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "Yalnızca kullanıcı yazıcı ön ayarlarına sahip yazıcı adları görüntülenecek ve seçtiğiniz her ön ayar zip olarak dışa aktarılacaktır." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Yalnızca kullanıcı filamenti ön ayarlarına sahip filament adları \n" "görüntülenecek ve seçtiğiniz her filament adındaki tüm kullanıcı filamenti ön ayarları zip olarak dışa aktarılacaktır." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Yalnızca işlem ön ayarları değiştirilen yazıcı adları görüntülenecek \n" "ve seçtiğiniz her yazıcı adındaki tüm kullanıcı işlem ön ayarları zip olarak dışa aktarılacaktır." @@ -20260,7 +20260,7 @@ msgid "We need information for diagnosing source of the issue. Check wiki page f msgstr "Sorunun kaynağını teşhis etmek için bilgiye ihtiyacımız var. Ayrıntılı kılavuz için wiki sayfasına bakın." # AI Translated -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "Paketle düğmesi, geçerli oturumun proje dosyasını ve günlüklerini bir zip dosyasında toplar." # AI Translated @@ -20316,7 +20316,7 @@ msgid "Stored logs" msgstr "Saklanan günlükler" # AI Translated -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Saklanan tüm günlükleri bir zip dosyasında paketler." # AI Translated @@ -20402,7 +20402,7 @@ msgid "Authorizing..." msgstr "Yetkilendiriliyor..." # AI Translated -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Hata. Yetkilendirme için api belirteci alınamıyor" # AI Translated diff --git a/localization/i18n/uk/OrcaSlicer_uk.po b/localization/i18n/uk/OrcaSlicer_uk.po index df06c01684..8393e92947 100644 --- a/localization/i18n/uk/OrcaSlicer_uk.po +++ b/localization/i18n/uk/OrcaSlicer_uk.po @@ -6339,10 +6339,10 @@ msgstr "Імпорт 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "Завантажте модель" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "Імпорт Zip-архіву" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Завантажити моделі, що містяться в zip-архіві" msgid "Import Configs" @@ -8180,8 +8180,8 @@ msgid "Customized Preset" msgstr "Пристосований пресет" # AI Translated -msgid "Component name(s) inside step file not in UTF8 format!" -msgstr "Назви компонентів усередині файлу STEP не у форматі UTF8!" +msgid "Component name(s) inside step file not in UTF-8 format!" +msgstr "Назви компонентів усередині файлу STEP не у форматі UTF-8!" msgid "Because of unsupported text encoding, garbage characters may appear!" msgstr "Через непідтримуване кодування тексту можуть зʼявлятися непотрібні символи!" @@ -8202,7 +8202,7 @@ msgstr "Обʼєм обʼєкта дорівнює нулю" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "Обʼєкт із файлу %s занадто малий, можливо, в метрах або дюймах.\n" "Ви хочете масштабувати до міліметрів?" @@ -11173,12 +11173,12 @@ msgstr "%s: %s" msgid "No modifications need to be copied." msgstr "Немає змін для копіювання." -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Параметри копіювання" # AI Translated #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "Змінити параметри %s" # AI Translated @@ -12881,8 +12881,7 @@ msgstr "мм або %" msgid "Other layers" msgstr "Інші шари" -# AI Translated -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "Температура столу для всіх шарів, крім першого. Значення 0 означає, що філамент не підтримує друк на Cool Plate SuperTack." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." @@ -16313,8 +16312,8 @@ msgid "Reduce infill retraction" msgstr "Зменшити втягування заповнення" # AI Translated -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." -msgstr "Не втягувати, коли переміщення повністю проходить у зоні заповнення. Це означає, що витікання не буде видно. Це може зменшити кількість втягувань для складних моделей і заощадити час друку, але сповільнює нарізку та генерацію G-коду. Зверніть увагу, що z-hop також не виконується в зонах, де втягування пропускається." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." +msgstr "Не втягувати, коли переміщення повністю проходить у зоні заповнення. Це означає, що витікання не буде видно. Це може зменшити кількість втягувань для складних моделей і заощадити час друку, але сповільнює нарізку та генерацію G-коду. Зверніть увагу, що Z-hop також не виконується в зонах, де втягування пропускається." msgid "This option will drop the temperature of the inactive extruders to prevent oozing." msgstr "Цей параметр знижує температуру неактивних екструдерів, щоб запобігти підтіканням." @@ -16489,7 +16488,7 @@ msgstr "Величина втягування після протирання" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "Довжина швидкого втягування після протирання, відносно довжини втягування.\n" @@ -16538,7 +16537,7 @@ msgstr "Коли втягування спрацьовує перед зміно msgid "Z-hop height" msgstr "Висота Z-підйому" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "Під час кожного втягування сопло трохи піднімається, щоб створити зазор між соплом та об’єктом друку. Це запобігає зіткненню сопла з об’єктом друку під час переміщення. Використання спіральної лінії підняття по осі Z може запобігти появі ниток" msgid "Z-hop lower boundary" @@ -20244,12 +20243,12 @@ msgstr "Показувати лише назви принтерів зі змі msgid "Only display the filament names with changes to filament presets." msgstr "Показувати лише назви філаментів зі змінами у пресетах філаменту." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "Будуть відображатися лише назви принтерів з пресетами принтера користувача, і кожен обраний пресет буде експортовано у форматі ZIP." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Будуть відображатися лише назви філаментів з налаштуваннями філаменту користувача, \n" "і всі налаштування філаменту користувача для кожної вибраної назви філаменту \n" @@ -20257,7 +20256,7 @@ msgstr "" msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Будуть відображатися лише назви принтерів зі зміненими налаштуваннями процесу, \n" "і всі налаштування процесу користувача для кожної вибраної назви принтера будуть \n" @@ -20499,7 +20498,7 @@ msgid "We need information for diagnosing source of the issue. Check wiki page f msgstr "Нам потрібна інформація для встановлення джерела проблеми. Докладний посібник дивіться на сторінці wiki." # AI Translated -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "Кнопка «Пакувати» збирає файл проєкту та журнали поточного сеансу в один zip-файл." # AI Translated @@ -20543,7 +20542,7 @@ msgstr "Рівень журналу" msgid "Stored logs" msgstr "Збережені логи" -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Запаковує всі збережені логи у файл zip." msgid "Profiles" @@ -20610,7 +20609,7 @@ msgstr "Тип принтера не знайдено, будь ласка ви msgid "Authorizing..." msgstr "Авторизування..." -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Помилка. Не вдалося отримати api-токен для авторизування" msgid "Could not parse server response." diff --git a/localization/i18n/vi/OrcaSlicer_vi.po b/localization/i18n/vi/OrcaSlicer_vi.po index e78fc51687..936bb590c5 100644 --- a/localization/i18n/vi/OrcaSlicer_vi.po +++ b/localization/i18n/vi/OrcaSlicer_vi.po @@ -6687,10 +6687,10 @@ msgstr "Nhập 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "Tải model" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "Nhập lưu trữ Zip" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "Tải các model chứa trong lưu trữ zip" msgid "Import Configs" @@ -8585,8 +8585,8 @@ msgstr "Vui lòng xác nhận G-code trong các preset này an toàn để ngăn msgid "Customized Preset" msgstr "Preset tùy chỉnh" -msgid "Component name(s) inside step file not in UTF8 format!" -msgstr "Tên của các thành phần bên trong file STEP không phải định dạng UTF8!" +msgid "Component name(s) inside step file not in UTF-8 format!" +msgstr "Tên của các thành phần bên trong file STEP không phải định dạng UTF-8!" # AI Translated msgid "Because of unsupported text encoding, garbage characters may appear!" @@ -8608,10 +8608,10 @@ msgstr "Thể tích của đối tượng bằng không" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "Đối tượng từ file %s quá nhỏ, và có thể đang ở đơn vị mét hoặc inch.\n" -" Bạn có muốn chuyển đổi sang milimét?" +"Bạn có muốn chuyển đổi sang milimét?" msgid "Object too small" msgstr "Đối tượng quá nhỏ" @@ -11692,12 +11692,12 @@ msgid "No modifications need to be copied." msgstr "Không có thay đổi nào cần sao chép." # AI Translated -msgid "Copy paramters" +msgid "Copy parameters" msgstr "Sao chép tham số" # AI Translated #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "Sửa tham số của %s" # AI Translated @@ -13449,7 +13449,7 @@ msgstr "mm hoặc %" msgid "Other layers" msgstr "Lớp khác" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "Nhiệt độ bàn cho các lớp ngoại trừ lớp đầu tiên. Giá trị 0 có nghĩa là filament không hỗ trợ in trên bản Cool SuperTack." msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." @@ -16846,8 +16846,8 @@ msgid "Reduce infill retraction" msgstr "Giảm rút infill" # AI Translated -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." -msgstr "Không rút khi di chuyển ở vùng infill hoàn toàn. Điều đó có nghĩa là chảy nhựa không thể nhìn thấy. Điều này có thể giảm số lần rút cho model phức tạp và tiết kiệm thời gian in, nhưng làm cho slice và tạo G-code chậm hơn. Lưu ý rằng z-hop cũng không được thực hiện ở những vùng bỏ qua việc rút." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." +msgstr "Không rút khi di chuyển ở vùng infill hoàn toàn. Điều đó có nghĩa là chảy nhựa không thể nhìn thấy. Điều này có thể giảm số lần rút cho model phức tạp và tiết kiệm thời gian in, nhưng làm cho slice và tạo G-code chậm hơn. Lưu ý rằng Z-hop cũng không được thực hiện ở những vùng bỏ qua việc rút." msgid "This option will drop the temperature of the inactive extruders to prevent oozing." msgstr "Tùy chọn này sẽ giảm nhiệt độ của các extruder không hoạt động để ngăn chảy nhựa." @@ -17022,7 +17022,7 @@ msgstr "Lượng rút sau khi lau" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "Độ dài rút nhanh sau khi lau, tương đối so với độ dài rút.\n" @@ -17071,7 +17071,7 @@ msgstr "Khi rút được kích hoạt trước khi đổi công cụ, filament msgid "Z-hop height" msgstr "Chiều cao Z-hop" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "Bất cứ khi nào rút được thực hiện, đầu phun được nâng lên một chút để tạo khoảng trống giữa đầu phun và bản in. Nó ngăn đầu phun va vào bản in khi di chuyển. Sử dụng đường xoắn ốc để nâng Z có thể ngăn dây kéo." msgid "Z-hop lower boundary" @@ -20793,19 +20793,19 @@ msgstr "Chỉ hiển thị tên máy in có thay đổi đối với cài đặt msgid "Only display the filament names with changes to filament presets." msgstr "Chỉ hiển thị tên filament có thay đổi đối với cài đặt sẵn filament." -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "Chỉ tên máy in có cài đặt sẵn máy in người dùng sẽ được hiển thị, và mỗi cài đặt sẵn bạn chọn sẽ được xuất dưới dạng zip." msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "Chỉ tên filament có cài đặt sẵn filament người dùng sẽ được hiển thị, \n" "và tất cả cài đặt sẵn filament người dùng trong mỗi tên filament bạn chọn sẽ được xuất dưới dạng zip." msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "Chỉ tên máy in có cài đặt sẵn quy trình đã thay đổi sẽ được hiển thị, \n" "và tất cả cài đặt sẵn quy trình người dùng trong mỗi tên máy in bạn chọn sẽ được xuất dưới dạng zip." @@ -21057,7 +21057,7 @@ msgid "We need information for diagnosing source of the issue. Check wiki page f msgstr "Chúng tôi cần thông tin để chẩn đoán nguồn gốc vấn đề. Hãy xem trang wiki để có hướng dẫn chi tiết." # AI Translated -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "Nút Đóng gói thu thập file dự án và nhật ký của phiên hiện tại vào một file zip." # AI Translated @@ -21113,7 +21113,7 @@ msgid "Stored logs" msgstr "Nhật ký đã lưu" # AI Translated -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "Đóng gói toàn bộ nhật ký đã lưu vào một file zip." # AI Translated @@ -21201,7 +21201,7 @@ msgid "Authorizing..." msgstr "Đang xác thực..." # AI Translated -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "Lỗi. Không lấy được token api để xác thực" # AI Translated diff --git a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po index d2f07d19ae..99a6cadd67 100644 --- a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po +++ b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po @@ -6157,10 +6157,10 @@ msgstr "导入 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "加载模型" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "导入 ZIP 压缩文件" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "从 ZIP 压缩文件中导入一个或多个模型" msgid "Import Configs" @@ -7905,8 +7905,8 @@ msgstr "请确认这些预设中的G-codes是否安全,以防止对机器造 msgid "Customized Preset" msgstr "自定义的预设" -msgid "Component name(s) inside step file not in UTF8 format!" -msgstr "STEP 文件中的部件名称不是 UTF8 格式!" +msgid "Component name(s) inside step file not in UTF-8 format!" +msgstr "STEP 文件中的部件名称不是 UTF-8 格式!" # AI Translated msgid "Because of unsupported text encoding, garbage characters may appear!" @@ -7928,7 +7928,7 @@ msgstr "对象的体积为零" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "文件 %s 中对象的尺寸过小,似乎是以米(m)或者英寸(inch)为单位定义的。\n" "OrcaSlicer的内部单位为毫米(mm)。是否要转换成毫米(mm)?" @@ -10738,12 +10738,12 @@ msgid "No modifications need to be copied." msgstr "没有需要复制的修改。" # AI Translated -msgid "Copy paramters" +msgid "Copy parameters" msgstr "复制参数" # AI Translated #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "修改 %s 的参数" # AI Translated @@ -12374,7 +12374,8 @@ msgstr "mm 或 %" msgid "Other layers" msgstr "其它层" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +#, fuzzy +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "除首层外的其他层的热床温度。0值表示该耗材丝不支持在Cool Plate SuperTack上打印。" msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." @@ -15583,7 +15584,7 @@ msgstr "从切割区域到垃圾桶的起始和结束点。" msgid "Reduce infill retraction" msgstr "减小填充回抽" -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "当空驶完全在填充区域内时不触发回抽。这意味着即使漏料也是不可见的。对于复杂模型,该设置能够减少回抽次数以及打印时长,但是会造成G-code生成变慢" msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -15754,7 +15755,7 @@ msgstr "擦拭后的回抽量" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "擦拭后快速回抽的长度,相对于回抽长度。\n" @@ -15801,7 +15802,7 @@ msgstr "在换工具头之前触发回抽时,耗材丝会按指定的长度回 msgid "Z-hop height" msgstr "Z抬升高度" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "回抽完成之后,喷嘴轻微抬升,和打印件之间产生一定间隙。这能够避免空驶时喷嘴和打印件剐蹭和碰撞。使用螺旋线抬升z能够减少拉丝。" msgid "Z-hop lower boundary" @@ -19386,17 +19387,17 @@ msgstr "仅显示对打印机、耗材和工艺预设有改动的打印机名称 msgid "Only display the filament names with changes to filament presets." msgstr "仅显示对耗材预设有改动的耗材名称。" -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "只显示带有用户打印机预设的打印机名称,并且您选择的每个预设都将导出为一个 ZIP 文件。" msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "只显示带有用户耗材预设的耗材名称,您选择的每个耗材名称中的所有用户耗材预设都将导出为一个 ZIP 文件。" msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "只显示带有更改的工艺预设的打印机名称,您选择的每个打印机名称中的所有用户工艺预设都将导出为一个 ZIP 文件。" msgid "Please select at least one printer or filament." @@ -19635,7 +19636,7 @@ msgid "We need information for diagnosing source of the issue. Check wiki page f msgstr "我们需要相关信息来诊断问题的根源。请查看 wiki 页面获取详细指南。" # AI Translated -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "“打包”按钮会将当前会话的项目文件和日志收集到一个 zip 文件中。" # AI Translated @@ -19691,7 +19692,7 @@ msgid "Stored logs" msgstr "已存储的日志" # AI Translated -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "将所有已存储的日志打包到一个 zip 文件中。" # AI Translated @@ -19771,7 +19772,7 @@ msgstr "未找到打印机类型,请手动选择。" msgid "Authorizing..." msgstr "正在授权..." -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "错误。无法获取用于授权的 API 令牌" msgid "Could not parse server response." diff --git a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po index 456092deb5..86f5263b1b 100644 --- a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po +++ b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po @@ -6287,10 +6287,10 @@ msgstr "匯入 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "載入模型" -msgid "Import Zip Archive" +msgid "Import ZIP Archive" msgstr "匯入壓縮檔" -msgid "Load models contained within a zip archive" +msgid "Load models contained within a ZIP archive" msgstr "載入壓縮檔中的模型" msgid "Import Configs" @@ -8066,7 +8066,7 @@ msgstr "請確認這些預設中的 G-code 是安全的,以防止對列印裝 msgid "Customized Preset" msgstr "自訂預設" -msgid "Component name(s) inside step file not in UTF8 format!" +msgid "Component name(s) inside step file not in UTF-8 format!" msgstr "STEP 檔案內部元件的名稱不是 UTF-8 格式!" # AI Translated @@ -8089,7 +8089,7 @@ msgstr "物件的體積為零" #, c-format, boost-format msgid "" "The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"Do you want to scale to millimeters?" msgstr "" "檔案 %s 中的物件太小,可能以公尺(M)或英吋(Inches)為單位。\n" "是否要轉換成毫米(mm)?" @@ -10944,12 +10944,12 @@ msgid "No modifications need to be copied." msgstr "沒有需要複製的修改。" # AI Translated -msgid "Copy paramters" +msgid "Copy parameters" msgstr "複製參數" # AI Translated #, c-format, boost-format -msgid "Modify paramters of %s" +msgid "Modify parameters of %s" msgstr "修改 %s 的參數" # AI Translated @@ -12578,7 +12578,8 @@ msgstr "mm 或 %" msgid "Other layers" msgstr "其它層" -msgid "Bed temperature for layers except the initial one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." +#, fuzzy +msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "除首層外的其他層的熱床溫度。0值表示該線材不支援在低溫增穩列印板上列印。" msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." @@ -15790,7 +15791,7 @@ msgstr "從切割區域到垃圾桶的起始和結束點。" msgid "Reduce infill retraction" msgstr "減小填充回抽" -msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped." +msgid "Don't retract when the travel is entirely within an infill area. That means the oozing can't been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped." msgstr "當空駛完全在填充區域內時不觸發回抽。這意味著即使漏料也是不可見的。對於複雜模型,該設定能夠減少回抽次數以及列印時長,但是會造成 G-code 產生變慢" msgid "This option will drop the temperature of the inactive extruders to prevent oozing." @@ -15961,7 +15962,7 @@ msgstr "擦拭後的回抽量" # AI Translated #, no-c-format, no-boost-format msgid "" -"The length of fast retraction after wipe, relative to retraction length.\n" +"This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value." msgstr "" "擦拭後快速回抽的長度,相對於回抽長度。\n" @@ -16008,7 +16009,7 @@ msgstr "在換工具之前觸發回抽時,線材會依指定的長度回抽( msgid "Z-hop height" msgstr "Z 抬升高度" -msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing." +msgid "Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing." msgstr "回抽完成之後,噴嘴輕微抬升,和列印物件之間產生一定間隙。這能夠避免空駛時噴嘴和列印物件剮蹭和碰撞。使用螺旋線抬升z能夠減少拉絲" msgid "Z-hop lower boundary" @@ -19573,19 +19574,19 @@ msgstr "僅顯示對列印裝置、線材和處理預設設定有變更的列印 msgid "Only display the filament names with changes to filament presets." msgstr "僅顯示對線材預設設定有變更的線材名稱。" -msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip." +msgid "Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive." msgstr "只有具有使用者列印裝置預設設定的列印裝置名稱會顯示,您選擇的每個預設設定將以 zip 檔案格式匯出。" msgid "" "Only the filament names with user filament presets will be displayed, \n" -"and all user filament presets in each filament name you select will be exported as a zip." +"and all user filament presets in each filament name you select will be exported as a ZIP archive." msgstr "" "只有具有使用者線材預設設定的線材名稱會顯示,\n" "您選擇的每個線材名稱中的所有使用者線材預設設定將以 zip 檔案格式匯出。" msgid "" "Only printer names with changed process presets will be displayed, \n" -"and all user process presets in each printer name you select will be exported as a zip." +"and all user process presets in each printer name you select will be exported as a ZIP archive." msgstr "" "只有具有變更過處理預設設定的列印裝置名稱會顯示,\n" "您選擇的每個列印裝置名稱中的所有使用者處理預設設定將以 zip 檔案格式匯出。" @@ -19826,7 +19827,7 @@ msgid "We need information for diagnosing source of the issue. Check wiki page f msgstr "我們需要相關資訊以診斷問題來源。請查看 wiki 頁面以取得詳細指南。" # AI Translated -msgid "Pack button collects project file and logs of current session onto a zip file." +msgid "Pack button collects project file and logs of current session onto a ZIP archive." msgstr "「打包」按鈕會將目前工作階段的專案檔案與記錄收集到一個 zip 檔案中。" # AI Translated @@ -19882,7 +19883,7 @@ msgid "Stored logs" msgstr "已儲存的記錄" # AI Translated -msgid "Packs all stored logs onto a zip file." +msgid "Packs all stored logs onto a ZIP archive." msgstr "將所有已儲存的記錄打包成一個 zip 檔案。" # AI Translated @@ -19962,7 +19963,7 @@ msgstr "找不到列印裝置類型,請手動選取。" msgid "Authorizing..." msgstr "授權中..." -msgid "Error. Can't get api token for authorization" +msgid "Error. Can't get API token for authorization" msgstr "錯誤。無法取得用於授權的 API token。" msgid "Could not parse server response." diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 17d7cee678..29362fcf39 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1130,8 +1130,7 @@ void PrintConfigDef::init_fff_params() // BBS def = this->add("supertack_plate_temp", coInts); def->label = L("Other layers"); - def->tooltip = L("Bed temperature for layers except the initial one. " - "A value of 0 means the filament does not support printing on the Cool Plate SuperTack."); + def->tooltip = L("This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack."); def->sidetext = L(u8"\u2103" /* °C */); // degrees Celsius, CIS languages need translation def->full_label = L("Bed temperature"); def->min = 0; @@ -2770,7 +2769,7 @@ void PrintConfigDef::init_fff_params() def = this->add("fan_cooling_layer_time", coFloats); def->label = L("Layer time"); def->tooltip = L("The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time."); - def->sidetext = L("s"); // seconds, CIS languages need translation + def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation def->min = 0; def->max = 1000; def->mode = comSimple; @@ -2923,7 +2922,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Filament load time"); def->tooltip = L("Time to load new filament when switch filament. It's usually applicable for single-extruder multi-material machines. " "For tool changers or multi-tool machines, it's typically 0. For statistics only."); - def->sidetext = L("s"); // seconds, CIS languages need translation + def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation def->min = 0; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0.0)); @@ -2932,7 +2931,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Filament unload time"); def->tooltip = L("Time to unload old filament when switch filament. It's usually applicable for single-extruder multi-material machines. " "For tool changers or multi-tool machines, it's typically 0. For statistics only."); - def->sidetext = L("s"); // seconds, CIS languages need translation + def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation def->min = 0; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0.0)); @@ -2941,7 +2940,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Tool change time"); def->tooltip = L("Time taken to switch tools. It's usually applicable for tool changers or multi-tool machines. " "For single-extruder multi-material machines, it's typically 0. For statistics only."); - def->sidetext = L("s"); // seconds, CIS languages need translation + def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation def->min = 0; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat { 0. }); @@ -3087,7 +3086,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Time to wait after the filament is unloaded. " "May help to get reliable tool changes with flexible materials " "that may need more time to shrink to original dimensions."); - def->sidetext = L("s"); // seconds, CIS languages need translation + def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation def->min = 0; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloats { 0. }); @@ -4206,7 +4205,7 @@ void PrintConfigDef::init_fff_params() "\nIt won't move fan commands from custom G-code (they act as a sort of 'barrier')." "\nIt won't move fan commands into the start G-code if the 'only custom start G-code' is activated." "\nUse 0 to deactivate."); - def->sidetext = L("s"); // seconds, CIS languages need translation + def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0)); @@ -4222,7 +4221,7 @@ void PrintConfigDef::init_fff_params() "\nThis is useful for fans where a low PWM/power may be insufficient to get the fan started spinning from a stop, or to " "get the fan up to speed faster." "\nSet to 0 to deactivate."); - def->sidetext = L("s"); // seconds, CIS languages need translation + def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation def->min = 0; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0)); @@ -4866,7 +4865,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Ironing expansion"); def->category = L("Quality"); def->tooltip = L("Expand or contract the ironing area."); - def->sidetext = L("mm"); + def->sidetext = L("mm"); // millimeters, CIS languages need translation def->min = -100; def->max = 100; def->mode = comExpert; @@ -4903,7 +4902,7 @@ void PrintConfigDef::init_fff_params() def->category = L("Quality"); def->tooltip = L("Minimum Z-layer height.\n" "Also controls the slicing plane."); - def->sidetext = L("mm"); + def->sidetext = L("mm"); // millimeters, CIS languages need translation def->min = 0; def->max = 100; def->mode = comExpert; @@ -5102,7 +5101,7 @@ void PrintConfigDef::init_fff_params() def->category = L("Machine limits"); def->readonly = false; def->tooltip = L("The allowed maximum output force of Y axis"); - def->sidetext = L("N"); + def->sidetext = L_CONTEXT("N", "Newton"); // Newtons, CIS languages need translation def->min = 0; def->mode = comDevelop; def->set_default_value(new ConfigOptionFloat(0)); @@ -5112,7 +5111,7 @@ void PrintConfigDef::init_fff_params() def->category = L("Machine limits"); def->readonly = false; def->tooltip = L("The machine bed mass load of Y axis"); - def->sidetext = L("g"); + def->sidetext = L_CONTEXT("g", "gram"); // grams, CIS languages need translation def->min = 0; def->mode = comDevelop; def->set_default_value(new ConfigOptionFloat(0)); @@ -5122,7 +5121,7 @@ void PrintConfigDef::init_fff_params() def->category = L("Machine limits"); def->readonly = false; def->tooltip = L("The allowed max printed mass on a plate"); - def->sidetext = L("g"); + def->sidetext = L_CONTEXT("g", "gram"); // grams, CIS languages need translation def->min = 0; def->mode = comDevelop; def->set_default_value(new ConfigOptionFloat(0)); @@ -5481,7 +5480,7 @@ void PrintConfigDef::init_fff_params() def = this->add("reduce_infill_retraction", coBool); def->label = L("Reduce infill retraction"); - def->tooltip = L("Don\'t retract when the travel is entirely within an infill area. That means the oozing can\'t been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped."); + def->tooltip = L("Don\'t retract when the travel is entirely within an infill area. That means the oozing can\'t been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(false)); @@ -5736,7 +5735,7 @@ void PrintConfigDef::init_fff_params() def = this->add("retract_after_wipe", coPercents); def->label = L("Retract amount after wipe"); // xgettext:no-c-format, no-boost-format - def->tooltip = L("The length of fast retraction after wipe, relative to retraction length.\n" + def->tooltip = L("This is the length of fast retraction after wipe, relative to retraction length.\n" "The value will be clamped by 100% minus the retract amount before the wipe value."); def->sidetext = "%"; def->mode = comExpert; @@ -5802,7 +5801,7 @@ void PrintConfigDef::init_fff_params() def = this->add("z_hop", coFloats); def->label = L("Z-hop height"); - def->tooltip = L("Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing."); + def->tooltip = L("Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing."); def->sidetext = L("mm"); // millimeters, CIS languages need translation def->mode = comSimple; def->min = 0; @@ -6380,7 +6379,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Layer time"); def->tooltip = L("The printing speed in exported G-code will be slowed down when the estimated layer time is " "shorter than this value in order to get better cooling for these layers."); - def->sidetext = L("s"); // seconds, CIS languages need translation + def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation def->min = 0; def->max = 1000; def->mode = comSimple; @@ -6533,7 +6532,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Preheat time"); def->tooltip = L("To reduce the waiting time after tool change, Orca can preheat the next tool while the current tool is still in use. " "This setting specifies the time in seconds to preheat the next tool. Orca will insert a M104 command to preheat the tool in advance."); - def->sidetext = L("s"); // seconds, CIS languages need translation + def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation def->min = 0; def->max = 120; def->mode = comAdvanced; @@ -8025,7 +8024,7 @@ void PrintConfigDef::init_fff_params() def = this->add("machine_hotend_change_time", coFloat); def->label = L("Hotend change time"); def->tooltip = L("Time to change hotend."); - def->sidetext = L("s"); + def->sidetext = L_CONTEXT("s", "second"); def->min = 0; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0.0)); diff --git a/src/libslic3r/calib.cpp b/src/libslic3r/calib.cpp index 10fa9653eb..3c2981d822 100644 --- a/src/libslic3r/calib.cpp +++ b/src/libslic3r/calib.cpp @@ -28,9 +28,9 @@ std::string CalibPressureAdvance::move_to(Vec2d pt, GCodeWriter &writer, std::st gcode << writer.retract(); // retract before z move or move if(z > EPSILON && layer_height >= 0){ - gcode << writer.travel_to_z(z, "z-hop"); // Perform z hop + gcode << writer.travel_to_z(z, "Z-hop"); // Perform z hop gcode << writer.travel_to_xy(pt, comment); // Travel with z move - gcode << writer.travel_to_z(layer_height, "undo z-hop"); // Undo z hop + gcode << writer.travel_to_z(layer_height, "undo Z-hop"); // Undo z hop }else { gcode << writer.travel_to_xy(pt, comment); } diff --git a/src/slic3r/GUI/CreatePresetsDialog.cpp b/src/slic3r/GUI/CreatePresetsDialog.cpp index 063d1ce628..892576f0c0 100644 --- a/src/slic3r/GUI/CreatePresetsDialog.cpp +++ b/src/slic3r/GUI/CreatePresetsDialog.cpp @@ -3867,14 +3867,14 @@ void ExportConfigsDialog::select_curr_radiobox(std::vector<std::pair<RadioBox *, m_preset_sizer->Add(create_checkbox(m_presets_window, preset.second, printer_name, m_preset), 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(5)); } - m_serial_text->SetLabel(_L("Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip.")); + m_serial_text->SetLabel(_L("Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive.")); } else if (export_type == m_exprot_type.filament_preset) { for (std::pair<std::string, std::vector<std::pair<std::string, Preset *>>> filament_name_to_preset : m_filament_name_to_presets) { if (filament_name_to_preset.second.empty()) continue; wxString filament_name = wxString::FromUTF8(filament_name_to_preset.first); m_preset_sizer->Add(create_checkbox(m_presets_window, filament_name, m_printer_name), 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(5)); } - m_serial_text->SetLabel(_L("Only the filament names with user filament presets will be displayed, \nand all user filament presets in each filament name you select will be exported as a zip.")); + m_serial_text->SetLabel(_L("Only the filament names with user filament presets will be displayed, \nand all user filament presets in each filament name you select will be exported as a ZIP archive.")); } else if (export_type == m_exprot_type.process_preset) { for (std::pair<std::string, std::vector<Preset *>> presets : m_process_presets) { Preset * printer_preset = preset_bundle->printers.find_preset(presets.first, false); @@ -3890,7 +3890,7 @@ void ExportConfigsDialog::select_curr_radiobox(std::vector<std::pair<RadioBox *, } } - m_serial_text->SetLabel(_L("Only printer names with changed process presets will be displayed, \nand all user process presets in each printer name you select will be exported as a zip.")); + m_serial_text->SetLabel(_L("Only printer names with changed process presets will be displayed, \nand all user process presets in each printer name you select will be exported as a ZIP archive.")); } //m_presets_window->SetSizerAndFit(m_preset_sizer); m_presets_window->Layout(); diff --git a/src/slic3r/GUI/FilamentMapDialog.cpp b/src/slic3r/GUI/FilamentMapDialog.cpp index 12ca3a2965..7bb6f51421 100644 --- a/src/slic3r/GUI/FilamentMapDialog.cpp +++ b/src/slic3r/GUI/FilamentMapDialog.cpp @@ -241,7 +241,7 @@ FilamentMapDialog::FilamentMapDialog(wxWindow *parent, wxBoxSizer *mode_sizer = new wxBoxSizer(wxHORIZONTAL); - m_auto_btn = new CapsuleButton(this, PageType::ptAuto, only_saving_mode ? _L("Fila Saving") : _L("Auto"), false); + m_auto_btn = new CapsuleButton(this, PageType::ptAuto, only_saving_mode ? _L("File Saving") : _L("Auto"), false); m_manual_btn = new CapsuleButton(this, PageType::ptManual, _L("Custom"), false); if (show_default) m_default_btn = new CapsuleButton(this, PageType::ptDefault, _L("Same as Global"), true); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index a81cb72ab9..7b8912fe5b 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -2850,7 +2850,7 @@ void MainFrame::init_menubar_as_editor() [this](wxCommandEvent&) { if (m_plater) { m_plater->add_model(); } }, "", nullptr, [this](){return can_add_models(); }, this); #endif - append_menu_item(import_menu, wxID_ANY, _L("Import Zip Archive") + dots, _L("Load models contained within a zip archive"), + append_menu_item(import_menu, wxID_ANY, _L("Import ZIP Archive") + dots, _L("Load models contained within a ZIP archive"), [this](wxCommandEvent&) { if (m_plater) m_plater->import_zip_archive(); }, "menu_import", nullptr, [this]() { return can_add_models(); }); append_menu_item(import_menu, wxID_ANY, _L("Import Configs") + dots /*+ "\t" + ctrl + "I"*/, _L("Load configs"), diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 067b1fcd04..0347803dbc 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -9016,7 +9016,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_ if (!isUtf8StepFile) { const auto no_warn = wxGetApp().app_config->get_bool("step_not_utf8_no_warn"); if (!no_warn) { - MessageDialog dlg(nullptr, _L("Component name(s) inside step file not in UTF8 format!") + "\n\n" + _L("Because of unsupported text encoding, garbage characters may appear!"), + MessageDialog dlg(nullptr, _L("Component name(s) inside step file not in UTF-8 format!") + "\n\n" + _L("Because of unsupported text encoding, garbage characters may appear!"), wxString(SLIC3R_APP_FULL_NAME " - ") + _L("Attention!"), wxOK | wxICON_INFORMATION); dlg.show_dsa_button(_L("Remember my choice.")); dlg.ShowModal(); @@ -9129,7 +9129,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_ else if (model.looks_like_saved_in_meters()) { // BBS do not handle look like in meters MessageDialog dlg(q, - format_wxstr(_L("The object from file %s is too small, and may be in meters or inches.\n Do you want to scale to millimeters\?"), + format_wxstr(_L("The object from file %s is too small, and may be in meters or inches.\nDo you want to scale to millimeters\?"), from_path(filename)), _L("Object too small"), wxICON_QUESTION | wxYES_NO); int answer = dlg.ShowModal(); @@ -9137,7 +9137,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_ } else if (model.looks_like_imperial_units()) { // BBS do not handle look like in meters MessageDialog dlg(q, - format_wxstr(_L("The object from file %s is too small, and may be in meters or inches.\n Do you want to scale to millimeters\?"), + format_wxstr(_L("The object from file %s is too small, and may be in meters or inches.\nDo you want to scale to millimeters\?"), from_path(filename)), _L("Object too small"), wxICON_QUESTION | wxYES_NO); int answer = dlg.ShowModal(); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index d65d7f68bd..644c5258a1 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -8404,7 +8404,7 @@ void Tab::sync_excluder() } } if (config_to_apply.empty()) { - MessageDialog md(wxGetApp().plater(), _L("No modifications need to be copied."), _L("Copy paramters"), wxICON_INFORMATION | wxOK); + MessageDialog md(wxGetApp().plater(), _L("No modifications need to be copied."), _L("Copy parameters"), wxICON_INFORMATION | wxOK); md.ShowModal(); return; } @@ -8412,7 +8412,7 @@ void Tab::sync_excluder() std::string pt = m_preset_bundle->printers.get_edited_preset().get_printer_type(m_preset_bundle); std::string active_nozzle_name = DevPrinterConfigUtil::get_toolhead_display_name(pt, active_index, ToolHeadComponent::Nozzle, ToolHeadNameCase::LowerCase); std::string other_nozzle_name = DevPrinterConfigUtil::get_toolhead_display_name(pt, 1 - active_index, ToolHeadComponent::Nozzle, ToolHeadNameCase::LowerCase); - wxString title = wxString::Format(_L("Modify paramters of %s"), _L(active_nozzle_name)); + wxString title = wxString::Format(_L("Modify parameters of %s"), _L(active_nozzle_name)); wxString header = wxString::Format(_L("Do you want to modify the following parameters of the %s to that of the %s?"), _L(active_nozzle_name), _L(other_nozzle_name)); UnsavedChangesDialog dlg(title, header, &config_origin, from_index, dest_index, active_index == 0, active_nozzle); diff --git a/src/slic3r/GUI/TroubleshootDialog.cpp b/src/slic3r/GUI/TroubleshootDialog.cpp index c1dee7ca5c..a8c36eb975 100644 --- a/src/slic3r/GUI/TroubleshootDialog.cpp +++ b/src/slic3r/GUI/TroubleshootDialog.cpp @@ -226,7 +226,7 @@ TroubleshootDialog::TroubleshootDialog() }; auto info_desc_1 = create_info_line(_L("We need information for diagnosing source of the issue. Check wiki page for detailed guide.")); - auto info_desc_2 = create_info_line(_L("Pack button collects project file and logs of current session onto a zip file.")); + auto info_desc_2 = create_info_line(_L("Pack button collects project file and logs of current session onto a ZIP archive.")); auto info_desc_3 = create_info_line(_L("Any additional visual examples like images or screen recordings might be helpful while reporting the issue.")); wxBoxSizer *info_desc_sizer = new wxBoxSizer(wxVERTICAL); info_desc_sizer->Add(info_desc_1, 0, wxEXPAND | wxBOTTOM, FromDIP(8)); @@ -292,7 +292,7 @@ TroubleshootDialog::TroubleshootDialog() auto log_level_szr = create_label(_L("Log level"), ""); log_level_szr->Add(create_item_log_level_combo(), 0, wxALIGN_CENTER_VERTICAL); - auto log_pack_szr = create_label(_L("Stored logs"), _L("Packs all stored logs onto a zip file.")); + auto log_pack_szr = create_label(_L("Stored logs"), _L("Packs all stored logs onto a ZIP archive.")); auto log_pack_btn = create_btn(_L("Pack") + "...", ""); log_pack_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { auto data_dir = boost::filesystem::path(Slic3r::data_dir()); diff --git a/src/slic3r/Utils/3DPrinterOS.cpp b/src/slic3r/Utils/3DPrinterOS.cpp index b177e37e38..61fcc80d5b 100755 --- a/src/slic3r/Utils/3DPrinterOS.cpp +++ b/src/slic3r/Utils/3DPrinterOS.cpp @@ -323,7 +323,7 @@ bool C3DPrinterOS::login(wxString& msg) const msg.clear(); std::string token = get_api_auth_token(msg); if (token.empty()) { - msg = _L("Error. Can't get api token for authorization"); + msg = _L("Error. Can't get API token for authorization"); return false; } From b81c0e30c1c17c6e16c2f12f10488e6d649a87ef Mon Sep 17 00:00:00 2001 From: Ian Bassi <ian.bassi@outlook.com> Date: Wed, 2 Sep 2026 10:27:18 -0300 Subject: [PATCH 26/51] Localization update (#15497) * gettext * AI Translated * Update OrcaSlicer_es.po --- localization/i18n/OrcaSlicer.pot | 143 ++++++++++-- localization/i18n/ca/OrcaSlicer_ca.po | 219 +++++++++++++++--- localization/i18n/cs/OrcaSlicer_cs.po | 229 ++++++++++++++++--- localization/i18n/de/OrcaSlicer_de.po | 215 ++++++++++++++++-- localization/i18n/en/OrcaSlicer_en.po | 142 ++++++++++-- localization/i18n/es/OrcaSlicer_es.po | 180 +++++++++++++-- localization/i18n/eu/OrcaSlicer_eu.po | 215 ++++++++++++++++-- localization/i18n/fr/OrcaSlicer_fr.po | 227 ++++++++++++++++--- localization/i18n/hu/OrcaSlicer_hu.po | 215 ++++++++++++++++-- localization/i18n/it/OrcaSlicer_it.po | 215 ++++++++++++++++-- localization/i18n/ja/OrcaSlicer_ja.po | 235 +++++++++++++++++--- localization/i18n/ko/OrcaSlicer_ko.po | 227 ++++++++++++++++--- localization/i18n/lt/OrcaSlicer_lt.po | 215 ++++++++++++++++-- localization/i18n/nl/OrcaSlicer_nl.po | 233 ++++++++++++++++--- localization/i18n/pl/OrcaSlicer_pl.po | 227 ++++++++++++++++--- localization/i18n/pt_BR/OrcaSlicer_pt_BR.po | 215 ++++++++++++++++-- localization/i18n/ru/OrcaSlicer_ru.po | 215 ++++++++++++++++-- localization/i18n/sv/OrcaSlicer_sv.po | 233 ++++++++++++++++--- localization/i18n/th/OrcaSlicer_th.po | 219 +++++++++++++++--- localization/i18n/tr/OrcaSlicer_tr.po | 225 ++++++++++++++++--- localization/i18n/uk/OrcaSlicer_uk.po | 225 ++++++++++++++++--- localization/i18n/vi/OrcaSlicer_vi.po | 219 +++++++++++++++--- localization/i18n/zh_CN/OrcaSlicer_zh_CN.po | 216 +++++++++++++++--- localization/i18n/zh_TW/OrcaSlicer_zh_TW.po | 216 +++++++++++++++--- 24 files changed, 4459 insertions(+), 661 deletions(-) diff --git a/localization/i18n/OrcaSlicer.pot b/localization/i18n/OrcaSlicer.pot index 4f4e5079da..db62fb4443 100644 --- a/localization/i18n/OrcaSlicer.pot +++ b/localization/i18n/OrcaSlicer.pot @@ -3,11 +3,12 @@ # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # +#, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -2761,6 +2762,9 @@ msgstr "" msgid "Merge with" msgstr "" +msgid "Decompose Color" +msgstr "" + msgid "Delete this filament" msgstr "" @@ -3038,6 +3042,9 @@ msgstr "" msgid "Merge parts to an object" msgstr "" +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "" + msgid "Add layers" msgstr "" @@ -7402,6 +7409,9 @@ msgstr "" msgid "The %s nozzle can not print %s." msgstr "" +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "" + #, possible-boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "" @@ -7522,12 +7532,36 @@ msgstr "" msgid "Set filaments to use" msgstr "" +msgid "Add Mixed Filament" +msgstr "" + +msgid "Mixed Filament" +msgstr "" + +msgid "Remove last mixed filament" +msgstr "" + +msgid "Add mixed filament" +msgstr "" + +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "" + msgid "Search plate, object and part." msgstr "" msgid "Pellets" msgstr "" +msgid "Mixed filament has broken component references" +msgstr "" + +msgid "Edit / Delete / Merge" +msgstr "" + +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "" + #, possible-c-format, possible-boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "" @@ -7699,6 +7733,12 @@ msgstr "" msgid "Multi-part object detected" msgstr "" +msgid "Matching textures to filaments" +msgstr "" + +msgid "Texture Import Warning" +msgstr "" + msgid "Load these files as a single object with multiple parts?\n" msgstr "" @@ -7893,6 +7933,18 @@ msgstr "" msgid "Sync now" msgstr "" +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "" + +msgid "Applying texture colors..." +msgstr "" + +msgid "Updating 3D view..." +msgstr "" + +msgid "Texture colors applied." +msgstr "" + msgid "You can keep the modified presets for the new project or discard them" msgstr "" @@ -9042,6 +9094,9 @@ msgstr "" msgid "First layer filament sequence" msgstr "" +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "" + msgid "By Layer" msgstr "" @@ -10806,27 +10861,6 @@ msgstr "" msgid "Please choose the filament colour" msgstr "" -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "" - -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "" - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "" - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "" - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "" - msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "" @@ -11509,6 +11543,9 @@ msgstr "" msgid "No extrusions under current settings." msgstr "" +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "" + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "" @@ -11545,6 +11582,9 @@ msgstr "" msgid "Variable layer height is not supported with Organic supports." msgstr "" +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "" + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "" @@ -12957,6 +12997,7 @@ msgstr "" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "" +msgctxt "second" msgid "s" msgstr "" @@ -13250,6 +13291,48 @@ msgstr "" msgid "Support material is commonly used to print supports and support interfaces." msgstr "" +msgid "Is mixed filament" +msgstr "" + +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "" + +msgid "Mixed filament components" +msgstr "" + +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "" + +msgid "Mixed filament sublayer ratios" +msgstr "" + +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "" + +msgid "Mixed filament gradient" +msgstr "" + +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "" + +msgid "Mixed filament gradient range" +msgstr "" + +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "" + +msgid "Mixed filament gradient curve" +msgstr "" + +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "" + +msgid "Mixed filament per-part gradient" +msgstr "" + +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "" + msgid "Filament printable" msgstr "" @@ -14397,6 +14480,7 @@ msgstr "" msgid "The allowed maximum output force of Y axis" msgstr "" +msgctxt "Newton" msgid "N" msgstr "" @@ -14406,6 +14490,7 @@ msgstr "" msgid "The machine bed mass load of Y axis" msgstr "" +msgctxt "gram" msgid "g" msgstr "" @@ -15833,6 +15918,12 @@ msgid "" "Setting a value in the retract amount before wipe setting below will perform any excess retraction before the wipe, else it will be performed after." msgstr "" +msgid "Mixed color sublayer" +msgstr "" + +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "" + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "" @@ -16860,6 +16951,9 @@ msgstr "" msgid "The supplied file couldn't be read because it's empty." msgstr "" +msgid "The file format is incompatible and cannot be parsed." +msgstr "" + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "" @@ -18960,7 +19054,7 @@ msgstr "" msgid "Enable smart filament assign: Assign one filament to multiple nozzles to maximize savings" msgstr "" -msgid "Fila Saving" +msgid "File Saving" msgstr "" msgid "Don't remind me again" @@ -19320,6 +19414,9 @@ msgstr "" msgid "NO RAMMING AT ALL" msgstr "" +msgid "s" +msgstr "" + msgid "Volumetric speed" msgstr "" diff --git a/localization/i18n/ca/OrcaSlicer_ca.po b/localization/i18n/ca/OrcaSlicer_ca.po index 873cf0d7fb..2b42f300ac 100644 --- a/localization/i18n/ca/OrcaSlicer_ca.po +++ b/localization/i18n/ca/OrcaSlicer_ca.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: 2025-03-15 10:55+0100\n" "Last-Translator: \n" "Language-Team: \n" @@ -3015,6 +3015,10 @@ msgstr "Editar" msgid "Merge with" msgstr "Fusiona amb" +# AI Translated +msgid "Decompose Color" +msgstr "Descompondre el color" + msgid "Delete this filament" msgstr "Elimina aquest filament" @@ -3316,6 +3320,10 @@ msgstr "Muntatge" msgid "Merge parts to an object" msgstr "Fusionar les peces en un objecte" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "Utilitzar una alçada de capa variable juntament amb la subcapa de color mixt pot reduir la qualitat de la barreja de colors." + # AI Translated msgid "Add layers" msgstr "Afegir capes" @@ -7956,6 +7964,10 @@ msgstr "Personalitzar la placa actual" msgid "The %s nozzle can not print %s." msgstr "El broquet %s no pot imprimir %s." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "Imprimir filament de color mixt en una impressora d'un sol extrusor requereix canvis de filament i purgues freqüents, cosa que pot augmentar considerablement el malbaratament i el risc d'obstrucció del broquet o del conducte de residus." + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "No es recomana barrejar %1% amb %2% en la impressió.\n" @@ -8081,6 +8093,26 @@ msgstr "Sincronitzar la llista de filaments des d'AMS" msgid "Set filaments to use" msgstr "Configurar els filaments a utilitzar" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Afegir filament mixt" + +# AI Translated +msgid "Mixed Filament" +msgstr "Filament mixt" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Eliminar l'últim filament mixt" + +# AI Translated +msgid "Add mixed filament" +msgstr "Afegir filament mixt" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "El filament mixt té components no vàlids o incoherents. Torneu a editar les entrades afectades." + msgid "Search plate, object and part." msgstr "Cercar placa, objecte i peça." @@ -8088,6 +8120,18 @@ msgstr "Cercar placa, objecte i peça." msgid "Pellets" msgstr "Pèl·lets" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "El filament mixt té referències de components trencades" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Editar / Esborrar / Fusionar" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "El filament mixt de destinació utilitza aquest filament físic com a component. En fusionar-los s'eliminarà aquest filament físic i el filament mixt pot quedar no vàlid. Voleu continuar?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "En completar l'operació, el projecte %s es tancarà i es crearà un nou projecte." @@ -8275,6 +8319,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Objecte de múltiples peces detectat" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Associant les textures als filaments" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Avís d'importació de textures" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Carregar aquests fitxers com un sol objecte amb diverses peces?\n" @@ -8488,6 +8540,22 @@ msgstr "" msgid "Sync now" msgstr "Sincronitza ara" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "No s'ha pogut importar la textura. El model sembla contenir dades de textura, però el procés d'importació no s'ha pogut completar. El model s'importarà només com a geometria." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Aplicant els colors de textura..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "Actualitzant la vista 3D..." + +# AI Translated +msgid "Texture colors applied." +msgstr "Colors de textura aplicats." + msgid "You can keep the modified presets for the new project or discard them" msgstr "Podeu mantenir els perfils modificats al projecte nou o descartar-los" @@ -9780,6 +9848,10 @@ msgstr "Gerro en Espiral" msgid "First layer filament sequence" msgstr "Seqüència d'impressió de la primera capa" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "La llista de filaments conté filaments mixtos. La seqüència de filaments personalitzada no tindrà efecte." + msgid "By Layer" msgstr "Per Capa" @@ -11715,29 +11787,6 @@ msgstr "Volums de purga per al canvi de filament" msgid "Please choose the filament colour" msgstr "Trieu el color del filament" -# AI Translated -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "La visualització en directe nativa de Wayland requereix el sink de vídeo GTK de GStreamer. Instal·leu el connector gtksink per a GStreamer i reinicieu l'OrcaSlicer." - -# AI Translated -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "No s'ha pogut inicialitzar el sink de vídeo natiu de GStreamer per a Wayland. Comproveu la instal·lació del connector GTK de GStreamer." - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "El Windows Media Player és necessari per a aquesta tasca. Voleu habilitar el \"Windows Media Player\" per al vostre sistema operatiu?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource no s'ha registrat correctament per a la reproducció multimèdia! Premeu Sí per tornar-lo a registrar. Seràs promocionat dues vegades" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Falta el component BambuSource registrat per a la reproducció multimèdia! Reinstal·leu OrcaSlicer o cerqueu ajuda a la comunitat." - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Utilitzar un BambuSource des d'una instal·lació diferent, la reproducció de vídeo pot no funcionar correctament! Premeu Sí per solucionar-ho." - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "Al vostre sistema li falten còdecs H.264 per al GStreamer, necessaris per reproduir vídeo. (Proveu d'instal·lar els paquets gstreamer1.0-plugins-bad o gstreamer1.0-libav i, a continuació, reinicieu Orca Slicer?)" - # AI Translated msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "L'agent del núvol no està disponible. Reinicieu l'OrcaSlicer i torneu-ho a provar." @@ -12465,6 +12514,10 @@ msgstr "Si tot i així voleu imprimir, podeu activar l'opció a Preferències / msgid "No extrusions under current settings." msgstr "No hi ha extrusions a la configuració actual." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "S'està utilitzant un filament mixt amb degradat, però 'Subcapa de color mixt' està desactivat. El degradat no s'imprimirà." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "El mode suau de timelapse no està permès quan la seqüència \"Per objecte\" està habilitada." @@ -12501,6 +12554,10 @@ msgstr "Potser voleu reduir la mida del model o canviar la configuració d'impre msgid "Variable layer height is not supported with Organic supports." msgstr "Alçada de Capa Variable no és compatible amb suports Orgànics." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "El filament de la torre de purga no pot ser un filament mixt." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "És possible que els diferents diàmetres de broquet i els diferents diàmetres de filament no funcionin bé quan la torre principal està activada. És molt experimental, així que si us plau, procediu amb precaució." @@ -14263,6 +14320,8 @@ msgstr "Temps de capa" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "S'habilitarà el ventilador de refrigeració de peces per a capes el temps estimat de les quals sigui inferior a aquest valor. La velocitat del ventilador s'interpola entre les velocitats mínima i màxima del ventilador segons el temps d'impressió per capes" +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -14572,6 +14631,62 @@ msgstr "Material de suport" msgid "Support material is commonly used to print supports and support interfaces." msgstr "El material de suport s'utilitza habitualment per imprimir interfície de suport i suport" +# AI Translated +msgid "Is mixed filament" +msgstr "És filament mixt" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Indica si aquesta ranura de filament és un filament mixt compost per diversos filaments físics" + +# AI Translated +msgid "Mixed filament components" +msgstr "Components del filament mixt" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Índexs (començant per 1) dels filaments components, separats per comes; p. ex. \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Proporcions de subcapa del filament mixt" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Valors de proporció separats per comes que sumin 1.0; p. ex. \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Degradat del filament mixt" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Activa el mode de degradat en direcció Z per a les subcapes del filament mixt. En activar-lo, les proporcions de les subcapes varien linealment entre capes." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Rang del degradat del filament mixt" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Proporcions inicial i final del primer component en el mode de degradat. Parell separat per comes; p. ex. \"0.10,0.90\" significa del 10% al 90%." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Corba del degradat del filament mixt" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Corba personalitzada opcional, a l'estil de Photoshop, que assigna el progrés en Z a la proporció del primer component. Es codifica com a punts de control separats per barres verticals, amb el format \"x,y\" (heretat) o \"x,y,m_in,m_out\" quan cal anul·lar la tangent (un valor buit o \"nan\" fa servir el valor PCHIP predeterminat). x està dins de [0,1]; y es limita al rang de proporcions configurat; p. ex. \"0,0.15|0.5,0.50|1,0.85\". Si es deixa buit, s'utilitza el gradient_range lineal." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Degradat per peça del filament mixt" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Quan el mode de degradat està activat, aplica el degradat a cada peça d'un muntatge de manera independent en lloc de tractar tot el muntatge com un únic rang Z." + msgid "Filament printable" msgstr "Filament imprimible" @@ -15860,6 +15975,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "Força de sortida màxima permesa de l'eix Y" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -15872,6 +15988,7 @@ msgid "The machine bed mass load of Y axis" msgstr "Càrrega de massa del llit de la màquina a l'eix Y" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -17482,6 +17599,14 @@ msgstr "" "\n" "L'establiment d'un valor en la quantitat de retractació abans de l'esborrat es realitzarà qualsevol retracció en excés abans de la neteja, sinó es realitzarà després." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Subcapa de color mixt" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Activa la divisió en subcapes de color mixt. En activar-la, les capes que contenen filaments de color mixt es divideixen en subcapes per aconseguir efectes de barreja de colors." + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "La Torre de Purga es pot utilitzar per netejar els residus al broquet i estabilitzar la pressió de la cambra dins del broquet, per tal d'evitar defectes d'aparença en imprimir objectes." @@ -18573,6 +18698,10 @@ msgstr "La generació de malla del fitxer del model ha fallat o la forma no és msgid "The supplied file couldn't be read because it's empty." msgstr "El fitxer subministrat no s'ha pogut llegir perquè està buit" +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "El format del fitxer és incompatible i no es pot analitzar." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Format de fitxer desconegut. El fitxer d'entrada ha de tenir extensió .stl, .obj, .amf( .xml )." @@ -20928,8 +21057,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "Activar l'assignació intel·ligent de filament: assigna un filament a diversos broquets per maximitzar l'estalvi" # AI Translated -msgid "Fila Saving" -msgstr "Estalvi de filament" +msgid "File Saving" +msgstr "Desament de fitxers" msgid "Don't remind me again" msgstr "No m'ho recordis més" @@ -21338,6 +21467,9 @@ msgstr "Reinicia ara" msgid "NO RAMMING AT ALL" msgstr "SENSE EMPENTA" +msgid "s" +msgstr "s" + msgid "Volumetric speed" msgstr "Velocitat volumètrica" @@ -21989,6 +22121,41 @@ msgstr "" "Evitar la deformació( warping )\n" "Sabíeu que quan imprimiu materials propensos a deformar-se, com ara l'ABS, augmentar adequadament la temperatura del llit pot reduir la probabilitat de deformació?" +# AI Translated +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "La visualització en directe nativa de Wayland requereix el sink de vídeo GTK de GStreamer. Instal·leu el connector gtksink per a GStreamer i reinicieu l'OrcaSlicer." + +# AI Translated +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "No s'ha pogut inicialitzar el sink de vídeo natiu de GStreamer per a Wayland. Comproveu la instal·lació del connector GTK de GStreamer." + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "El Windows Media Player és necessari per a aquesta tasca. Voleu habilitar el \"Windows Media Player\" per al vostre sistema operatiu?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource no s'ha registrat correctament per a la reproducció multimèdia! Premeu Sí per tornar-lo a registrar. Seràs promocionat dues vegades" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "Falta el component BambuSource registrat per a la reproducció multimèdia! Reinstal·leu OrcaSlicer o cerqueu ajuda a la comunitat." + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "Utilitzar un BambuSource des d'una instal·lació diferent, la reproducció de vídeo pot no funcionar correctament! Premeu Sí per solucionar-ho." + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "Al vostre sistema li falten còdecs H.264 per al GStreamer, necessaris per reproduir vídeo. (Proveu d'instal·lar els paquets gstreamer1.0-plugins-bad o gstreamer1.0-libav i, a continuació, reinicieu Orca Slicer?)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "Estalvi de filament" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/cs/OrcaSlicer_cs.po b/localization/i18n/cs/OrcaSlicer_cs.po index f51c5dc3e2..d2ef18cd2a 100644 --- a/localization/i18n/cs/OrcaSlicer_cs.po +++ b/localization/i18n/cs/OrcaSlicer_cs.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: \n" "Last-Translator: Jakub Hencl\n" "Language-Team: \n" @@ -2977,6 +2977,10 @@ msgstr "Upravit" msgid "Merge with" msgstr "Sloučit s" +# AI Translated +msgid "Decompose Color" +msgstr "Rozložit barvu" + msgid "Delete this filament" msgstr "Smazat tento filament" @@ -3279,6 +3283,10 @@ msgstr "Sestava" msgid "Merge parts to an object" msgstr "Sloučit části do objektu" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "Použití proměnné výšky vrstvy společně s podvrstvou míchané barvy může zhoršit kvalitu míchání barev." + # AI Translated msgid "Add layers" msgstr "Přidat vrstvy" @@ -7921,6 +7929,10 @@ msgstr "Přizpůsobit aktuální desku" msgid "The %s nozzle can not print %s." msgstr "Tryska %s nemůže tisknout %s." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "Tisk filamentu s míchanou barvou na tiskárně s jedním extruderem vyžaduje časté výměny filamentu a čištění, což může výrazně zvýšit množství odpadu a riziko ucpání trysky nebo odpadního skluzu." + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "Míchání %1% s %2% při tisku není doporučeno.\n" @@ -8050,12 +8062,44 @@ msgstr "Synchronizovat seznam filamentů z AMS" msgid "Set filaments to use" msgstr "Nastavit používané filamenty" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Přidat míchaný filament" + +# AI Translated +msgid "Mixed Filament" +msgstr "Míchaný filament" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Odebrat poslední míchaný filament" + +# AI Translated +msgid "Add mixed filament" +msgstr "Přidat míchaný filament" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "Míchaný filament má neplatné nebo neodpovídající komponenty. Upravte prosím dotčené položky znovu." + msgid "Search plate, object and part." msgstr "Hledat desku, objekt a díl." msgid "Pellets" msgstr "Pelety" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "Míchaný filament má poškozené odkazy na komponenty" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Upravit / Smazat / Sloučit" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "Cílový míchaný filament používá tento fyzický filament jako komponentu. Sloučením se tento fyzický filament odstraní a míchaný filament může přestat být platný. Pokračovat?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "Po dokončení operace bude projekt %s uzavřen a bude vytvořen nový projekt." @@ -8237,6 +8281,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Detekován vícedílný objekt" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Přiřazování textur k filamentům" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Upozornění při importu textury" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Načíst tyto soubory jako jeden objekt s více částmi?\n" @@ -8447,6 +8499,22 @@ msgstr "" msgid "Sync now" msgstr "Synchronizovat nyní" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "Import textury se nezdařil. Zdá se, že model obsahuje data textury, ale proces importu nebylo možné dokončit. Model bude importován pouze jako geometrie." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Aplikují se barvy textury..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "Aktualizuje se 3D náhled..." + +# AI Translated +msgid "Texture colors applied." +msgstr "Barvy textury byly použity." + msgid "You can keep the modified presets for the new project or discard them" msgstr "Upravené předvolby můžete ponechat v novém projektu nebo je zahodit" @@ -9728,6 +9796,10 @@ msgstr "Spirálová váza" msgid "First layer filament sequence" msgstr "Pořadí filamentů v první vrstvě" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "Seznam filamentů obsahuje míchané filamenty. Vlastní pořadí filamentů se neuplatní." + msgid "By Layer" msgstr "Podle vrstvy" @@ -11697,34 +11769,6 @@ msgstr "Objemy čištění při výměně filamentu" msgid "Please choose the filament colour" msgstr "Vyberte prosím barvu filamentu" -# AI Translated -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "Nativní živý náhled ve Waylandu vyžaduje video sink GStreamer GTK. Nainstalujte prosím plugin gtksink pro GStreamer a poté restartujte OrcaSlicer." - -# AI Translated -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Nepodařilo se inicializovat nativní video sink GStreamer pro Wayland. Zkontrolujte prosím instalaci pluginu GStreamer GTK." - -# AI Translated -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "Pro tuto úlohu je vyžadován Windows Media Player! Chcete ve svém operačním systému povolit „Windows Media Player“?" - -# AI Translated -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource nebyl správně zaregistrován pro přehrávání médií! Stisknutím Ano jej znovu zaregistrujete. Budete vyzváni dvakrát" - -# AI Translated -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Chybí komponenta BambuSource registrovaná pro přehrávání médií! Přeinstalujte prosím OrcaSlicer nebo požádejte o pomoc komunitu." - -# AI Translated -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Používá se BambuSource z jiné instalace, přehrávání videa nemusí fungovat správně! Stisknutím Ano to opravíte." - -# AI Translated -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "Ve vašem systému chybí kodeky H.264 pro GStreamer, které jsou nutné k přehrávání videa. (Zkuste nainstalovat balíčky gstreamer1.0-plugins-bad nebo gstreamer1.0-libav a poté restartovat Orca Slicer?)" - # AI Translated msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "Cloudový agent není dostupný. Restartujte prosím OrcaSlicer a zkuste to znovu." @@ -12446,6 +12490,10 @@ msgstr "Pokud chcete přesto tisknout, můžete povolit možnost v Nastavení / msgid "No extrusions under current settings." msgstr "Při aktuálním nastavení nejsou žádné extruze." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "Je použit míchaný filament s gradientem, ale 'Podvrstva míchané barvy' je vypnutá. Gradient nebude vytištěn." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "Plynulý režim časosběru není podporován, pokud je povoleno pořadí tisku „podle objektu“." @@ -12482,6 +12530,10 @@ msgstr "Možná budete chtít zmenšit velikost modelu nebo změnit aktuální n msgid "Variable layer height is not supported with Organic supports." msgstr "Proměnná výška vrstvy není podporována s organickými podporami." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "Filament věže na očištění trysky nemůže být míchaný filament." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Různé průměry trysek a filamentu nemusí správně fungovat, pokud je povolena základní věž. Jedná se o velmi experimentální funkci, proto pokračujte opatrně." @@ -14232,6 +14284,8 @@ msgstr "Čas vrstvy" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "Ventilátor chlazení části bude spuštěn u vrstev, jejichž odhadovaný čas je kratší než tato hodnota. Rychlost ventilátoru je interpolována mezi minimální a maximální podle času tisku vrstvy." +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -14540,6 +14594,62 @@ msgstr "Podpůrný materiál" msgid "Support material is commonly used to print supports and support interfaces." msgstr "Podpůrný materiál se běžně používá pro tisk podpěr a rozhraní podpěr." +# AI Translated +msgid "Is mixed filament" +msgstr "Je míchaný filament" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Určuje, zda je tato pozice filamentu míchaným filamentem složeným z několika fyzických filamentů" + +# AI Translated +msgid "Mixed filament components" +msgstr "Komponenty míchaného filamentu" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Čárkami oddělené indexy komponentních filamentů počítané od 1, např. \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Poměry podvrstev míchaného filamentu" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Čárkami oddělené hodnoty poměrů, jejichž součet je 1.0, např. \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Gradient míchaného filamentu" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Zapne režim gradientu ve směru Z pro podvrstvy míchaného filamentu. Je-li zapnutý, poměry podvrstev se mění lineárně napříč vrstvami." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Rozsah gradientu míchaného filamentu" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Počáteční a koncový poměr první komponenty v režimu gradientu. Dvojice oddělená čárkou, např. \"0.10,0.90\" znamená 10% až 90%." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Křivka gradientu míchaného filamentu" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Volitelná vlastní křivka ve stylu Photoshopu, která mapuje postup v ose Z na poměr první komponenty. Zapisuje se jako řídicí body oddělené svislými čarami, buď ve tvaru \"x,y\" (starší formát), nebo \"x,y,m_in,m_out\", pokud je potřeba přepsat tečnu (prázdná hodnota nebo \"nan\" použije výchozí PCHIP). x je v intervalu [0,1]; y je omezeno na nastavený rozsah poměrů, např. \"0,0.15|0.5,0.50|1,0.85\". Pokud je pole prázdné, použije se lineární gradient_range." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Gradient míchaného filamentu podle dílu" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Je-li zapnutý režim gradientu, aplikuje gradient na každý díl sestavy samostatně místo toho, aby se celá sestava brala jako jeden rozsah Z." + msgid "Filament printable" msgstr "Tisknutelný filament" @@ -15816,6 +15926,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "Povolená maximální výstupní síla osy Y" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -15828,6 +15939,7 @@ msgid "The machine bed mass load of Y axis" msgstr "Zatížení osy Y hmotností podložky stroje" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -17427,6 +17539,14 @@ msgstr "" "\n" "Nastavení hodnoty v parametru množství retrakce před očištěním níže provede případnou dodatečnou retrakci před očištěním, jinak bude provedena po něm." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Podvrstva míchané barvy" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Zapne dělení na podvrstvy míchané barvy. Je-li zapnuto, vrstvy obsahující filamenty s míchanou barvou se rozdělí na podvrstvy, aby vznikl efekt míchání barev." + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "Čistící věž lze použít k odstranění zbytků materiálu na trysce a ke stabilizaci tlaku v komoře trysky, aby se předešlo vizuálním vadám při tisku objektů." @@ -18500,6 +18620,10 @@ msgstr "Síťování modelového souboru selhalo nebo nebyl nalezen platný tvar msgid "The supplied file couldn't be read because it's empty." msgstr "Zadaný soubor nelze načíst, protože je prázdný." +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "Formát souboru není kompatibilní a nelze jej načíst." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Neznámý formát souboru. Vstupní soubor musí mít příponu .stl, .obj nebo .amf(.xml)." @@ -20851,8 +20975,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "Povolit chytré přiřazení filamentu: přiřadit jeden filament více tryskám pro maximální úsporu" # AI Translated -msgid "Fila Saving" -msgstr "Úspora filamentu" +msgid "File Saving" +msgstr "Ukládání souboru" # AI Translated msgid "Don't remind me again" @@ -21308,6 +21432,9 @@ msgstr "Restartovat nyní" msgid "NO RAMMING AT ALL" msgstr "ŽÁDNÝ RAMMING" +msgid "s" +msgstr "s" + # AI Translated msgid "Volumetric speed" msgstr "Objemová rychlost" @@ -21975,6 +22102,46 @@ msgstr "" "Zamezte kroucení\n" "Víte, že při tisku materiálů náchylných ke kroucení, jako je ABS, může vhodné zvýšení teploty vyhřívané desky snížit pravděpodobnost kroucení?" +# AI Translated +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "Nativní živý náhled ve Waylandu vyžaduje video sink GStreamer GTK. Nainstalujte prosím plugin gtksink pro GStreamer a poté restartujte OrcaSlicer." + +# AI Translated +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "Nepodařilo se inicializovat nativní video sink GStreamer pro Wayland. Zkontrolujte prosím instalaci pluginu GStreamer GTK." + +# AI Translated +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "Pro tuto úlohu je vyžadován Windows Media Player! Chcete ve svém operačním systému povolit „Windows Media Player“?" + +# AI Translated +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource nebyl správně zaregistrován pro přehrávání médií! Stisknutím Ano jej znovu zaregistrujete. Budete vyzváni dvakrát" + +# AI Translated +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "Chybí komponenta BambuSource registrovaná pro přehrávání médií! Přeinstalujte prosím OrcaSlicer nebo požádejte o pomoc komunitu." + +# AI Translated +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "Používá se BambuSource z jiné instalace, přehrávání videa nemusí fungovat správně! Stisknutím Ano to opravíte." + +# AI Translated +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "Ve vašem systému chybí kodeky H.264 pro GStreamer, které jsou nutné k přehrávání videa. (Zkuste nainstalovat balíčky gstreamer1.0-plugins-bad nebo gstreamer1.0-libav a poté restartovat Orca Slicer?)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "Úspora filamentu" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/de/OrcaSlicer_de.po b/localization/i18n/de/OrcaSlicer_de.po index 8b27148a03..4ff61fb6ea 100644 --- a/localization/i18n/de/OrcaSlicer_de.po +++ b/localization/i18n/de/OrcaSlicer_de.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: \n" "Last-Translator: Heiko Liebscher <hliebschergmail.com>\n" "Language-Team: \n" @@ -2917,6 +2917,10 @@ msgstr "Bearbeiten" msgid "Merge with" msgstr "Zusammenführen mit" +# AI Translated +msgid "Decompose Color" +msgstr "Farbe zerlegen" + msgid "Delete this filament" msgstr "Diesen Filament löschen" @@ -3216,6 +3220,10 @@ msgstr "Zusammenbau" msgid "Merge parts to an object" msgstr "Teile zu einem Objekt zusammenführen" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "Die Verwendung einer variablen Schichthöhe zusammen mit der Mischfarben-Unterschicht kann zu einer schlechten Farbmischqualität führen." + # AI Translated msgid "Add layers" msgstr "Schichten hinzufügen" @@ -7791,6 +7799,10 @@ msgstr "Aktuelle Platte anpassen" msgid "The %s nozzle can not print %s." msgstr "Die %s Düse kann %s nicht drucken." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "Der Druck von Mischfarben-Filament auf einem Drucker mit nur einem Extruder erfordert häufige Filamentwechsel und Spülvorgänge, was den Abfall und das Risiko einer Verstopfung von Düse bzw. Abfallschacht deutlich erhöhen kann." + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "Mischen von %1% mit %2% im Druck wird nicht empfohlen.\n" @@ -7916,6 +7928,26 @@ msgstr "Filamentliste von AMS synchronisieren" msgid "Set filaments to use" msgstr "Zu verwendende Filamente einstellen" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Mischfilament hinzufügen" + +# AI Translated +msgid "Mixed Filament" +msgstr "Mischfilament" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Letztes Mischfilament entfernen" + +# AI Translated +msgid "Add mixed filament" +msgstr "Mischfilament hinzufügen" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "Das Mischfilament enthält ungültige oder nicht zusammenpassende Komponenten. Bitte bearbeiten Sie die betroffenen Einträge erneut." + msgid "Search plate, object and part." msgstr "Suche Platte, Objekt und Teil." @@ -7923,6 +7955,18 @@ msgstr "Suche Platte, Objekt und Teil." msgid "Pellets" msgstr "Pellets" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "Das Mischfilament enthält ungültige Komponentenverweise" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Bearbeiten / Löschen / Zusammenführen" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "Das Ziel-Mischfilament verwendet dieses physische Filament als Komponente. Beim Zusammenführen wird dieses physische Filament entfernt und das Mischfilament kann dadurch ungültig werden. Fortfahren?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "Nach Abschluss Ihrer Operation wird das %s-Projekt geschlossen und ein neues Projekt erstellt." @@ -8106,6 +8150,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Mehrteiliges Objekt erkannt" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Texturen werden den Filamenten zugeordnet" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Warnung beim Texturimport" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Diese Dateien als ein einziges Objekt mit mehreren Teilen laden?\n" @@ -8319,6 +8371,22 @@ msgstr "" msgid "Sync now" msgstr "Jetzt synchronisieren" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "Der Texturimport ist fehlgeschlagen. Das Modell scheint Texturdaten zu enthalten, der Importvorgang konnte jedoch nicht abgeschlossen werden. Das Modell wird nur als Geometrie importiert." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Texturfarben werden angewendet..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "3D-Ansicht wird aktualisiert..." + +# AI Translated +msgid "Texture colors applied." +msgstr "Texturfarben angewendet." + # AI Translated msgid "You can keep the modified presets for the new project or discard them" msgstr "Sie können die geänderten Profile für das neue Projekt beibehalten oder sie verwerfen" @@ -9563,6 +9631,10 @@ msgstr "Vasenmodus" msgid "First layer filament sequence" msgstr "Erste Filament-Schichtsequenz" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "Die Filamentliste enthält Mischfilamente. Die benutzerdefinierte Filamentreihenfolge wird nicht wirksam." + msgid "By Layer" msgstr "Nach Schicht" @@ -11460,27 +11532,6 @@ msgstr "Reinigungsvolumen für Filamentwechsel" msgid "Please choose the filament colour" msgstr "Bitte wählen Sie die Filamentfarbe" -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "Native Wayland Liveview erfordert das GStreamer GTK Video Sink. Bitte installieren Sie das gtksink-Plugin für GStreamer und starten Sie OrcaSlicer neu." - -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Fehler beim Initialisieren des nativen Wayland GStreamer Video Sinks. Bitte überprüfen Ihre GStreamer GTK-Plugin-Installation." - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "Windows Media Player wird für diese Aufgabe benötigt! Möchten Sie 'Windows Media Player' für Ihr Betriebssystem aktivieren?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource wurde nicht korrekt für das Abspielen von Medien registriert! Drücken Sie Ja, um es erneut zu registrieren. Sie werden zweimal aufgefordert" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Fehlende BambuSource-Komponente, die für das Abspielen von Medien registriert ist! Bitte installieren Sie OrcaSlicer neu oder suchen Sie Hilfe in der Community." - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Verwendung eines BambuSource aus einer anderen Installation, das Abspielen von Videos funktioniert möglicherweise nicht korrekt! Drücken Sie Ja, um es zu beheben." - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "Ihr System fehlt H.264-Codecs für GStreamer, die zum Abspielen von Videos erforderlich sind. (Versuchen Sie, die Pakete gstreamer1.0-plugins-bad oder gstreamer1.0-libav zu installieren und starten Sie Orca Slicer neu?)" - msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "Cloud-Agent ist nicht verfügbar. Bitte starten Sie OrcaSlicer neu und versuchen Sie es erneut." @@ -12185,6 +12236,10 @@ msgstr "Wenn Sie trotzdem drucken möchten, können Sie die Option in Einstellun msgid "No extrusions under current settings." msgstr "Keine Extrusion unter den aktuellen Einstellungen." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "Es wird ein Mischfilament mit Verlauf verwendet, aber „Mischfarben-Unterschicht“ ist deaktiviert. Der Verlauf wird nicht gedruckt." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "Der gewählte Zeitraffermodus wird nicht unterstützt, wenn die Sequenz \"nach Objekt\" aktiviert ist." @@ -12221,6 +12276,10 @@ msgstr "Sie möchten möglicherweise die Größe Ihres Modells reduzieren oder d msgid "Variable layer height is not supported with Organic supports." msgstr "Variable Schichthöhe wird nicht mit organischen Stützstrukturen unterstützt." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "Das Filament des Reinigungsturms darf kein Mischfilament sein." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Unterschiedliche Düsendurchmesser und unterschiedliche Filamentdurchmesser funktionieren möglicherweise nicht gut, wenn der Reinigungsturm aktiviert ist. Es ist sehr experimentell, also gehen Sie bitte vorsichtig vor." @@ -13934,6 +13993,8 @@ msgstr "Schichtdauer" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "Der Bauteillüfter wird für Schichten aktiviert, deren geschätzte Zeit kürzer als dieser Wert ist. Die Lüftergeschwindigkeit wird zwischen der minimalen und maximalen Geschwindigkeit entsprechend der Druckzeit der Schicht interpoliert." +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -14238,6 +14299,62 @@ msgstr "Stützmaterial" msgid "Support material is commonly used to print supports and support interfaces." msgstr "Stützmaterial wird üblicherweise zum Drucken von Stützen und Stütz-Schnittstellen verwendet." +# AI Translated +msgid "Is mixed filament" +msgstr "Ist Mischfilament" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Gibt an, ob dieser Filamentplatz ein Mischfilament aus mehreren physischen Filamenten ist" + +# AI Translated +msgid "Mixed filament components" +msgstr "Komponenten des Mischfilaments" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Durch Kommas getrennte Indizes der Komponentenfilamente, beginnend bei 1, z. B. \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Unterschicht-Anteile des Mischfilaments" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Durch Kommas getrennte Anteilswerte, die in der Summe 1.0 ergeben, z. B. \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Verlauf des Mischfilaments" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Aktiviert den Verlaufsmodus in Z-Richtung für die Unterschichten des Mischfilaments. Wenn aktiviert, ändern sich die Anteile der Unterschichten linear über die Schichten hinweg." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Verlaufsbereich des Mischfilaments" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Start- und Endanteil der ersten Komponente im Verlaufsmodus. Durch Komma getrenntes Paar, z. B. \"0.10,0.90\" bedeutet 10% bis 90%." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Verlaufskurve des Mischfilaments" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Optionale benutzerdefinierte Kurve im Photoshop-Stil, die den Z-Fortschritt auf den Anteil der ersten Komponente abbildet. Kodiert als durch senkrechte Striche getrennte Kontrollpunkte, entweder \"x,y\" (veraltet) oder \"x,y,m_in,m_out\", wenn die Tangente überschrieben werden soll (ein leerer Wert oder \"nan\" verwendet den PCHIP-Standard). x liegt in [0,1]; y wird auf den konfigurierten Anteilsbereich begrenzt, z. B. \"0,0.15|0.5,0.50|1,0.85\". Bleibt das Feld leer, wird stattdessen der lineare gradient_range verwendet." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Verlauf pro Teil beim Mischfilament" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Wenn der Verlaufsmodus aktiviert ist, wird der Verlauf auf jedes Teil eines Zusammenbaus einzeln angewendet, anstatt den gesamten Zusammenbau als einen einzigen Z-Bereich zu behandeln." + msgid "Filament printable" msgstr "Filament druckbar" @@ -15478,6 +15595,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "Die maximal zulässige Ausgangskraft der Y-Achse" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -15488,6 +15606,7 @@ msgid "The machine bed mass load of Y axis" msgstr "Die Maschinenbett-Massenlast der Y-Achse" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -17070,6 +17189,14 @@ msgstr "" "\n" "Wenn ein Wert in der Einstellung \"Rückzugsmenge vor dem Wischen\" unten angegeben ist, wird ein überschüssiger Rückzug vor dem Wischen ausgeführt, ansonsten wird er danach ausgeführt." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Mischfarben-Unterschicht" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Aktiviert die Aufteilung in Mischfarben-Unterschichten. Wenn aktiviert, werden Schichten mit Mischfarben-Filamenten in Unterschichten aufgeteilt, um Farbmischeffekte zu erzielen." + # AI Translated msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "Der Reinigungsturm kann verwendet werden, um Rückstände auf der Düse zu entfernen und den Kammerdruck im Inneren der Düse zu stabilisieren, um Erscheinungsdefekte beim Drucken von Objekten zu vermeiden." @@ -18140,6 +18267,10 @@ msgstr "Das Erstellen eines Netzes aus der Modelldatei ist fehlgeschlagen oder e msgid "The supplied file couldn't be read because it's empty." msgstr "Die angegebene Datei konnte nicht gelesen werden, weil sie leer ist." +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "Das Dateiformat ist nicht kompatibel und kann nicht gelesen werden." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Unbekanntes Dateiformat: Die Eingabedatei muss die Endung .stl, .obj oder .amf(.xml) haben." @@ -20398,8 +20529,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "Intelligente Filamentzuweisung aktivieren: Ein Filament mehreren Düsen zuweisen, um Einsparungen zu maximieren" # AI Translated -msgid "Fila Saving" -msgstr "Filamentersparnis" +msgid "File Saving" +msgstr "Datei speichern" msgid "Don't remind me again" msgstr "Nicht mehr erinnern" @@ -20764,6 +20895,9 @@ msgstr "Jetzt neu starten" msgid "NO RAMMING AT ALL" msgstr "KEIN RAMMING ÜBERALL" +msgid "s" +msgstr "s" + msgid "Volumetric speed" msgstr "Volumetrische Geschwindigkeit" @@ -21388,6 +21522,39 @@ msgstr "" "Verwerfungen vermeiden\n" "Wussten Sie, dass beim Drucken von Materialien, die zu Verwerfungen neigen, wie z.B. ABS, durch eine entsprechende Erhöhung der Heizbetttemperatur die Wahrscheinlichkeit von Verwerfungen verringert werden kann?" +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "Native Wayland Liveview erfordert das GStreamer GTK Video Sink. Bitte installieren Sie das gtksink-Plugin für GStreamer und starten Sie OrcaSlicer neu." + +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "Fehler beim Initialisieren des nativen Wayland GStreamer Video Sinks. Bitte überprüfen Ihre GStreamer GTK-Plugin-Installation." + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "Windows Media Player wird für diese Aufgabe benötigt! Möchten Sie 'Windows Media Player' für Ihr Betriebssystem aktivieren?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource wurde nicht korrekt für das Abspielen von Medien registriert! Drücken Sie Ja, um es erneut zu registrieren. Sie werden zweimal aufgefordert" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "Fehlende BambuSource-Komponente, die für das Abspielen von Medien registriert ist! Bitte installieren Sie OrcaSlicer neu oder suchen Sie Hilfe in der Community." + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "Verwendung eines BambuSource aus einer anderen Installation, das Abspielen von Videos funktioniert möglicherweise nicht korrekt! Drücken Sie Ja, um es zu beheben." + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "Ihr System fehlt H.264-Codecs für GStreamer, die zum Abspielen von Videos erforderlich sind. (Versuchen Sie, die Pakete gstreamer1.0-plugins-bad oder gstreamer1.0-libav zu installieren und starten Sie Orca Slicer neu?)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "Filamentersparnis" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/en/OrcaSlicer_en.po b/localization/i18n/en/OrcaSlicer_en.po index 0d0d0e2ddb..67d4d196d4 100644 --- a/localization/i18n/en/OrcaSlicer_en.po +++ b/localization/i18n/en/OrcaSlicer_en.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: 2026-06-17 15:44-0300\n" "Last-Translator: Alexandre Folle de Menezes\n" "Language-Team: \n" @@ -2758,6 +2758,9 @@ msgstr "" msgid "Merge with" msgstr "" +msgid "Decompose Color" +msgstr "" + msgid "Delete this filament" msgstr "" @@ -3035,6 +3038,9 @@ msgstr "" msgid "Merge parts to an object" msgstr "" +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "" + msgid "Add layers" msgstr "" @@ -7399,6 +7405,9 @@ msgstr "" msgid "The %s nozzle can not print %s." msgstr "" +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "" + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "" @@ -7519,12 +7528,36 @@ msgstr "" msgid "Set filaments to use" msgstr "" +msgid "Add Mixed Filament" +msgstr "" + +msgid "Mixed Filament" +msgstr "" + +msgid "Remove last mixed filament" +msgstr "" + +msgid "Add mixed filament" +msgstr "" + +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "" + msgid "Search plate, object and part." msgstr "" msgid "Pellets" msgstr "" +msgid "Mixed filament has broken component references" +msgstr "" + +msgid "Edit / Delete / Merge" +msgstr "" + +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "" @@ -7696,6 +7729,12 @@ msgstr "" msgid "Multi-part object detected" msgstr "" +msgid "Matching textures to filaments" +msgstr "" + +msgid "Texture Import Warning" +msgstr "" + msgid "Load these files as a single object with multiple parts?\n" msgstr "" @@ -7890,6 +7929,18 @@ msgstr "" msgid "Sync now" msgstr "" +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "" + +msgid "Applying texture colors..." +msgstr "" + +msgid "Updating 3D view..." +msgstr "" + +msgid "Texture colors applied." +msgstr "" + msgid "You can keep the modified presets for the new project or discard them" msgstr "" @@ -9039,6 +9090,9 @@ msgstr "" msgid "First layer filament sequence" msgstr "" +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "" + msgid "By Layer" msgstr "" @@ -10803,27 +10857,6 @@ msgstr "" msgid "Please choose the filament colour" msgstr "" -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "" - -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "" - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "" - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "" - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "" - msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "" @@ -11506,6 +11539,9 @@ msgstr "" msgid "No extrusions under current settings." msgstr "" +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "" + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "" @@ -11542,6 +11578,9 @@ msgstr "" msgid "Variable layer height is not supported with Organic supports." msgstr "" +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "" + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "" @@ -12954,6 +12993,7 @@ msgstr "" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "" +msgctxt "second" msgid "s" msgstr "" @@ -13247,6 +13287,48 @@ msgstr "" msgid "Support material is commonly used to print supports and support interfaces." msgstr "" +msgid "Is mixed filament" +msgstr "" + +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "" + +msgid "Mixed filament components" +msgstr "" + +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "" + +msgid "Mixed filament sublayer ratios" +msgstr "" + +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "" + +msgid "Mixed filament gradient" +msgstr "" + +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "" + +msgid "Mixed filament gradient range" +msgstr "" + +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "" + +msgid "Mixed filament gradient curve" +msgstr "" + +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "" + +msgid "Mixed filament per-part gradient" +msgstr "" + +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "" + msgid "Filament printable" msgstr "" @@ -14394,6 +14476,7 @@ msgstr "" msgid "The allowed maximum output force of Y axis" msgstr "" +msgctxt "Newton" msgid "N" msgstr "" @@ -14403,6 +14486,7 @@ msgstr "" msgid "The machine bed mass load of Y axis" msgstr "" +msgctxt "gram" msgid "g" msgstr "" @@ -15830,6 +15914,12 @@ msgid "" "Setting a value in the retract amount before wipe setting below will perform any excess retraction before the wipe, else it will be performed after." msgstr "" +msgid "Mixed color sublayer" +msgstr "" + +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "" + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "" @@ -16857,6 +16947,9 @@ msgstr "" msgid "The supplied file couldn't be read because it's empty." msgstr "" +msgid "The file format is incompatible and cannot be parsed." +msgstr "" + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "" @@ -18957,7 +19050,7 @@ msgstr "" msgid "Enable smart filament assign: Assign one filament to multiple nozzles to maximize savings" msgstr "" -msgid "Fila Saving" +msgid "File Saving" msgstr "" msgid "Don't remind me again" @@ -19317,6 +19410,9 @@ msgstr "" msgid "NO RAMMING AT ALL" msgstr "" +msgid "s" +msgstr "" + msgid "Volumetric speed" msgstr "" diff --git a/localization/i18n/es/OrcaSlicer_es.po b/localization/i18n/es/OrcaSlicer_es.po index 032516c978..bc8e1e9f79 100644 --- a/localization/i18n/es/OrcaSlicer_es.po +++ b/localization/i18n/es/OrcaSlicer_es.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: \n" "Last-Translator: Ian A. Bassi <>\n" "Language-Team: \n" @@ -2832,6 +2832,9 @@ msgstr "Editar" msgid "Merge with" msgstr "Fusionar con" +msgid "Decompose Color" +msgstr "Descomponer color" + msgid "Delete this filament" msgstr "Eliminar este filamento" @@ -3113,6 +3116,9 @@ msgstr "Ensamblaje" msgid "Merge parts to an object" msgstr "Fusionar piezas en un objeto" +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "Usar altura de capa variable junto con la subcapa de color mezclado puede reducir la calidad de la mezcla de colores." + msgid "Add layers" msgstr "Añadir capas" @@ -7613,6 +7619,9 @@ msgstr "Personalizar cama actual" msgid "The %s nozzle can not print %s." msgstr "La boquilla %s no puede imprimir %s." +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "Imprimir filamento de color mezclado en una impresora de un solo extrusor requiere cambios de filamento y purgas frecuentes, lo que puede aumentar considerablemente el desperdicio y el riesgo de obstrucción de la boquilla o del conducto de residuos." + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "No se recomienda mezclar %1% con %2% en la impresión.\n" @@ -7735,12 +7744,36 @@ msgstr "Sicronizar filamentos de la lista AMS" msgid "Set filaments to use" msgstr "Elegir filamentos para usar" +msgid "Add Mixed Filament" +msgstr "Añadir filamento mixto" + +msgid "Mixed Filament" +msgstr "Filamento mixto" + +msgid "Remove last mixed filament" +msgstr "Eliminar el último filamento mixto" + +msgid "Add mixed filament" +msgstr "Añadir filamento mixto" + +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "El filamento mixto tiene componentes no válidos o incoherentes. Vuelva a editar las entradas afectadas." + msgid "Search plate, object and part." msgstr "Buscar cama, objeto y parte." msgid "Pellets" msgstr "Pellets" +msgid "Mixed filament has broken component references" +msgstr "El filamento mixto tiene referencias de componentes rotas" + +msgid "Edit / Delete / Merge" +msgstr "Editar / Borrar / Fusionar" + +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "El filamento mixto de destino usa este filamento físico como componente. Al fusionarlos se eliminará este filamento físico y el filamento mixto puede quedar no válido. ¿Continuar?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "Al completar la operación, el proyecto %s se cerrará y se creará un nuevo proyecto." @@ -7919,6 +7952,12 @@ msgstr "" msgid "Multi-part object detected" msgstr "Objeto multipieza detectado" +msgid "Matching textures to filaments" +msgstr "Asociando texturas a los filamentos" + +msgid "Texture Import Warning" +msgstr "Aviso de importación de texturas" + msgid "Load these files as a single object with multiple parts?\n" msgstr "¿Cargar estos archivos como un objeto único con múltiples piezas?\n" @@ -8123,6 +8162,18 @@ msgstr "" msgid "Sync now" msgstr "Sincronizar ahora" +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "No se ha podido importar la textura. El modelo parece contener datos de textura, pero no se ha podido completar el proceso de importación. El modelo se importará solo como geometría." + +msgid "Applying texture colors..." +msgstr "Aplicando colores de textura..." + +msgid "Updating 3D view..." +msgstr "Actualizando la vista 3D..." + +msgid "Texture colors applied." +msgstr "Colores de textura aplicados." + msgid "You can keep the modified presets for the new project or discard them" msgstr "Puedes mantener los perfiles modificados en el nuevo proyecto o descartarlos" @@ -9338,6 +9389,9 @@ msgstr "Vaso en espiral" msgid "First layer filament sequence" msgstr "Secuencia de primera capa de filamento" +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "La lista de filamentos contiene filamentos mixtos. La secuencia de filamentos personalizada no tendrá efecto." + msgid "By Layer" msgstr "Por Capa" @@ -11181,27 +11235,6 @@ msgstr "Volúmenes de purgado para el cambio de filamentos" msgid "Please choose the filament colour" msgstr "Por favor, elija el color del filamento" -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "La función de visualización en directo nativa de Wayland requiere el receptor de vídeo GTK de GStreamer. Instale el plugin gtksink para GStreamer y, a continuación, reinicie OrcaSlicer." - -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "No se pudo inicializar el receptor de vídeo nativo de Wayland GStreamer. Compruebe la instalación del plugin GTK de GStreamer." - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "Para esta tarea se necesita el Reproductor de Windows Media. ¿Desea activar el \"Reproductor de Windows Media\" en su sistema operativo?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource no se ha registrado correctamente para la reproducción multimedia. Pulse Sí para volver a registrarlo. Será promocionado dos veces" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "¡Falta el componente BambuSource para la reproducción de medios! Reinstale OrcaSlicer o busque ayuda en la comunidad." - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Si utiliza una BambuSource de una instalación diferente, es posible que la reproducción de vídeo no funcione correctamente. Pulsa Sí para solucionarlo." - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "A tu sistema le faltan los codecs H.264 para GStreamer, necesarios para reproducir vídeo. (Prueba a instalar los paquetes gstreamer1.0-plugins-bad o gstreamer1.0-libav y, a continuación, reinicia Orca Slicer...)." - msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "El proveedor de servicios en la nube no está disponible. Reinicia OrcaSlicer e inténtalo de nuevo." @@ -11891,6 +11924,9 @@ msgstr "Si aún así quieres imprimir, puedes activar la opción en Preferencias msgid "No extrusions under current settings." msgstr "No hay extrusiones con los ajustes actuales." +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "Se está usando un filamento mixto con degradado, pero 'Subcapa de color mezclado' está desactivado. El degradado no se imprimirá." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "Modo de timelapse suave no está soportado cuando la secuencia \"por objeto\" está activada." @@ -11927,6 +11963,9 @@ msgstr "Es posible que desee reducir el tamaño de su modelo o cambiar la config msgid "Variable layer height is not supported with Organic supports." msgstr "La altura de capa adaptativa no es compatible con los soportes orgánicos." +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "El filamento de la torre de purga no puede ser un filamento mixto." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Diámetros de boquillas y diámetros de filamento diferentes pueden no funcionar correctamente cuando la torre de purga está activada. Esta función es experimental, así que proceda con cautela." @@ -13611,6 +13650,7 @@ msgstr "Tiempo de capa" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "El ventilador de refrigeración de la pieza se activará para las capas cuyo tiempo estimado sea inferior a este valor. La velocidad del ventilador se interpola entre las velocidades mínima y máxima del ventilador en función del tiempo de impresión de cada capa." +msgctxt "second" msgid "s" msgstr "s" @@ -13916,6 +13956,50 @@ msgstr "Material de soporte" msgid "Support material is commonly used to print supports and support interfaces." msgstr "El material de soporte se utiliza habitualmente para imprimir soportes y la interfaz de los soportes." +msgid "Is mixed filament" +msgstr "Es filamento mixto" + +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Indica si esta ranura de filamento es un filamento mixto compuesto por varios filamentos físicos" + +msgid "Mixed filament components" +msgstr "Componentes del filamento mixto" + +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Índices (empezando en 1) de los filamentos componentes, separados por comas; p. ej. \"1,3\"" + +msgid "Mixed filament sublayer ratios" +msgstr "Proporciones de subcapa del filamento mixto" + +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Valores de proporción separados por comas cuya suma sea 1.0; p. ej. \"0.7,0.3\"" + +msgid "Mixed filament gradient" +msgstr "Degradado del filamento mixto" + +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Activa el modo de degradado en dirección Z para las subcapas del filamento mixto. Al activarlo, las proporciones de las subcapas varían linealmente entre capas." + +msgid "Mixed filament gradient range" +msgstr "Rango del degradado del filamento mixto" + +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Proporciones inicial y final del primer componente en el modo de degradado. Par separado por comas; p. ej. \"0.10,0.90\" significa del 10% al 90%." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Curva del degradado del filamento mixto" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Curva personalizada opcional, al estilo de Photoshop, que asigna el progreso en Z a la proporción del primer componente. Se codifica como puntos de control separados por barras verticales, con el formato \"x,y\" (heredado) o \"x,y,m_in,m_out\" cuando se necesita anular la tangente (un valor vacío o \"nan\" usa el valor PCHIP predeterminado). x está en [0,1]; y se limita al rango de proporciones configurado; p. ej. \"0,0.15|0.5,0.50|1,0.85\". Si se deja vacío, se usa el gradient_range lineal." + +msgid "Mixed filament per-part gradient" +msgstr "Degradado por pieza del filamento mixto" + +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Cuando el modo de degradado está activado, aplica el degradado a cada pieza de un ensamblaje de forma independiente en lugar de tratar todo el ensamblaje como un único rango Z." + msgid "Filament printable" msgstr "Filamento imprimible" @@ -15150,6 +15234,7 @@ msgstr "Fuerza máxima del eje Y" msgid "The allowed maximum output force of Y axis" msgstr "La fuerza máxima permitida del eje Y" +msgctxt "Newton" msgid "N" msgstr "N" @@ -15159,6 +15244,7 @@ msgstr "Masa de la cama del eje Y" msgid "The machine bed mass load of Y axis" msgstr "La carga de la masa de la cama de la máquina del eje Y" +msgctxt "gram" msgid "g" msgstr "g" @@ -16715,6 +16801,14 @@ msgstr "" "\n" "Fijando un valor en la cantidad de retracción antes del purgado se realizará cualquier exceso de retracción antes del purgado, de lo contrario se realizará después." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Subcapa de color mezclado" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Activa la división en subcapas de color mezclado. Al activarlo, las capas que contienen filamentos de color mezclado se dividen en subcapas para lograr efectos de mezcla de colores." + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "La torre de purga puede utilizarse para limpiar los residuos de la boquilla y estabilizar la presión de la recámara en el interior de la boquilla, con el fin de evitar defectos visuales al imprimir objetos." @@ -17771,6 +17865,10 @@ msgstr "La generación de la malla del archivo del modelo falló o no hay una fo msgid "The supplied file couldn't be read because it's empty." msgstr "No se ha podido leer el archivo proporcionado porque está vacío." +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "El formato del archivo es incompatible y no se puede analizar." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Formato de archivo desconocido: el archivo de entrada debe tener extensión .STL, .obj o .amf (.xml)." @@ -20027,8 +20125,9 @@ msgstr "Eliminado" msgid "Enable smart filament assign: Assign one filament to multiple nozzles to maximize savings" msgstr "Activar la asignación inteligente de filamento: asigna un filamento a varias boquillas para maximizar el ahorro" -msgid "Fila Saving" -msgstr "Ahorro de filamento" +# AI Translated +msgid "File Saving" +msgstr "Guardado de archivo" msgid "Don't remind me again" msgstr "No me recuerdes de nuevo" @@ -20387,6 +20486,9 @@ msgstr "Reiniciar ahora" msgid "NO RAMMING AT ALL" msgstr "NO CHOCAR EN ABSOLUTO" +msgid "s" +msgstr "s" + msgid "Volumetric speed" msgstr "Velocidad volumétrica" @@ -20963,6 +21065,36 @@ msgstr "" "Evita la deformación\n" "¿Sabías que al imprimir materiales propensos a la deformación como el ABS, aumentar adecuadamente la temperatura de la cama térmica puede reducir la probabilidad de deformaciones?" +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "La función de visualización en directo nativa de Wayland requiere el receptor de vídeo GTK de GStreamer. Instale el plugin gtksink para GStreamer y, a continuación, reinicie OrcaSlicer." + +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "No se pudo inicializar el receptor de vídeo nativo de Wayland GStreamer. Compruebe la instalación del plugin GTK de GStreamer." + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "Para esta tarea se necesita el Reproductor de Windows Media. ¿Desea activar el \"Reproductor de Windows Media\" en su sistema operativo?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource no se ha registrado correctamente para la reproducción multimedia. Pulse Sí para volver a registrarlo. Será promocionado dos veces" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "¡Falta el componente BambuSource para la reproducción de medios! Reinstale OrcaSlicer o busque ayuda en la comunidad." + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "Si utiliza una BambuSource de una instalación diferente, es posible que la reproducción de vídeo no funcione correctamente. Pulsa Sí para solucionarlo." + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "A tu sistema le faltan los codecs H.264 para GStreamer, necesarios para reproducir vídeo. (Prueba a instalar los paquetes gstreamer1.0-plugins-bad o gstreamer1.0-libav y, a continuación, reinicia Orca Slicer...)." + +#~ msgid "N" +#~ msgstr "N" + +#~ msgid "g" +#~ msgstr "g" + +#~ msgid "Fila Saving" +#~ msgstr "Ahorro de filamento" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/eu/OrcaSlicer_eu.po b/localization/i18n/eu/OrcaSlicer_eu.po index 26185f6514..9ee2e6451d 100644 --- a/localization/i18n/eu/OrcaSlicer_eu.po +++ b/localization/i18n/eu/OrcaSlicer_eu.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: 2026-07-20 13:33+0200\n" "Last-Translator: Manu Goiogana <mgoiogana@gmail.com>\n" "Language-Team: \n" @@ -2868,6 +2868,10 @@ msgstr "Editatu" msgid "Merge with" msgstr "Batu honekin" +# AI Translated +msgid "Decompose Color" +msgstr "Deskonposatu kolorea" + msgid "Delete this filament" msgstr "Ezabatu filamentu hau" @@ -3149,6 +3153,10 @@ msgstr "Multzoa" msgid "Merge parts to an object" msgstr "Batu piezak objektu batean" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "Geruza-altuera aldakorra kolore nahasiaren azpigeruzarekin batera erabiltzeak kolore-nahasketaren kalitatea okertu dezake." + msgid "Add layers" msgstr "Geruzak gehitu" @@ -7679,6 +7687,10 @@ msgstr "Pertsonalizatu uneko plaka" msgid "The %s nozzle can not print %s." msgstr "%s pitak ezin du %s inprimatu." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "Kolore nahasiko filamentua estrusore bakarreko inprimagailu batean inprimatzeak filamentu-aldaketa eta purgatze ugari eskatzen ditu, eta horrek nabarmen handitu ditzake hondakinak eta pita edo hondakin-hodia buxatzeko arriskua." + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "Ez da gomendatzen inprimatzean %1% eta %2% nahastea.\n" @@ -7801,12 +7813,44 @@ msgstr "Sinkronizatu filamentuen zerrenda AMSarekin" msgid "Set filaments to use" msgstr "Ezarri erabili beharreko filamentuak" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Gehitu filamentu nahasia" + +# AI Translated +msgid "Mixed Filament" +msgstr "Filamentu nahasia" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Kendu azken filamentu nahasia" + +# AI Translated +msgid "Add mixed filament" +msgstr "Gehitu filamentu nahasia" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "Filamentu nahasiak baliogabeko edo bat ez datozen osagaiak ditu. Editatu berriro kaltetutako sarrerak." + msgid "Search plate, object and part." msgstr "Bilatu plaka, objektua eta pieza." msgid "Pellets" msgstr "Pelletak" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "Filamentu nahasiak hautsitako osagai-erreferentziak ditu" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Editatu / Ezabatu / Batu" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "Helburuko filamentu nahasiak filamentu fisiko hau erabiltzen du osagai gisa. Batzeak filamentu fisiko hau ezabatuko du eta filamentu nahasia baliogabetu dezake. Jarraitu?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "Eragiketa amaitzean, %s proiektua itxi eta proiektu berri bat sortuko da." @@ -7985,6 +8029,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Pieza anitzeko objektua detektatu da" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Testurak filamentuekin parekatzen" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Testura inportatzeko abisua" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Kargatu fitxategi hauek pieza anitzeko objektu bakar gisa?\n" @@ -8189,6 +8241,22 @@ msgstr "" msgid "Sync now" msgstr "Sinkronizatu orain" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "Testura inportatzeak huts egin du. Badirudi modeloak testura-datuak dituela, baina ezin izan da inportatze-prozesua osatu. Modeloa geometria gisa soilik inportatuko da." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Testura-koloreak aplikatzen..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "3D ikuspegia eguneratzen..." + +# AI Translated +msgid "Texture colors applied." +msgstr "Testura-koloreak aplikatuta." + msgid "You can keep the modified presets for the new project or discard them" msgstr "Aldatutako aurrezarpenak proiektu berrirako gorde edo baztertu ditzakezu" @@ -9406,6 +9474,10 @@ msgstr "Espiral formako loreontzia" msgid "First layer filament sequence" msgstr "Lehen geruzako filamentuen sekuentzia" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "Filamentu-zerrendak filamentu nahasiak ditu. Filamentu-sekuentzia pertsonalizatuak ez du eraginik izango." + msgid "By Layer" msgstr "Geruzaren arabera" @@ -11273,27 +11345,6 @@ msgstr "Filamentua aldatzeko purgatze-bolumenak" msgid "Please choose the filament colour" msgstr "Hautatu filamentuen kolorea" -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "Waylanden jatorrizko zuzeneko ikuspegiak GStreamer GTK bideo-hustubidea behar du. Instalatu GStreamerrerako gtksink plugina eta berrabiarazi OrcaSlicer." - -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Ezin izan da Waylanden jatorrizko GStreamer bideo-hustubidea hasieratu. Egiaztatu GStreamer GTK pluginaren instalazioa." - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "Windows Media Player behar da zeregin honetarako! 'Windows Media Player' gaitu nahi duzu zure sistema eragilean?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource ez da behar bezala erregistratu multimedia erreproduzitzeko! Sakatu Bai berriro erregistratzeko. Bi aldiz galdetuko zaizu" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Multimedia erreproduzitzeko erregistratutako BambuSource osagaia falta da! Berrinstalatu OrcaSlicer edo eskatu laguntza komunitateari." - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Beste instalazio bateko BambuSource erabiltzen ari zara; baliteke bideo-erreprodukzioak behar bezala ez funtzionatzea! Sakatu Bai konpontzeko." - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "Zure sisteman GStreamer-erako H.264 kodekak falta dira, eta beharrezkoak dira bideoa erreproduzitzeko. (Saiatu gstreamer1.0-plugins-bad edo gstreamer1.0-libav paketeak instalatzen, eta berrabiarazi OrcaSlicer?)" - msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "Hodeiko agentea ez dago erabilgarri. Berrabiarazi OrcaSlicer eta saiatu berriro." @@ -11993,6 +12044,10 @@ msgstr "Hala ere inprimatu nahi baduzu, aukera hau gaitu dezakezu: Hobespenak / msgid "No extrusions under current settings." msgstr "Uneko ezarpenekin ez dago estrusiorik." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "Gradientedun filamentu nahasi bat erabiltzen ari da, baina 'Kolore nahasiaren azpigeruza' desgaituta dago. Gradientea ez da inprimatuko." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "Timelapsearen modu leuna ez da onartzen \"objektuka\" sekuentzia gaituta dagoenean." @@ -12029,6 +12084,10 @@ msgstr "Modeloaren tamaina txikitu edo uneko inprimatze-ezarpenak aldatu eta ber msgid "Variable layer height is not supported with Organic supports." msgstr "Geruza-altuera aldakorra ez da onartzen euskarri organikoekin." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "Purgatze-dorrearen filamentua ezin da filamentu nahasia izan." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Pitaren diametro eta filamentu-diametro desberdinek agian ez dute ondo funtzionatuko purgatze-dorrea gaituta dagoenean. Oso esperimentala da; jarraitu kontuz." @@ -13729,6 +13788,8 @@ msgstr "Geruza-denbora" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "Piezaren hozte-haizagailua gaituko da estimatutako denbora balio hau baino laburragoa duten geruzetan. Haizagailuaren abiadura gutxienekoaren eta gehienekoaren artean interpolatuko da geruzaren inprimatze-denboraren arabera." +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -14034,6 +14095,62 @@ msgstr "Euskarri-materiala" msgid "Support material is commonly used to print supports and support interfaces." msgstr "Euskarri-materiala euskarriak eta euskarri-interfazeak inprimatzeko erabiltzen da normalean." +# AI Translated +msgid "Is mixed filament" +msgstr "Filamentu nahasia da" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Filamentu-zirrikitu hau hainbat filamentu fisikoz osatutako filamentu nahasia den adierazten du" + +# AI Translated +msgid "Mixed filament components" +msgstr "Filamentu nahasiaren osagaiak" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Osagai-filamentuen indizeak, komaz bereizita eta 1etik hasita; adib. \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Filamentu nahasiaren azpigeruza-ratioak" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Komaz bereizitako ratio-balioak, guztira 1.0 ematen dutenak; adib. \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Filamentu nahasiaren gradientea" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Z norabideko gradiente modua gaitzen du filamentu nahasiaren azpigeruzetarako. Gaituta dagoenean, azpigeruzen ratioak linealki aldatzen dira geruzaz geruza." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Filamentu nahasiaren gradiente-barrutia" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Lehen osagaiaren hasierako eta amaierako ratioak gradiente moduan. Komaz bereizitako parea; adib. \"0.10,0.90\" %10etik %90era esan nahi du." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Filamentu nahasiaren gradiente-kurba" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Aukerako Photoshop estiloko kurba pertsonalizatua, Z progresioa lehen osagaiaren ratioarekin lotzen duena. Barra bertikalez bereizitako kontrol-puntu gisa kodetzen da, \"x,y\" (zaharra) edo \"x,y,m_in,m_out\" formatuan, tangentea gainidatzi behar denean (balio hutsak edo \"nan\" balioak PCHIP lehenetsia erabiltzen du). x [0,1] tartean dago; y konfiguratutako ratio-barrutira mugatzen da; adib. \"0,0.15|0.5,0.50|1,0.85\". Hutsik uzten bada, gradient_range lineala erabiltzen da haren ordez." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Filamentu nahasiaren gradientea pieza bakoitzeko" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Gradiente modua gaituta dagoenean, gradientea multzoko pieza bakoitzari modu independentean aplikatzen zaio, multzo osoa Z barruti bakar gisa hartu beharrean." + msgid "Filament printable" msgstr "Filamentua inprimagarria" @@ -15285,6 +15402,8 @@ msgstr "Y ardatzaren gehieneko indarra" msgid "The allowed maximum output force of Y axis" msgstr "Y ardatzaren gehieneko irteera-indar baimendua" +# AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -15294,6 +15413,8 @@ msgstr "Y ardatzeko ohearen masa" msgid "The machine bed mass load of Y axis" msgstr "Y ardatzeko makinaren oheak jasaten duen masa-karga" +# AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -16859,6 +16980,14 @@ msgstr "" "\n" "Beheko garbitu aurreko atzera-egite kantitatearen ezarpenean balio batezarriz gero, gehiegizko atzera-egitea garbiketa baino lehen egingo da; bestela, ondoren egingo da." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Kolore nahasiaren azpigeruza" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Kolore nahasiaren azpigeruzatan zatitzea gaitzen du. Gaituta dagoenean, kolore nahasiko filamentuak dituzten geruzak azpigeruzatan zatitzen dira kolore-nahasketa efektuak lortzeko." + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "Purgatze-dorrea pitaren hondarrak garbitzeko eta pitaren barruko ganbera-presioa egonkortzeko erabil daiteke, objektuetan itxura-akatsak saihesteko." @@ -17917,6 +18046,10 @@ msgstr "Modelo-fitxategiaren sareztatzeak huts egin du edo ez dago baliozko form msgid "The supplied file couldn't be read because it's empty." msgstr "Emandako fitxategia ezin izan da irakurri hutsik dagoelako." +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "Fitxategi-formatua bateraezina da eta ezin da analizatu." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Fitxategi-formatu ezezaguna: sarrerako fitxategiak .stl, .obj edo .amf(.xml) luzapena izan behar du." @@ -20179,8 +20312,9 @@ msgstr "Ezabatuta" msgid "Enable smart filament assign: Assign one filament to multiple nozzles to maximize savings" msgstr "Gaitu filamentuen esleipen adimenduna: esleitu filamentua hainbat pitatara aurrezpena maximizatzeko" -msgid "Fila Saving" -msgstr "Filamentu-aurrezpena" +# AI Translated +msgid "File Saving" +msgstr "Fitxategia gordetzea" msgid "Don't remind me again" msgstr "Ez gogorarazi berriro" @@ -20541,6 +20675,9 @@ msgstr "Berrabiarazi orain" msgid "NO RAMMING AT ALL" msgstr "MUTURRAREN MOLDAKETARIK EZ INONDIK INORA" +msgid "s" +msgstr "s" + msgid "Volumetric speed" msgstr "Abiadura bolumetrikoa" @@ -21117,6 +21254,36 @@ msgstr "" "Saihestu okertzea\n" "Ba al zenekien ABS bezalako okertzeko joera duten materialak inprimatzean ohe beroaren tenperatura egoki igotzeak okertzeko probabilitatea murriztu dezakeela?" +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "Waylanden jatorrizko zuzeneko ikuspegiak GStreamer GTK bideo-hustubidea behar du. Instalatu GStreamerrerako gtksink plugina eta berrabiarazi OrcaSlicer." + +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "Ezin izan da Waylanden jatorrizko GStreamer bideo-hustubidea hasieratu. Egiaztatu GStreamer GTK pluginaren instalazioa." + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "Windows Media Player behar da zeregin honetarako! 'Windows Media Player' gaitu nahi duzu zure sistema eragilean?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource ez da behar bezala erregistratu multimedia erreproduzitzeko! Sakatu Bai berriro erregistratzeko. Bi aldiz galdetuko zaizu" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "Multimedia erreproduzitzeko erregistratutako BambuSource osagaia falta da! Berrinstalatu OrcaSlicer edo eskatu laguntza komunitateari." + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "Beste instalazio bateko BambuSource erabiltzen ari zara; baliteke bideo-erreprodukzioak behar bezala ez funtzionatzea! Sakatu Bai konpontzeko." + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "Zure sisteman GStreamer-erako H.264 kodekak falta dira, eta beharrezkoak dira bideoa erreproduzitzeko. (Saiatu gstreamer1.0-plugins-bad edo gstreamer1.0-libav paketeak instalatzen, eta berrabiarazi OrcaSlicer?)" + +#~ msgid "N" +#~ msgstr "N" + +#~ msgid "g" +#~ msgstr "g" + +#~ msgid "Fila Saving" +#~ msgstr "Filamentu-aurrezpena" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/fr/OrcaSlicer_fr.po b/localization/i18n/fr/OrcaSlicer_fr.po index 28a2e27a01..e56aee63a7 100644 --- a/localization/i18n/fr/OrcaSlicer_fr.po +++ b/localization/i18n/fr/OrcaSlicer_fr.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: Guislain Cyril, Thomas Lété\n" @@ -2896,6 +2896,10 @@ msgstr "Éditer" msgid "Merge with" msgstr "Fusionner avec" +# AI Translated +msgid "Decompose Color" +msgstr "Décomposer la couleur" + msgid "Delete this filament" msgstr "Supprimer ce filament" @@ -3178,6 +3182,10 @@ msgstr "Assemblé" msgid "Merge parts to an object" msgstr "Fusionner les pièces en un objet" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "L’utilisation d’une hauteur de couche variable avec la sous-couche de couleur mixte peut dégrader la qualité du mélange des couleurs." + msgid "Add layers" msgstr "Ajouter des couches" @@ -7733,6 +7741,10 @@ msgstr "Personnaliser le plateau actuel" msgid "The %s nozzle can not print %s." msgstr "La buse %s ne peut pas imprimer %s." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "L’impression d’un filament de couleur mixte sur une imprimante à extrudeur unique nécessite des changements de filament et des purges fréquents, ce qui peut augmenter considérablement les déchets et le risque d’obstruction de la buse ou de la goulotte à déchets." + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "Le mélange de %1% avec %2% lors de l'impression n'est pas recommandé.\n" @@ -7858,12 +7870,44 @@ msgstr "Synchroniser la liste des filaments depuis l'AMS" msgid "Set filaments to use" msgstr "Définir les filaments à utiliser" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Ajouter un filament mixte" + +# AI Translated +msgid "Mixed Filament" +msgstr "Filament mixte" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Supprimer le dernier filament mixte" + +# AI Translated +msgid "Add mixed filament" +msgstr "Ajouter un filament mixte" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "Le filament mixte comporte des composants invalides ou incohérents. Veuillez modifier à nouveau les entrées concernées." + msgid "Search plate, object and part." msgstr "Recherche de plaque, d'objet et de pièce." msgid "Pellets" msgstr "Granulés" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "Le filament mixte comporte des références de composants invalides" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Éditer / Supprimer / Fusionner" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "Le filament mixte cible utilise ce filament physique comme composant. La fusion supprimera ce filament physique et risque de rendre le filament mixte invalide. Continuer ?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "Une fois votre opération terminée, le projet %s sera fermé et un nouveau projet sera créé." @@ -8042,6 +8086,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Objet en plusieurs pièces détecté" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Association des textures aux filaments" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Avertissement d’importation de texture" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Charger ces fichiers en tant qu'objet unique avec plusieurs parties ?\n" @@ -8246,6 +8298,22 @@ msgstr "" msgid "Sync now" msgstr "Synchroniser maintenant" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "Échec de l’importation de la texture. Le modèle semble contenir des données de texture, mais le processus d’importation n’a pas pu être mené à son terme. Le modèle sera importé en tant que géométrie uniquement." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Application des couleurs de texture..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "Mise à jour de la vue 3D..." + +# AI Translated +msgid "Texture colors applied." +msgstr "Couleurs de texture appliquées." + msgid "You can keep the modified presets for the new project or discard them" msgstr "Vous pouvez conserver les préréglages modifiés dans le nouveau projet ou les supprimer" @@ -9477,6 +9545,10 @@ msgstr "Vase spirale" msgid "First layer filament sequence" msgstr "Séquence d’impression de la première couche" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "La liste des filaments contient des filaments mixtes. La séquence de filaments personnalisée ne sera pas appliquée." + msgid "By Layer" msgstr "Par Couche" @@ -11369,27 +11441,6 @@ msgstr "Volumes de purge pour le changement de filament" msgid "Please choose the filament colour" msgstr "Veuillez choisir la couleur du filament" -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "L’aperçu en direct natif sous Wayland nécessite le récepteur vidéo GStreamer GTK. Veuillez installer le plugin gtksink pour GStreamer, puis redémarrer OrcaSlicer." - -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Échec de l’initialisation du récepteur vidéo GStreamer natif sous Wayland. Veuillez vérifier l’installation de votre plugin GStreamer GTK." - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "Windows Media Player est nécessaire pour cette tâche ! Voulez-vous activer ‘Windows Media Player’ pour votre système d’exploitation ?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource n’a pas été correctement enregistré pour la lecture de médias ! Appuyez sur Oui pour le réenregistrer. Vous recevrez deux fois la demande de permission" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Composant BambuSource manquant pour la lecture multimédia ! Veuillez réinstaller OrcaSlicer ou demander de l'aide à la communauté." - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Si vous utilisez une BambuSource provenant d’une autre installation, la lecture de la vidéo peut ne pas fonctionner correctement ! Appuyez sur Oui pour résoudre le problème." - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "Il manque à votre système les codecs H.264 pour GStreamer, qui sont nécessaires pour lire la vidéo. (Essayez d’installer les paquets gstreamer1.0-plugins-bad ou gstreamer1.0-libav, puis redémarrez Orca Slicer)." - msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "L’agent cloud n’est pas disponible. Veuillez redémarrer OrcaSlicer et réessayer." @@ -12092,6 +12143,10 @@ msgstr "Si vous souhaitez tout de même imprimer, vous pouvez activer l’option msgid "No extrusions under current settings." msgstr "Aucune extrusion dans les paramètres actuels." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "Un filament mixte avec dégradé est utilisé, mais « Sous-couche de couleur mixte » est désactivé. Le dégradé ne sera pas imprimé." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "Le mode fluide du timelapse n'est pas pris en charge lorsque le mode d'impression « par objet » est activé." @@ -12128,6 +12183,10 @@ msgstr "Vous devez réduire la taille de votre modèle ou modifier les paramètr msgid "Variable layer height is not supported with Organic supports." msgstr "La hauteur de couche variable n’est pas prise en charge avec les supports organiques." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "Le filament de la tour d’essuyage ne peut pas être un filament mixte." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Différents diamètres de buses et de filaments peuvent ne pas fonctionner correctement lorsque la tour d’amorçage est activée. Il s’agit d’un projet très expérimental, il convient donc de procéder avec prudence." @@ -12475,27 +12534,21 @@ msgstr "mm ou %" msgid "Other layers" msgstr "Autres couches" -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "Température du plateau pour les couches sauf la première. Une valeur de 0 signifie que le filament ne prend pas en charge l'impression sur la Cool Plate SuperTack." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "Il s'agit de la température du plateau pour toutes les couches à l'exception de la première. Une valeur à 0 signifie que ce filament ne peut pas être imprimé sur la plaque \"Cool plate\"." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured Cool Plate." msgstr "Température du plateau pour les couches à l’exception de la couche initiale. La valeur 0 signifie que le filament ne peut pas être imprimé sur la plaque Cool Plate texturée." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Engineering Plate." msgstr "Il s'agit de la température du plateau pour toutes les couches à l'exception de la première. Une valeur à 0 signifie que ce filament ne peut pas être imprimé sur la plaque Engineering." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the High Temp Plate." msgstr "Il s'agit de la température du plateau pour toutes les couches à l'exception de la première. Une valeur à 0 signifie que ce filament ne peut pas être imprimé sur le plateau haute température (\"High Temp plate\")." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured PEI Plate." msgstr "Température du plateau après la première couche. 0 signifie que le filament ne peut pas être imprimé sur la plaque PEI texturée." @@ -13837,6 +13890,8 @@ msgstr "Temps de couche" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "Le ventilateur de refroidissement des pièces sera activé pour les couches dont le temps estimé est inférieur à cette valeur. La vitesse du ventilateur est interpolée entre les vitesses minimale et maximale du ventilateur en fonction du temps d'impression de la couche" +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -14143,6 +14198,62 @@ msgstr "Supports" msgid "Support material is commonly used to print supports and support interfaces." msgstr "Le matériau de support est généralement utilisé pour imprimer le support et les interfaces de support" +# AI Translated +msgid "Is mixed filament" +msgstr "Est un filament mixte" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Indique si cet emplacement de filament est un filament mixte composé de plusieurs filaments physiques" + +# AI Translated +msgid "Mixed filament components" +msgstr "Composants du filament mixte" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Indices (à partir de 1) des filaments composants, séparés par des virgules ; par ex. \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Proportions des sous-couches du filament mixte" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Valeurs de proportion séparées par des virgules dont la somme vaut 1.0 ; par ex. \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Dégradé du filament mixte" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Active le mode dégradé dans la direction Z pour les sous-couches du filament mixte. Lorsqu’il est activé, les proportions des sous-couches varient linéairement d’une couche à l’autre." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Plage du dégradé du filament mixte" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Proportions de début et de fin du premier composant en mode dégradé. Paire séparée par une virgule ; par ex. \"0.10,0.90\" signifie de 10% à 90%." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Courbe du dégradé du filament mixte" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Courbe personnalisée facultative, de style Photoshop, associant la progression en Z à la proportion du premier composant. Encodée sous forme de points de contrôle séparés par des barres verticales, au format \"x,y\" (ancien) ou \"x,y,m_in,m_out\" lorsqu’une tangente doit être forcée (une valeur vide ou \"nan\" utilise la valeur PCHIP par défaut). x est compris dans [0,1] ; y est limité à la plage de proportions configurée ; par ex. \"0,0.15|0.5,0.50|1,0.85\". Si le champ est vide, le gradient_range linéaire est utilisé à la place." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Dégradé par pièce du filament mixte" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Lorsque le mode dégradé est activé, applique le dégradé à chaque pièce d’un assemblage indépendamment au lieu de traiter l’assemblage entier comme une seule plage Z." + msgid "Filament printable" msgstr "Filament imprimable" @@ -15388,6 +15499,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "Force de sortie maximale autorisée sur l'axe Y" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -15398,6 +15510,7 @@ msgid "The machine bed mass load of Y axis" msgstr "Charge massique du plateau de la machine sur l'axe Y" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -16971,6 +17084,14 @@ msgstr "" "\n" "Le réglage d’une valeur dans le paramètre de quantité de rétraction avant essuyage ci-dessous permet d’effectuer toute rétraction excédentaire avant l’essuyage, sinon elle sera effectuée après l’essuyage." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Sous-couche de couleur mixte" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Active la division en sous-couches de couleur mixte. Lorsqu’elle est activée, les couches contenant des filaments de couleur mixte sont divisées en sous-couches afin d’obtenir des effets de mélange de couleurs." + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "La tour de purge peut être utilisée pour nettoyer les résidus sur la buse et stabiliser la pression du caisson à l'intérieur de la buse afin d'éviter les défauts d'apparence lors de l'impression d'objets." @@ -18037,6 +18158,10 @@ msgstr "Le maillage d'un fichier modèle a échoué ou la forme n'est pas valide msgid "The supplied file couldn't be read because it's empty." msgstr "Le fichier fourni n'a pas pu être lu car il est vide" +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "Le format du fichier est incompatible et ne peut pas être analysé." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Format de fichier inconnu : le fichier d'entrée doit porter l'extension .stl, .obj ou .amf (.xml)." @@ -20296,8 +20421,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "Activer l'attribution intelligente de filament : attribuer un filament à plusieurs buses pour maximiser les économies" # AI Translated -msgid "Fila Saving" -msgstr "Économie de filament" +msgid "File Saving" +msgstr "Enregistrement du fichier" msgid "Don't remind me again" msgstr "Ne plus me rappeler" @@ -20662,6 +20787,9 @@ msgstr "Redémarrer maintenant" msgid "NO RAMMING AT ALL" msgstr "AUCUN BOURRAGE" +msgid "s" +msgstr "s" + msgid "Volumetric speed" msgstr "Vitesse volumétrique" @@ -21194,7 +21322,8 @@ msgstr "" "Divisez vos impressions en plateaux\n" "Saviez-vous que vous pouvez diviser un modèle comportant de nombreuses pièces en plateaux individuels prêts à être imprimés ? Cela simplifie le processus de suivi de toutes les pièces." -#: resources/data/hints.ini: [hint:Speed up your print with Adaptive Layer Height] +#: resources/data/hints.ini: [hint:Speed up your print with Adaptive Layer +#: Height] msgid "" "Speed up your print with Adaptive Layer Height\n" "Did you know that you can print a model even faster by using the Adaptive Layer Height option? Check it out!" @@ -21266,7 +21395,8 @@ msgstr "" "Améliorer la solidité\n" "Saviez-vous que vous pouvez définir un plus grand nombre de périmètre et une densité de remplissage plus élevée pour améliorer la résistance du modèle ?" -#: resources/data/hints.ini: [hint:When do you need to print with the printer door opened] +#: resources/data/hints.ini: [hint:When do you need to print with the printer +#: door opened] msgid "" "When do you need to print with the printer door opened?\n" "Did you know that opening the printer door can reduce the probability of extruder/hotend clogging when printing lower temperature filament with a higher enclosure temperature? There is more info about this in the Wiki." @@ -21282,6 +21412,39 @@ msgstr "" "Éviter la déformation\n" "Saviez-vous que lors de l’impression de matériaux susceptibles de se déformer, tels que l’ABS, une augmentation appropriée de la température du plateau chauffant peut réduire la probabilité de déformation?" +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "L’aperçu en direct natif sous Wayland nécessite le récepteur vidéo GStreamer GTK. Veuillez installer le plugin gtksink pour GStreamer, puis redémarrer OrcaSlicer." + +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "Échec de l’initialisation du récepteur vidéo GStreamer natif sous Wayland. Veuillez vérifier l’installation de votre plugin GStreamer GTK." + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "Windows Media Player est nécessaire pour cette tâche ! Voulez-vous activer ‘Windows Media Player’ pour votre système d’exploitation ?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource n’a pas été correctement enregistré pour la lecture de médias ! Appuyez sur Oui pour le réenregistrer. Vous recevrez deux fois la demande de permission" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "Composant BambuSource manquant pour la lecture multimédia ! Veuillez réinstaller OrcaSlicer ou demander de l'aide à la communauté." + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "Si vous utilisez une BambuSource provenant d’une autre installation, la lecture de la vidéo peut ne pas fonctionner correctement ! Appuyez sur Oui pour résoudre le problème." + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "Il manque à votre système les codecs H.264 pour GStreamer, qui sont nécessaires pour lire la vidéo. (Essayez d’installer les paquets gstreamer1.0-plugins-bad ou gstreamer1.0-libav, puis redémarrez Orca Slicer)." + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "Économie de filament" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/hu/OrcaSlicer_hu.po b/localization/i18n/hu/OrcaSlicer_hu.po index 1dbfe0b1b7..a15d471073 100644 --- a/localization/i18n/hu/OrcaSlicer_hu.po +++ b/localization/i18n/hu/OrcaSlicer_hu.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "Language: hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -2948,6 +2948,10 @@ msgstr "Szerkesztés" msgid "Merge with" msgstr "Egyesítés ezzel" +# AI Translated +msgid "Decompose Color" +msgstr "Szín szétbontása" + msgid "Delete this filament" msgstr "Filament törlése" @@ -3247,6 +3251,10 @@ msgstr "Összeállítás" msgid "Merge parts to an object" msgstr "Tárgyak egyesítése egy objektummá" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "A változó rétegmagasság és a kevert színű alréteg együttes használata ronthatja a színkeverés minőségét." + # AI Translated msgid "Add layers" msgstr "Rétegek hozzáadása" @@ -7847,6 +7855,10 @@ msgstr "Aktuális tálca testreszabása" msgid "The %s nozzle can not print %s." msgstr "A(z) %s fúvóka nem tudja nyomtatni ezt: %s." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "A kevert színű filament nyomtatása egyextruderes nyomtatón gyakori filamentcserét és öblítést igényel, ami jelentősen növelheti a hulladék mennyiségét, valamint a fúvóka vagy a hulladékcsúszda eltömődésének kockázatát." + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "A(z) %1% és %2% keverése nyomtatás közben nem ajánlott.\n" @@ -7972,12 +7984,44 @@ msgstr "Filamentlista szinkronizálása az AMS-ből" msgid "Set filaments to use" msgstr "Használni kívánt filament beállítása" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Kevert filament hozzáadása" + +# AI Translated +msgid "Mixed Filament" +msgstr "Kevert filament" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Utolsó kevert filament eltávolítása" + +# AI Translated +msgid "Add mixed filament" +msgstr "Kevert filament hozzáadása" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "A kevert filament érvénytelen vagy nem egyező összetevőket tartalmaz. Szerkessze újra az érintett bejegyzéseket." + msgid "Search plate, object and part." msgstr "Tálca, objektum és tárgy keresése." msgid "Pellets" msgstr "Pelletek" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "A kevert filament hibás összetevő-hivatkozásokat tartalmaz" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Szerkesztés / Törlés / Egyesítés" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "A cél kevert filament ezt a fizikai filamentet használja összetevőként. Az egyesítés eltávolítja ezt a fizikai filamentet, és a kevert filament érvénytelenné válhat. Folytatja?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "A művelet befejezésekor a(z) %s projekt bezárul, majd új projekt jön létre." @@ -8160,6 +8204,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Több részből álló objektum észlelve" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Textúrák hozzárendelése a filamentekhez" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Textúraimportálási figyelmeztetés" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Betöltöd ezeket a fájlokat több részből álló egyetlen objektumként?\n" @@ -8371,6 +8423,22 @@ msgstr "" msgid "Sync now" msgstr "Szinkronizálás most" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "A textúra importálása sikertelen. Úgy tűnik, hogy a modell textúraadatokat tartalmaz, de az importálási folyamatot nem sikerült befejezni. A modell csak geometriaként lesz importálva." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Textúraszínek alkalmazása..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "3D nézet frissítése..." + +# AI Translated +msgid "Texture colors applied." +msgstr "A textúraszínek alkalmazva." + msgid "You can keep the modified presets for the new project or discard them" msgstr "Megtarthatod az új projekt módosított beállításait, vagy elvetheted őket" @@ -9633,6 +9701,10 @@ msgstr "Spirál (váza)" msgid "First layer filament sequence" msgstr "Kezdőréteg filament sorrendje" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "A filamentlista kevert filamenteket tartalmaz. Az egyéni filamentsorrend nem lép érvénybe." + # AI Translated msgid "By Layer" msgstr "Rétegenként" @@ -11552,27 +11624,6 @@ msgstr "Filamentcsere öblítési mennyisége" msgid "Please choose the filament colour" msgstr "Kérlek, válaszd ki a filament színét" -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "A natív Wayland élőképhez a GStreamer GTK videonyelő szükséges. Telepítsd a gtksink beépülő modult a GStreamerhez, majd indítsd újra az OrcaSlicert." - -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Nem sikerült inicializálni a natív Wayland GStreamer videonyelőt. Ellenőrizd a GStreamer GTK bővítmény telepítését." - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "Ehhez a művelethez Windows Media Player szükséges. Szeretnéd engedélyezni a \"Windows Media Player\"-t az operációs rendszerben?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "A BambuSource nincs megfelelően regisztrálva médialejátszáshoz. Kattints az Igen gombra az újbóli regisztráláshoz. Kétszer kapsz majd megerősítési kérést." - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "A médialejátszáshoz szükséges BambuSource-összetevő hiányzik. Kérlek, telepítsd újra az OrcaSlicert, vagy kérj segítséget a közösségtől." - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Ha egy másik telepítésből származó BambuSource van használatban, előfordulhat, hogy a videólejátszás nem működik megfelelően. Kattints az Igen gombra a javításhoz." - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "A rendszerből hiányoznak a GStreamer H.264 kodekjei, amelyek szükségesek a videolejátszáshoz. (Próbáld telepíteni a gstreamer1.0-plugins-bad vagy a gstreamer1.0-libav csomagokat, majd indítsd újra az Orca Slicert.)" - msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "A felhőszolgáltatás nem érhető el. Indítsd újra az OrcaSlicert, majd próbáld újra." @@ -12282,6 +12333,10 @@ msgstr "Ha továbbra is szeretnél nyomtatni, engedélyezheted az opciót itt: B msgid "No extrusions under current settings." msgstr "A jelenlegi beállításokkal nincsenek extrudálások." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "Színátmenetes kevert filament van használatban, de a 'Kevert színű alréteg' ki van kapcsolva. A színátmenet nem lesz kinyomtatva." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "A sima Timelapse nem használható, ha a nyomtatási sorrend \"Tárgyanként\"." @@ -12318,6 +12373,10 @@ msgstr "Próbáld meg csökkenteni a modell méretét vagy módosítani a jelenl msgid "Variable layer height is not supported with Organic supports." msgstr "A változó rétegmagasság nem működik az organikus támaszokkal." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "A törlőtorony filamentje nem lehet kevert filament." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Eltérő fúvókaátmérők és eltérő filamentátmérők mellett a törlőtorony nem biztos, hogy megfelelően működik. Ez nagyon kísérleti funkció, ezért körültekintően használd." @@ -14063,6 +14122,8 @@ msgstr "Rétegidő" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "A tárgyhűtő ventilátor azon rétegek esetében lesz engedélyezve, amelyek becsült ideje rövidebb ennél az értéknél. A ventilátor fordulatszáma a rétegnyomtatási időnek megfelelően skálázódik a minimális és maximális ventilátor fordulatszám között" +# AI Translated +msgctxt "second" msgid "s" msgstr "mp" @@ -14370,6 +14431,62 @@ msgstr "Támaszanyag" msgid "Support material is commonly used to print supports and support interfaces." msgstr "A támaszanyagot általában a támaszok és azok érintkező felületeinek nyomtatására használják." +# AI Translated +msgid "Is mixed filament" +msgstr "Kevert filament-e" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Megadja, hogy ez a filamenthely több fizikai filamentből álló kevert filament-e" + +# AI Translated +msgid "Mixed filament components" +msgstr "Kevert filament összetevői" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Az összetevő filamentek vesszővel elválasztott, 1-től induló indexei, pl. \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Kevert filament alréteg-arányai" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Vesszővel elválasztott arányértékek, amelyek összege 1.0, pl. \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Kevert filament színátmenete" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Bekapcsolja a Z irányú színátmenet módot a kevert filament alrétegeihez. Bekapcsolva az alrétegek arányai lineárisan változnak a rétegek mentén." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Kevert filament színátmenetének tartománya" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Az első összetevő kezdő és záró aránya színátmenet módban. Vesszővel elválasztott számpár, pl. a \"0.10,0.90\" 10%-tól 90%-ig tartót jelent." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Kevert filament színátmenet-görbéje" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Opcionális, Photoshop stílusú egyéni görbe, amely a Z irányú haladást az első összetevő arányához rendeli. Függőleges vonallal elválasztott vezérlőpontokként van kódolva, \"x,y\" (régi) vagy \"x,y,m_in,m_out\" formában, ha az érintő felülbírálására van szükség (üres érték vagy \"nan\" esetén a PCHIP alapértelmezés érvényes). x a [0,1] tartományban van; y a beállított aránytartományra van korlátozva, pl. \"0,0.15|0.5,0.50|1,0.85\". Ha üresen marad, helyette a lineáris gradient_range kerül felhasználásra." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Kevert filament színátmenete tárgyanként" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Ha a színátmenet mód be van kapcsolva, a színátmenet az összeállítás minden tárgyára külön-külön érvényesül, ahelyett hogy az egész összeállítást egyetlen Z tartományként kezelné." + msgid "Filament printable" msgstr "Filament nyomtatható" @@ -15633,6 +15750,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "Az Y tengely megengedett maximális kimeneti ereje" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -15643,6 +15761,7 @@ msgid "The machine bed mass load of Y axis" msgstr "Az Y tengely gépasztaltömeg-terhelése" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -17233,6 +17352,14 @@ msgstr "" "\n" "Ha az alábbi \"visszahúzási mennyiség törlés előtt\" beállításban értéket adsz meg, akkor az esetleges többletvisszahúzás a törlés előtt történik meg, különben utána." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Kevert színű alréteg" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Bekapcsolja a kevert színű alrétegekre bontást. Bekapcsolva a kevert színű filamentet tartalmazó rétegek alrétegekre lesznek bontva a színkeverési hatás eléréséhez." + # AI Translated msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "A törlőtorony a fúvókán lévő maradék eltávolítására és a fúvóka belsejében lévő nyomás stabilizálására szolgál, hogy elkerülhetők legyenek a megjelenésbeli hibák az objektumok nyomtatásakor." @@ -18306,6 +18433,10 @@ msgstr "A modellfájl hálósítása sikertelen volt, vagy nincs érvényes alak msgid "The supplied file couldn't be read because it's empty." msgstr "A megadott fájl nem olvasható be, mert üres" +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "A fájlformátum nem kompatibilis, ezért nem értelmezhető." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Ismeretlen fájlformátum. A bemeneti fájlnak .stl, .obj vagy .amf(.xml) kiterjesztésűnek kell lennie." @@ -20654,8 +20785,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "Intelligens filament-hozzárendelés bekapcsolása: egy filament több fúvókához rendelése a megtakarítás maximalizálásához" # AI Translated -msgid "Fila Saving" -msgstr "Filamentmegtakarítás" +msgid "File Saving" +msgstr "Fájl mentése" msgid "Don't remind me again" msgstr "Ne emlékeztessen újra" @@ -21058,6 +21189,9 @@ msgstr "Újraindítás most" msgid "NO RAMMING AT ALL" msgstr "EGYÁLTALÁN NINCS TÖMÖRÍTÉS" +msgid "s" +msgstr "mp" + msgid "Volumetric speed" msgstr "Volumetrikus sebesség" @@ -21709,6 +21843,39 @@ msgstr "" "Kunkorodás elkerülése\n" "Tudtad, hogy a kunkorodásra hajlamos anyagok (például ABS) nyomtatásakor az asztal hőmérsékletének növelése csökkentheti a kunkorodás valószínűségét?" +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "A natív Wayland élőképhez a GStreamer GTK videonyelő szükséges. Telepítsd a gtksink beépülő modult a GStreamerhez, majd indítsd újra az OrcaSlicert." + +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "Nem sikerült inicializálni a natív Wayland GStreamer videonyelőt. Ellenőrizd a GStreamer GTK bővítmény telepítését." + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "Ehhez a művelethez Windows Media Player szükséges. Szeretnéd engedélyezni a \"Windows Media Player\"-t az operációs rendszerben?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "A BambuSource nincs megfelelően regisztrálva médialejátszáshoz. Kattints az Igen gombra az újbóli regisztráláshoz. Kétszer kapsz majd megerősítési kérést." + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "A médialejátszáshoz szükséges BambuSource-összetevő hiányzik. Kérlek, telepítsd újra az OrcaSlicert, vagy kérj segítséget a közösségtől." + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "Ha egy másik telepítésből származó BambuSource van használatban, előfordulhat, hogy a videólejátszás nem működik megfelelően. Kattints az Igen gombra a javításhoz." + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "A rendszerből hiányoznak a GStreamer H.264 kodekjei, amelyek szükségesek a videolejátszáshoz. (Próbáld telepíteni a gstreamer1.0-plugins-bad vagy a gstreamer1.0-libav csomagokat, majd indítsd újra az Orca Slicert.)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "Filamentmegtakarítás" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/it/OrcaSlicer_it.po b/localization/i18n/it/OrcaSlicer_it.po index f9d31456bf..9af642f536 100644 --- a/localization/i18n/it/OrcaSlicer_it.po +++ b/localization/i18n/it/OrcaSlicer_it.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -2953,6 +2953,10 @@ msgstr "Modifica" msgid "Merge with" msgstr "Unisci con" +# AI Translated +msgid "Decompose Color" +msgstr "Scomponi colore" + msgid "Delete this filament" msgstr "Elimina questo filamento" @@ -3252,6 +3256,10 @@ msgstr "Assemblaggio" msgid "Merge parts to an object" msgstr "Unisci parti in un oggetto" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "L'uso dell'altezza strato variabile insieme al sottostrato di colore misto può ridurre la qualità della miscelazione dei colori." + # AI Translated msgid "Add layers" msgstr "Aggiungi strati" @@ -7851,6 +7859,10 @@ msgstr "Personalizza il piatto corrente" msgid "The %s nozzle can not print %s." msgstr "L'ugello %s non può stampare %s." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "La stampa di filamento a colore misto su una stampante a estrusore singolo richiede frequenti cambi di filamento e spurghi, il che può aumentare notevolmente gli scarti e il rischio di intasamento dell'ugello o dello scivolo di scarto." + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "Non è consigliato miscelare %1% con %2% nella stampa.\n" @@ -7976,12 +7988,44 @@ msgstr "Sincronizza l'elenco filamenti dall'AMS" msgid "Set filaments to use" msgstr "Imposta filamenti da usare" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Aggiungi filamento misto" + +# AI Translated +msgid "Mixed Filament" +msgstr "Filamento misto" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Rimuovi l'ultimo filamento misto" + +# AI Translated +msgid "Add mixed filament" +msgstr "Aggiungi filamento misto" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "Il filamento misto ha componenti non validi o incoerenti. Modificare nuovamente le voci interessate." + msgid "Search plate, object and part." msgstr "Cerca piatto, oggetto e parte." msgid "Pellets" msgstr "Granuli" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "Il filamento misto ha riferimenti a componenti non validi" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Modifica / Elimina / Unisci" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "Il filamento misto di destinazione utilizza questo filamento fisico come componente. L'unione rimuoverà questo filamento fisico e potrebbe invalidare il filamento misto. Continuare?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "Al completamento dell'operazione, il progetto %s verrà chiuso e ne verrà creato uno nuovo." @@ -8161,6 +8205,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Rilevato oggetto in più parti" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Associazione delle trame ai filamenti" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Avviso di importazione trama" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Caricare questi file come un singolo oggetto con più parti?\n" @@ -8371,6 +8423,22 @@ msgstr "" msgid "Sync now" msgstr "Sincronizza ora" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "Importazione della trama non riuscita. Il modello sembra contenere dati di trama, ma non è stato possibile completare il processo di importazione. Il modello verrà importato solo come geometria." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Applicazione dei colori della trama..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "Aggiornamento della vista 3D..." + +# AI Translated +msgid "Texture colors applied." +msgstr "Colori della trama applicati." + msgid "You can keep the modified presets for the new project or discard them" msgstr "È possibile conservare i profili modificati per il nuovo progetto o scartarli" @@ -9654,6 +9722,10 @@ msgstr "Vaso a spirale" msgid "First layer filament sequence" msgstr "Sequenza filamenti primo strato" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "L'elenco dei filamenti contiene filamenti misti. La sequenza di filamenti personalizzata non avrà effetto." + msgid "By Layer" msgstr "Per strato" @@ -11571,27 +11643,6 @@ msgstr "Volumi di spurgo per cambio filamento" msgid "Please choose the filament colour" msgstr "Scegliere il colore del filamento" -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "La funzione di visualizzazione in tempo reale nativa di Wayland richiede il ricevitore video GTK di GStreamer. Installare il modulo gtksink per GStreamer e riavviare OrcaSlicer." - -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Impossibile inizializzare il ricevitore video nativo di Wayland GStreamer. Verificare l'installazione del modulo GTK di GStreamer." - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "Per questa operazione è necessario Windows Media Player! Desideri abilitare 'Windows Media Player' sul il tuo sistema operativo?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource non è stato registrato correttamente per la riproduzione multimediale! Fare clic su Sì per effettuare nuovamente la registrazione. Sarai promosso due volte" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Componente BambuSource mancante per la riproduzione multimediale! Reinstallare OrcaSlicer o cercare aiuto nella comunità." - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "È in uso una versione di BambuSource da un'installazione diversa. La riproduzione video potrebbe non funzionare correttamente! Fare clic su Sì per risolvere il problema." - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "Nel tuo sistema mancano i codec H.264 per GStreamer, necessari per riprodurre i video. (Provare a installare i pacchetti gstreamer1.0-plugins-bad o gstreamer1.0-libav e riavviare OrcaSlicer?)" - msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "Il fornitore di servizi cloud non è disponibile. Riavviare OrcaSlicer e riprovare." @@ -12303,6 +12354,10 @@ msgstr "Se desideri comunque stampare, puoi abilitare l'opzione in Preferenze / msgid "No extrusions under current settings." msgstr "Nessuna estrusione con le impostazioni attuali." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "È in uso un filamento misto con gradiente, ma 'Sottostrato di colore misto' è disattivato. Il gradiente non verrà stampato." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "La modalità fluida del timelapse non è supportata quando è abilitata la sequenza \"Per oggetto\"." @@ -12339,6 +12394,10 @@ msgstr "È possibile ridurre le dimensioni del modello o modificare le impostazi msgid "Variable layer height is not supported with Organic supports." msgstr "Altezza strato adattiva non è compatibile con i Supporti organici." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "Il filamento della torre di spurgo non può essere un filamento misto." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Ugelli e filamenti di diverso diametro potrebbero non funzionare correttamente quando è abilitata la torre di spurgo. Questa funzione è sperimentale, quindi procedere con cautela." @@ -14082,6 +14141,8 @@ msgstr "Durata strato" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "La ventola di raffreddamento verrà attivata per gli strati in cui il tempo stimato è inferiore a questo valore. La velocità della ventola varierà tra la velocità minima e massima in base alla durata stimata di stampa dello strato." +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -14388,6 +14449,62 @@ msgstr "Materiale di supporto" msgid "Support material is commonly used to print supports and support interfaces." msgstr "Il materiale di supporto viene comunemente utilizzato per stampare supporti e interfacce di supporto." +# AI Translated +msgid "Is mixed filament" +msgstr "È filamento misto" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Indica se questo slot di filamento è un filamento misto composto da più filamenti fisici" + +# AI Translated +msgid "Mixed filament components" +msgstr "Componenti del filamento misto" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Indici (a partire da 1) dei filamenti componenti, separati da virgole; es. \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Proporzioni dei sottostrati del filamento misto" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Valori di proporzione separati da virgole la cui somma sia 1.0; es. \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Gradiente del filamento misto" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Attiva la modalità gradiente in direzione Z per i sottostrati del filamento misto. Se attivata, le proporzioni dei sottostrati variano linearmente tra gli strati." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Intervallo del gradiente del filamento misto" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Proporzioni iniziale e finale del primo componente in modalità gradiente. Coppia separata da virgola; es. \"0.10,0.90\" significa dal 10% al 90%." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Curva del gradiente del filamento misto" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Curva personalizzata opzionale, in stile Photoshop, che mappa l'avanzamento in Z sulla proporzione del primo componente. Codificata come punti di controllo separati da barre verticali, nel formato \"x,y\" (legacy) oppure \"x,y,m_in,m_out\" quando è necessario forzare la tangente (un valore vuoto o \"nan\" usa il valore PCHIP predefinito). x è compreso in [0,1]; y viene limitato all'intervallo di proporzioni configurato; es. \"0,0.15|0.5,0.50|1,0.85\". Se vuoto, viene usato il gradient_range lineare." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Gradiente per parte del filamento misto" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Quando la modalità gradiente è attiva, applica il gradiente a ciascuna parte di un assemblaggio in modo indipendente anziché trattare l'intero assemblaggio come un unico intervallo Z." + msgid "Filament printable" msgstr "Filamento stampabile" @@ -15655,6 +15772,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "La forza di uscita massima consentita dell'asse Y" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -15665,6 +15783,7 @@ msgid "The machine bed mass load of Y axis" msgstr "Il carico di massa del piano della macchina sull'asse Y" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -17258,6 +17377,14 @@ msgstr "" "\n" "Impostando un valore di quantità di retrazione prima dell'impostazione di spurgo di seguito, verra eseguita qualsiasi retrazione in eccesso prima dello spurgo. Altrimenti verrà eseguita dopo." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Sottostrato di colore misto" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Attiva la suddivisione in sottostrati di colore misto. Se attivata, gli strati che contengono filamenti a colore misto vengono suddivisi in sottostrati per ottenere effetti di miscelazione dei colori." + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "La torre di spurgo può essere utilizzata per pulire i residui presenti sull'ugello e stabilizzare la pressione della camera all'interno dell'ugello, al fine di evitare difetti estetici durante la stampa." @@ -18329,6 +18456,10 @@ msgstr "La generazione della mesh del file del modello è fallita o la forma non msgid "The supplied file couldn't be read because it's empty." msgstr "Impossibile leggere il file fornito perché è vuoto" +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "Il formato del file non è compatibile e non può essere interpretato." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Formato file sconosciuto: il file di input deve avere un'estensione .stl, .obj o .amf(.xml)." @@ -20672,8 +20803,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "Abilita l'assegnazione intelligente del filamento: assegna un filamento a più ugelli per massimizzare il risparmio" # AI Translated -msgid "Fila Saving" -msgstr "Risparmio filamento" +msgid "File Saving" +msgstr "Salvataggio file" msgid "Don't remind me again" msgstr "Non ricordarmelo più" @@ -21082,6 +21213,9 @@ msgstr "Riavvia ora" msgid "NO RAMMING AT ALL" msgstr "NESSUNA SPINTA" +msgid "s" +msgstr "s" + msgid "Volumetric speed" msgstr "Velocità volumetrica" @@ -21733,6 +21867,39 @@ msgstr "" "Evita le deformazioni\n" "Sapevi che quando si stampano materiali soggetti a deformazioni come l'ABS, aumentare in modo appropriato la temperatura del piano riscaldato può ridurre la probabilità di deformazione?" +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "La funzione di visualizzazione in tempo reale nativa di Wayland richiede il ricevitore video GTK di GStreamer. Installare il modulo gtksink per GStreamer e riavviare OrcaSlicer." + +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "Impossibile inizializzare il ricevitore video nativo di Wayland GStreamer. Verificare l'installazione del modulo GTK di GStreamer." + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "Per questa operazione è necessario Windows Media Player! Desideri abilitare 'Windows Media Player' sul il tuo sistema operativo?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource non è stato registrato correttamente per la riproduzione multimediale! Fare clic su Sì per effettuare nuovamente la registrazione. Sarai promosso due volte" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "Componente BambuSource mancante per la riproduzione multimediale! Reinstallare OrcaSlicer o cercare aiuto nella comunità." + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "È in uso una versione di BambuSource da un'installazione diversa. La riproduzione video potrebbe non funzionare correttamente! Fare clic su Sì per risolvere il problema." + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "Nel tuo sistema mancano i codec H.264 per GStreamer, necessari per riprodurre i video. (Provare a installare i pacchetti gstreamer1.0-plugins-bad o gstreamer1.0-libav e riavviare OrcaSlicer?)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "Risparmio filamento" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/ja/OrcaSlicer_ja.po b/localization/i18n/ja/OrcaSlicer_ja.po index 9c819dd7c1..8ee8813f1d 100644 --- a/localization/i18n/ja/OrcaSlicer_ja.po +++ b/localization/i18n/ja/OrcaSlicer_ja.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -2969,6 +2969,10 @@ msgstr "編集" msgid "Merge with" msgstr "結合" +# AI Translated +msgid "Decompose Color" +msgstr "色を分解" + msgid "Delete this filament" msgstr "このフィラメントを削除" @@ -3266,6 +3270,10 @@ msgstr "アセンブリ" msgid "Merge parts to an object" msgstr "パーツをオブジェクトに結合" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "可変積層ピッチと混色サブレイヤーを併用すると、混色の品質が低下する場合があります。" + # AI Translated msgid "Add layers" msgstr "積層を追加" @@ -7859,6 +7867,10 @@ msgstr "現在のプレートをカスタマイズ" msgid "The %s nozzle can not print %s." msgstr "%sノズルは%sを印刷できません。" +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "単一押出機のプリンターで混色フィラメントを印刷すると、フィラメント交換とフラッシュが頻繁に発生し、廃材やノズル/廃棄シュートの詰まりのリスクが大幅に増加する可能性があります。" + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "%1%と%2%を混合して印刷することは推奨されません。\n" @@ -7984,12 +7996,44 @@ msgstr "AMSと素材を同期" msgid "Set filaments to use" msgstr "フィラメントを選択" +# AI Translated +msgid "Add Mixed Filament" +msgstr "混合フィラメントを追加" + +# AI Translated +msgid "Mixed Filament" +msgstr "混合フィラメント" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "最後の混合フィラメントを削除" + +# AI Translated +msgid "Add mixed filament" +msgstr "混合フィラメントを追加" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "混合フィラメントのコンポーネントが無効か一致していません。該当する項目を編集し直してください。" + msgid "Search plate, object and part." msgstr "プレート、オブジェクト、パーツを検索。" msgid "Pellets" msgstr "ペレット" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "混合フィラメントのコンポーネント参照が壊れています" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "編集 / 削除 / 結合" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "対象の混合フィラメントはこの物理フィラメントをコンポーネントとして使用しています。結合するとこの物理フィラメントは削除され、混合フィラメントが無効になる可能性があります。続行しますか?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "操作完了後、%sプロジェクトが閉じられ、新しいプロジェクトが作成されます。" @@ -8176,6 +8220,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "マルチパーツ検出" +# AI Translated +msgid "Matching textures to filaments" +msgstr "テクスチャをフィラメントに対応付けています" + +# AI Translated +msgid "Texture Import Warning" +msgstr "テクスチャインポートの警告" + msgid "Load these files as a single object with multiple parts?\n" msgstr "これらのファイルを一つのオブジェクトとしてロードしますか?\n" @@ -8389,6 +8441,22 @@ msgstr "" msgid "Sync now" msgstr "今すぐ同期" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "テクスチャのインポートに失敗しました。モデルにテクスチャデータが含まれているようですが、インポート処理を完了できませんでした。モデルはジオメトリのみとしてインポートされます。" + +# AI Translated +msgid "Applying texture colors..." +msgstr "テクスチャの色を適用しています..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "3Dビューを更新しています..." + +# AI Translated +msgid "Texture colors applied." +msgstr "テクスチャの色を適用しました。" + msgid "You can keep the modified presets for the new project or discard them" msgstr "変更したプリセットをプロジェクト内に保存するか、破棄もできます" @@ -9676,6 +9744,10 @@ msgstr "スパイラル" msgid "First layer filament sequence" msgstr "初期レイヤーフィラメント順序" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "フィラメントリストに混合フィラメントが含まれています。カスタムフィラメント順序は適用されません。" + msgid "By Layer" msgstr "レイヤー別" @@ -11591,33 +11663,6 @@ msgstr "フィラメントを入替える為のフラッシュ量" msgid "Please choose the filament colour" msgstr "フィラメントの色を選択してください" -# AI Translated -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "ネイティブWaylandのライブビューにはGStreamer GTKビデオシンクが必要です。GStreamer用のgtksinkプラグインをインストールし、OrcaSlicerを再起動してください。" - -# AI Translated -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "ネイティブWaylandのGStreamerビデオシンクの初期化に失敗しました。GStreamer GTKプラグインのインストール状況をご確認ください。" - -# AI Translated -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "このタスクにはWindows Media Playerが必要です!お使いのOSで「Windows Media Player」を有効にしますか?" - -# AI Translated -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "メディア再生用のBambuSourceが正しく登録されていません!「はい」を押して再登録してください。確認が2回表示されます" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "メディア再生用のBambuSourceコンポーネントが見つかりません!OrcaSlicerを再インストールするかコミュニティに助けを求めてください。" - -# AI Translated -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "別のインストール環境のBambuSourceを使用しているため、動画が正しく再生されない可能性があります!「はい」を押して修正してください。" - -# AI Translated -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "お使いのシステムには、動画再生に必要なGStreamer用のH.264コーデックがありません。(gstreamer1.0-plugins-badまたはgstreamer1.0-libavパッケージをインストールし、Orca Slicerを再起動してみてください)" - # AI Translated msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "クラウドエージェントが利用できません。OrcaSlicerを再起動して再試行してください。" @@ -12343,6 +12388,10 @@ msgstr "それでも印刷する場合は、環境設定 / 制御 / スライス msgid "No extrusions under current settings." msgstr "現在の設定では造形しません" +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "グラデーション付きの混合フィラメントが使用されていますが、「混色サブレイヤー」が無効です。グラデーションは印刷されません。" + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "オブジェクト順で造形するでは、この機能を使用できません。" @@ -12379,6 +12428,10 @@ msgstr "モデルのサイズを小さくするか、現在のプリント設定 msgid "Variable layer height is not supported with Organic supports." msgstr "可変レイヤー高さはオーガニックサポートではサポートされていません。" +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "ワイプタワーのフィラメントに混合フィラメントは使用できません。" + # AI Translated msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "ノズル径やフィラメント径が異なる場合、プライムタワーを有効にすると正しく動作しないことがあります。非常に実験的な機能ですので、慎重にお進みください。" @@ -12756,29 +12809,23 @@ msgstr "mm 或は %" msgid "Other layers" msgstr "他の層" -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "1層目を除く各層のベッド温度です。0の場合、そのフィラメントはCool Plate SuperTackでの印刷に対応していません。" -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "ベッドの温度です(1層目以外)。値が0の場合、フィラメントが常温プレートで使用できないという意味です。" -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured Cool Plate." msgstr "1層目を除く各層のベッド温度です。0の場合、そのフィラメントはTextured Cool Plateでの印刷に対応していません。" -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Engineering Plate." msgstr "ベッドの温度です(1層目以外)。値が0の場合、フィラメントがエンジニアリング プレートで使用できないという意味です。" -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the High Temp Plate." msgstr "ベッドの温度です(1層目以外)。値が0の場合、フィラメントが高温プレートで使用できないという意味です。" -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured PEI Plate." -msgstr "1層目以外のベッド温度。値が0の場合、フィラメントがPEIプレートをサポートしない意味をします。" +msgstr "1層目を除く各層のベッド温度です。0の場合、そのフィラメントはTextured PEI Plateでの印刷に対応していません。" msgid "First layer" msgstr "1層目" @@ -14204,6 +14251,8 @@ msgstr "積層時間" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "パーツ冷却ファンは、積層造形時間がこの値より短い時に作動します。" +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -14522,6 +14571,62 @@ msgstr "サポート材料" msgid "Support material is commonly used to print supports and support interfaces." msgstr "サポート素材は、サポート又はサポート接触面の造形によく使われます。" +# AI Translated +msgid "Is mixed filament" +msgstr "混合フィラメントかどうか" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "このフィラメントスロットが複数の物理フィラメントで構成される混合フィラメントかどうか" + +# AI Translated +msgid "Mixed filament components" +msgstr "混合フィラメントのコンポーネント" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "構成フィラメントの番号(1 始まり)をカンマ区切りで指定します。例: \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "混合フィラメントのサブレイヤー比率" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "合計が 1.0 になる比率をカンマ区切りで指定します。例: \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "混合フィラメントのグラデーション" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "混合フィラメントのサブレイヤーに対して Z 方向のグラデーションモードを有効にします。有効にすると、サブレイヤーの比率が積層ごとに直線的に変化します。" + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "混合フィラメントのグラデーション範囲" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "グラデーションモードにおける最初のコンポーネントの開始比率と終了比率。カンマ区切りの 2 つの値で指定します。例: \"0.10,0.90\" は 10% から 90% を意味します。" + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "混合フィラメントのグラデーションカーブ" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Z 方向の進行度を最初のコンポーネントの比率に対応付ける、Photoshop 風のカスタムカーブ(省略可)。制御点を縦棒区切りでエンコードし、\"x,y\"(旧形式)または接線を上書きする場合は \"x,y,m_in,m_out\" の形式で指定します(空欄または \"nan\" は PCHIP の既定値を使用します)。x は [0,1] の範囲で、y は設定された比率範囲に制限されます。例: \"0,0.15|0.5,0.50|1,0.85\"。空欄の場合は線形の gradient_range が使用されます。" + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "混合フィラメントのパーツ別グラデーション" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "グラデーションモードが有効な場合、アセンブリ全体を 1 つの Z 範囲として扱うのではなく、アセンブリ内の各パーツに個別にグラデーションを適用します。" + msgid "Filament printable" msgstr "フィラメント印刷可能" @@ -15898,6 +16003,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "Y軸の許容最大出力" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -15908,6 +16014,7 @@ msgid "The machine bed mass load of Y axis" msgstr "Y軸のマシンベッド質量" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -17637,6 +17744,14 @@ msgstr "" "\n" "下の「ワイプ前のリトラクション量」設定に値を設定すると、超過分のリトラクションはワイプの前に行われます。それ以外の場合はワイプの後に行われます。" +# AI Translated +msgid "Mixed color sublayer" +msgstr "混色サブレイヤー" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "混色サブレイヤーへの分割を有効にします。有効にすると、混色フィラメントを含む積層がサブレイヤーに分割され、色を混ぜる効果が得られます。" + # AI Translated msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "ワイプタワーは、ノズルに残った樹脂を除去し、ノズル内のチャンバー圧力を安定させることで、オブジェクト印刷時の外観不良を防ぐために使用できます。" @@ -18808,6 +18923,10 @@ msgstr "モデルファイルのメッシュ処理に失敗したか、有効な msgid "The supplied file couldn't be read because it's empty." msgstr "提供されたファイルは空であるため読み込めませんでした。" +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "ファイル形式に互換性がないため、解析できません。" + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "ファイル形式が不明です。入力ファイルの拡張子は .stl、.obj、.amf(.xml)である必要があります。" @@ -21230,8 +21349,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "スマートフィラメント割り当てを有効にする: 1つのフィラメントを複数のノズルに割り当てて節約を最大化します" # AI Translated -msgid "Fila Saving" -msgstr "フィラ節約" +msgid "File Saving" +msgstr "ファイル保存" msgid "Don't remind me again" msgstr "再度通知しない" @@ -21638,6 +21757,9 @@ msgstr "今すぐ再起動" msgid "NO RAMMING AT ALL" msgstr "ラミングなし" +msgid "s" +msgstr "s" + msgid "Volumetric speed" msgstr "体積速度" @@ -22300,6 +22422,45 @@ msgstr "" "反りを避ける\n" "ABSのような反りやすい素材を印刷する場合、ヒートベッドの温度を適切に上げることで、反りが発生する確率を下げることができることをご存知ですか?" +# AI Translated +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "ネイティブWaylandのライブビューにはGStreamer GTKビデオシンクが必要です。GStreamer用のgtksinkプラグインをインストールし、OrcaSlicerを再起動してください。" + +# AI Translated +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "ネイティブWaylandのGStreamerビデオシンクの初期化に失敗しました。GStreamer GTKプラグインのインストール状況をご確認ください。" + +# AI Translated +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "このタスクにはWindows Media Playerが必要です!お使いのOSで「Windows Media Player」を有効にしますか?" + +# AI Translated +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "メディア再生用のBambuSourceが正しく登録されていません!「はい」を押して再登録してください。確認が2回表示されます" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "メディア再生用のBambuSourceコンポーネントが見つかりません!OrcaSlicerを再インストールするかコミュニティに助けを求めてください。" + +# AI Translated +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "別のインストール環境のBambuSourceを使用しているため、動画が正しく再生されない可能性があります!「はい」を押して修正してください。" + +# AI Translated +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "お使いのシステムには、動画再生に必要なGStreamer用のH.264コーデックがありません。(gstreamer1.0-plugins-badまたはgstreamer1.0-libavパッケージをインストールし、Orca Slicerを再起動してみてください)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "フィラ節約" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/ko/OrcaSlicer_ko.po b/localization/i18n/ko/OrcaSlicer_ko.po index 61d785ef2e..c415c90195 100644 --- a/localization/i18n/ko/OrcaSlicer_ko.po +++ b/localization/i18n/ko/OrcaSlicer_ko.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: 2025-06-02 17:12+0900\n" "Last-Translator: crwusiz <crwusiz@gmail.com>\n" "Language-Team: \n" @@ -2970,6 +2970,10 @@ msgstr "편집" msgid "Merge with" msgstr "병합" +# AI Translated +msgid "Decompose Color" +msgstr "색상 분해" + msgid "Delete this filament" msgstr "이 필라멘트 삭제" @@ -3266,6 +3270,10 @@ msgstr "조립" msgid "Merge parts to an object" msgstr "부품을 하나의 객체로 병합" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "가변 레이어 높이를 혼색 서브레이어와 함께 사용하면 색상 혼합 품질이 떨어질 수 있습니다." + # AI Translated msgid "Add layers" msgstr "레이어 추가" @@ -7871,6 +7879,10 @@ msgstr "사용자 정의 플레이트" msgid "The %s nozzle can not print %s." msgstr "%s 노즐은 %s 을 인쇄할 수 없습니다." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "단일 압출기 프린터에서 혼색 필라멘트를 출력하면 필라멘트 교체와 플러시가 자주 발생하여 낭비되는 재료와 노즐 / 폐기물 슈트 막힘 위험이 크게 늘어날 수 있습니다." + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "%1%와 %2% 혼합 출력을 권장하지 않습니다.\n" @@ -7997,12 +8009,44 @@ msgstr "AMS에서 필라멘트 목록 동기화" msgid "Set filaments to use" msgstr "사용할 필라멘트 설정" +# AI Translated +msgid "Add Mixed Filament" +msgstr "혼합 필라멘트 추가" + +# AI Translated +msgid "Mixed Filament" +msgstr "혼합 필라멘트" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "마지막 혼합 필라멘트 제거" + +# AI Translated +msgid "Add mixed filament" +msgstr "혼합 필라멘트 추가" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "혼합 필라멘트의 구성 요소가 잘못되었거나 일치하지 않습니다. 해당 항목을 다시 편집하세요." + msgid "Search plate, object and part." msgstr "플레이트, 객체 및 부품을 검색합니다." msgid "Pellets" msgstr "펠릿" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "혼합 필라멘트의 구성 요소 참조가 손상되었습니다" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "편집 / 삭제 / 병합" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "대상 혼합 필라멘트가 이 물리 필라멘트를 구성 요소로 사용합니다. 병합하면 이 물리 필라멘트가 제거되어 혼합 필라멘트가 무효가 될 수 있습니다. 계속할까요?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "작업을 완료하면 %s 프로젝트가 닫히고 새 프로젝트가 만들어집니다." @@ -8195,6 +8239,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "여러 부품으로 구성된 객체 감지됨" +# AI Translated +msgid "Matching textures to filaments" +msgstr "텍스처를 필라멘트에 매칭하는 중" + +# AI Translated +msgid "Texture Import Warning" +msgstr "텍스처 가져오기 경고" + msgid "Load these files as a single object with multiple parts?\n" msgstr "이 파일을 여러 부품이 있는 단일 객체로 로드하시겠습니까?\n" @@ -8423,6 +8475,22 @@ msgstr "" msgid "Sync now" msgstr "지금 동기화" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "텍스처 가져오기에 실패했습니다. 모델에 텍스처 데이터가 포함된 것으로 보이지만 텍스처 가져오기 과정을 완료하지 못했습니다. 모델은 형상만 가져옵니다." + +# AI Translated +msgid "Applying texture colors..." +msgstr "텍스처 색상 적용 중..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "3D 뷰 업데이트 중..." + +# AI Translated +msgid "Texture colors applied." +msgstr "텍스처 색상이 적용되었습니다." + msgid "You can keep the modified presets for the new project or discard them" msgstr "수정된 사전 설정을 새 프로젝트에 유지하거나 삭제할 수 있습니다" @@ -9766,6 +9834,10 @@ msgstr "나선형 꽃병 모드" msgid "First layer filament sequence" msgstr "첫 번째 레이어 필라멘트 순서" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "필라멘트 목록에 혼합 필라멘트가 있습니다. 사용자 지정 필라멘트 순서는 적용되지 않습니다." + msgid "By Layer" msgstr "레이어별" @@ -11723,30 +11795,6 @@ msgstr "필라멘트 교체를 위한 버리기 볼륨" msgid "Please choose the filament colour" msgstr "필라멘트 색상을 선택하세요" -# AI Translated -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "네이티브 Wayland 실시간 보기에는 GStreamer GTK 비디오 싱크가 필요합니다. GStreamer용 gtksink 플러그인을 설치한 후 OrcaSlicer를 다시 시작하십시오." - -# AI Translated -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "네이티브 Wayland GStreamer 비디오 싱크를 초기화하지 못했습니다. GStreamer GTK 플러그인 설치 상태를 확인하십시오." - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "이 작업에는 Windows Media Player가 필요합니다! 운영 체제에서 Windows Media Player를 활성화하시겠습니까?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "뱀부소스가 미디어 재생에 올바르게 등록되지 않았습니다! 다시 등록하려면 예를 누르세요. 두 번 승격됩니다" - -# AI Translated -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "미디어 재생용으로 등록된 BambuSource 구성 요소가 없습니다! OrcaSlicer를 다시 설치하거나 커뮤니티에 도움을 요청하십시오." - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "다른 설치 버전의 뱀부소스를 사용하면 동영상 재생이 제대로 작동하지 않을 수 있습니다! 예를 눌러 문제를 해결하세요." - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "시스템에 동영상 재생을 위해 필요한 GStreamer용 H.264 코덱이 존재하지 않습니다. (gstreamer1.0-plugins-bad 또는 gstreamer1.0-libav 패키지를 설치한 다음 Orca Slicer를 다시 실행하십시오.)" - # AI Translated msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "클라우드 에이전트를 사용할 수 없습니다. OrcaSlicer를 다시 시작한 후 다시 시도하십시오." @@ -12475,6 +12523,10 @@ msgstr "그래도 출력하려면 기본 설정 / 제어 / 슬라이싱 / 혼합 msgid "No extrusions under current settings." msgstr "현재 설정에 압출기가 없습니다." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "그라데이션 혼합 필라멘트가 사용 중이지만 '혼색 서브레이어'가 비활성화되어 있습니다. 그라데이션은 출력되지 않습니다." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "타임랩스의 유연 모드는 \"객체별\" 출력순서가 활성화된 경우 지원되지 않습니다." @@ -12513,6 +12565,10 @@ msgstr "모델 크기를 줄이거나 현재 출력 설정을 변경하고 다 msgid "Variable layer height is not supported with Organic supports." msgstr "유기체 서포트에서는 가변 레이어 높이가 지원되지 않습니다." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "프라임 타워 필라멘트는 혼합 필라멘트일 수 없습니다." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "프라임 타워를 활성화하면 노즐 직경과 필라멘트 직경이 다르면 제대로 작동하지 않을 수 있습니다. 매우 실험적인 기능이므로 주의해서 사용하시기 바랍니다." @@ -12889,27 +12945,21 @@ msgstr "mm 또는 %" msgid "Other layers" msgstr "다른 레이어" -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "초기 레이어를 제외한 레이어의 베드 온도입니다. 값이 0이면 해당 필라멘트가 쿨 플레이트 슈퍼택에서의 출력을 지원하지 않음을 의미합니다." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "초기 레이어를 제외한 레이어의 베드 온도. 값 0은 필라멘트가 쿨 플레이트 출력을 지원하지 않음을 의미합니다." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured Cool Plate." msgstr "초기 레이어를 제외한 레이어의 베드 온도입니다. 값 0은 필라멘트가 텍스처드 쿨 플레이트에서 출력를 지원하지 않음을 의미합니다." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Engineering Plate." msgstr "초기 레이어를 제외한 레이어의 베드 온도. 값 0은 필라멘트가 엔지니어링 플레이트 출력을 지원하지 않음을 의미합니다." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the High Temp Plate." msgstr "초기 레이어를 제외한 레이어의 베드 온도. 값 0은 필라멘트가 고온 플레이트 출력을 지원하지 않음을 의미합니다." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured PEI Plate." msgstr "초기 레이어를 제외한 레이어의 베드 온도. 값 0은 필라멘트가 텍스처 PEI 플레이트 출력을 지원하지 않음을 의미합니다." @@ -14312,6 +14362,8 @@ msgstr "레이어 시간" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "예상 시간이 이 값보다 짧은 레이어에 대해 출력물 냉각 팬이 활성화됩니다. 팬 속도는 레이어 출력 시간에 따라 최소 및 최대 팬 속도 사이에서 보간됩니다" +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -14625,6 +14677,62 @@ msgstr "서포트 재료" msgid "Support material is commonly used to print supports and support interfaces." msgstr "서포트 재료는 일반적으로 서포트 및 서포트 접점을 출력하는 데 사용됩니다" +# AI Translated +msgid "Is mixed filament" +msgstr "혼합 필라멘트 여부" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "이 필라멘트 슬롯이 여러 물리 필라멘트로 구성된 혼합 필라멘트인지 여부" + +# AI Translated +msgid "Mixed filament components" +msgstr "혼합 필라멘트 구성 요소" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "구성 필라멘트의 1부터 시작하는 인덱스를 쉼표로 구분하여 입력합니다. 예: \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "혼합 필라멘트 서브레이어 비율" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "합이 1.0이 되는 비율 값을 쉼표로 구분하여 입력합니다. 예: \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "혼합 필라멘트 그라데이션" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "혼합 필라멘트 서브레이어에 대해 Z 방향 그라데이션 모드를 활성화합니다. 활성화하면 서브레이어 비율이 레이어에 따라 선형으로 변합니다." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "혼합 필라멘트 그라데이션 범위" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "그라데이션 모드에서 첫 번째 구성 요소의 시작 및 종료 비율입니다. 쉼표로 구분된 한 쌍이며, 예를 들어 \"0.10,0.90\"은 10%에서 90%를 의미합니다." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "혼합 필라멘트 그라데이션 곡선" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Z 진행도를 첫 번째 구성 요소의 비율에 매핑하는 선택적 Photoshop 스타일 사용자 지정 곡선입니다. 제어점을 세로줄로 구분하여 \"x,y\"(레거시) 또는 접선을 재정의해야 할 때는 \"x,y,m_in,m_out\" 형식으로 인코딩합니다(빈 값 또는 \"nan\"은 PCHIP 기본값을 사용). x는 [0,1] 범위이며, y는 설정된 비율 범위로 제한됩니다. 예: \"0,0.15|0.5,0.50|1,0.85\". 비워 두면 대신 선형 gradient_range가 사용됩니다." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "혼합 필라멘트 부품별 그라데이션" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "그라데이션 모드가 활성화되면 조립 전체를 하나의 Z 범위로 처리하지 않고 조립의 각 부품에 그라데이션을 개별적으로 적용합니다." + msgid "Filament printable" msgstr "필라멘트 출력 가능" @@ -15943,6 +16051,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "Y축의 허용 최대 출력 힘" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -15953,6 +16062,7 @@ msgid "The machine bed mass load of Y axis" msgstr "Y축 장비 베드 질량 하중" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -17584,6 +17694,14 @@ msgstr "" "\n" "아래의 와이프 전 후퇴량 설정에서 값을 설정하면 와이프 전에 초과 후퇴가 수행되고, 그렇지 않으면 와이프 후에 수행됩니다." +# AI Translated +msgid "Mixed color sublayer" +msgstr "혼색 서브레이어" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "혼색 서브레이어 분할을 활성화합니다. 활성화하면 혼색 필라멘트가 포함된 레이어가 서브레이어로 분할되어 색상 혼합 효과를 얻습니다." + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "프라임 타워는 객체를 출력할 때 외관 결함을 방지하기 위해 노즐의 잔류물을 청소하고 노즐 내부의 압력을 안정화하는 데 사용할 수 있습니다." @@ -18687,6 +18805,10 @@ msgstr "모델 파일의 메싱이 실패했거나 유효한 형태가 없습니 msgid "The supplied file couldn't be read because it's empty." msgstr "제공된 파일이 비어 있어 읽을 수 없습니다" +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "파일 형식이 호환되지 않아 해석할 수 없습니다." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "알 수 없는 파일 형식: 입력 파일의 확장자는 .stl, .obj 또는 .amf(.xml)여야 합니다." @@ -21080,8 +21202,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "스마트 필라멘트 할당 활성화: 하나의 필라멘트를 여러 노즐에 할당하여 절약을 극대화합니다" # AI Translated -msgid "Fila Saving" -msgstr "필라멘트 절약" +msgid "File Saving" +msgstr "파일 저장" msgid "Don't remind me again" msgstr "다시 알리지 마세요" @@ -21511,6 +21633,9 @@ msgstr "지금 다시 시작" msgid "NO RAMMING AT ALL" msgstr "채워넣기 전혀 없음" +msgid "s" +msgstr "s" + # AI Translated msgid "Volumetric speed" msgstr "압출 속도" @@ -22164,6 +22289,42 @@ msgstr "" "뒤틀림 방지\n" "ABS와 같이 뒤틀림이 발생하기 쉬운 소재를 출력할 때, 히트베드 온도를 적절하게 높이면 뒤틀림 가능성을 줄일 수 있다는 사실을 알고 계셨나요?" +# AI Translated +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "네이티브 Wayland 실시간 보기에는 GStreamer GTK 비디오 싱크가 필요합니다. GStreamer용 gtksink 플러그인을 설치한 후 OrcaSlicer를 다시 시작하십시오." + +# AI Translated +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "네이티브 Wayland GStreamer 비디오 싱크를 초기화하지 못했습니다. GStreamer GTK 플러그인 설치 상태를 확인하십시오." + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "이 작업에는 Windows Media Player가 필요합니다! 운영 체제에서 Windows Media Player를 활성화하시겠습니까?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "뱀부소스가 미디어 재생에 올바르게 등록되지 않았습니다! 다시 등록하려면 예를 누르세요. 두 번 승격됩니다" + +# AI Translated +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "미디어 재생용으로 등록된 BambuSource 구성 요소가 없습니다! OrcaSlicer를 다시 설치하거나 커뮤니티에 도움을 요청하십시오." + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "다른 설치 버전의 뱀부소스를 사용하면 동영상 재생이 제대로 작동하지 않을 수 있습니다! 예를 눌러 문제를 해결하세요." + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "시스템에 동영상 재생을 위해 필요한 GStreamer용 H.264 코덱이 존재하지 않습니다. (gstreamer1.0-plugins-bad 또는 gstreamer1.0-libav 패키지를 설치한 다음 Orca Slicer를 다시 실행하십시오.)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "필라멘트 절약" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/lt/OrcaSlicer_lt.po b/localization/i18n/lt/OrcaSlicer_lt.po index e1ce2f18b2..b3458ec0e4 100644 --- a/localization/i18n/lt/OrcaSlicer_lt.po +++ b/localization/i18n/lt/OrcaSlicer_lt.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: 2026-07-02 14:13+0300\n" "Last-Translator: Gintaras Kučinskas <sharanchius@gmail.com>\n" "Language-Team: \n" @@ -2936,6 +2936,10 @@ msgstr "Redaguoti" msgid "Merge with" msgstr "Sujungti su" +# AI Translated +msgid "Decompose Color" +msgstr "Išskaidyti spalvą" + msgid "Delete this filament" msgstr "Ištrinti šią giją" @@ -3237,6 +3241,10 @@ msgstr "Surinkimas" msgid "Merge parts to an object" msgstr "Sujungti dalis į objektą" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "Kintamo sluoksnio aukščio naudojimas kartu su mišrios spalvos posluoksniu gali pabloginti spalvų maišymo kokybę." + # AI Translated msgid "Add layers" msgstr "Pridėti sluoksnių" @@ -7834,6 +7842,10 @@ msgstr "Individualizuoti esamą plokštę" msgid "The %s nozzle can not print %s." msgstr "%s purkštukas negali spausdinti %s." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "Spausdinant mišrios spalvos giją vieno ekstruderio spausdintuvu reikia dažnai keisti giją ir pravalyti, todėl gali gerokai padidėti atliekų kiekis ir purkštuko arba atliekų latako užsikimšimo rizika." + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "" @@ -7967,12 +7979,44 @@ msgstr "Sinchronizuoti gijų sąrašą iš AMS" msgid "Set filaments to use" msgstr "Nustatyti gijas naudojimui" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Pridėti mišrią giją" + +# AI Translated +msgid "Mixed Filament" +msgstr "Mišri gija" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Pašalinti paskutinę mišrią giją" + +# AI Translated +msgid "Add mixed filament" +msgstr "Pridėti mišrią giją" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "Mišri gija turi netinkamų arba neatitinkančių komponentų. Iš naujo suredaguokite susijusius įrašus." + msgid "Search plate, object and part." msgstr "Plokštės, objekto ir dalies paieška." msgid "Pellets" msgstr "Granulės" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "Mišri gija turi sugadintų komponentų nuorodų" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Redaguoti / Ištrinti / Sujungti" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "Paskirties mišri gija naudoja šią fizinę giją kaip komponentą. Sujungus ši fizinė gija bus pašalinta ir mišri gija gali tapti netinkama. Tęsti?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "Baigus šią operaciją, projektas „%s“ bus uždarytas ir bus sukurtas naujas projektas." @@ -8151,6 +8195,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Aptiktas kelių dalių objektas" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Tekstūros priskiriamos gijoms" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Tekstūros importavimo įspėjimas" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Ar įkelti šiuos failus kaip vieną objektą su keliomis detalėmis?\n" @@ -8365,6 +8417,22 @@ msgstr "" msgid "Sync now" msgstr "Sinchronizuoti dabar" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "Tekstūros importuoti nepavyko. Panašu, kad modelyje yra tekstūros duomenų, tačiau importavimo proceso nepavyko užbaigti. Modelis bus importuotas tik kaip geometrija." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Taikomos tekstūros spalvos..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "Atnaujinamas 3D vaizdas..." + +# AI Translated +msgid "Texture colors applied." +msgstr "Tekstūros spalvos pritaikytos." + msgid "You can keep the modified presets for the new project or discard them" msgstr "Pakeistus profilius galite išsaugoti naujam projektui arba juos atmesti" @@ -9594,6 +9662,10 @@ msgstr "Spiralinė vaza" msgid "First layer filament sequence" msgstr "Pirmojo sluoksnio gijos eiga" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "Gijų sąraše yra mišrių gijų. Pasirinktinė gijų seka nebus taikoma." + msgid "By Layer" msgstr "Pagal sluoksnį" @@ -11497,27 +11569,6 @@ msgstr "Išmetimo tūris keičiant gijas" msgid "Please choose the filament colour" msgstr "Pasirinkite gijos spalvą" -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "Tiesioginei „Native Wayland“ peržiūrai reikalingas „GStreamer GTK“ vaizdo sinchronizatorius (video sink). Įdiekite „GStreamer“ skirtą „gtksink“ papildinį, tada iš naujo paleiskite „OrcaSlicer“." - -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Nepavyko inicijuoti „native Wayland GStreamer“ vaizdo sinchronizatoriaus (video sink). Patikrinkite „GStreamer GTK“ papildinio įdiegimą." - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "Šiai užduočiai atlikti reikalingas \"Windows Media Player\"! Ar norite įjungti \"Windows Media Player\" savo operacinėje sistemoje?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "„BambuSource“ neteisingai užregistruotas medijos atkūrimui! Paspauskite „Taip“, kad jį perregistruotumėte. Jums reikės patvirtinti du kartus." - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Trūksta BambuSource komponento, užregistruoto medijos atkūrimui! Iš naujo įdiekite OrcaSlicer arba kreipkitės pagalbos į bendruomenę." - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Naudojant \"BambuSource\" iš kito diegimo šaltinio, vaizdo įrašų atkūrimas gali būti neteisingas! Paspauskite Taip, kad tai ištaisytumėte." - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "Jūsų sistemoje nėra \"GStreamer\" H.264 kodekų, reikalingų vaizdo įrašams atkurti. (Pabandykite įdiegti gstreamer1.0-plugins-bad arba gstreamer1.0-libav paketus, tada iš naujo paleiskite \"Orca Slicer\")" - msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "Debesies agentas nepasiekiamas. Iš naujo paleiskite „OrcaSlicer“ ir bandykite vėl." @@ -12225,6 +12276,10 @@ msgstr "Jei vis tiek norite spausdinti, galite įjungti šią parinktį skiltyje msgid "No extrusions under current settings." msgstr "Pagal dabartinius nustatymus nėra išspaudimų." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "Naudojama mišri gija su gradientu, tačiau 'Mišrios spalvos posluoksnis' yra išjungtas. Gradientas nebus atspausdintas." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "Sklandus pakadrinio filmavimo (timelapse) režimas nepalaikomas, kai įjungta spausdinimo seka „pagal objektą“." @@ -12261,6 +12316,10 @@ msgstr "Galbūt norėsite sumažinti modelio dydį arba pakeisti esamus spausdin msgid "Variable layer height is not supported with Organic supports." msgstr "Kintamas sluoksnio aukštis nepalaikomas su \" Organinėmis atramomis\"." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "Valymo bokšto gija negali būti mišri gija." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Skirtingo skersmens purkštukai ir skirtingo skersmens gijos gali neveikti gerai, kai įjungtas valymo bokštas. Tai labai eksperimentinė priemonė, todėl elkitės atsargiai." @@ -13961,6 +14020,8 @@ msgstr "Sluoksnio laikas" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "Detalės aušinimo ventiliatorius bus suaktyvintas tiems sluoksniams, kurių preliminarus spausdinimo laikas yra trumpesnis už šią reikšmę. Ventiliatoriaus sūkiai bus interpoliuojami tarp minimalaus ir maksimalaus greičio, priklausomai nuo sluoksnio spausdinimo trukmės." +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -14268,6 +14329,62 @@ msgstr "Atramų gija" msgid "Support material is commonly used to print supports and support interfaces." msgstr "Atramų gija paprastai naudojama atramoms ir atramų skiriamiesiems sluoksniams spausdinti." +# AI Translated +msgid "Is mixed filament" +msgstr "Yra mišri gija" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Nurodo, ar ši gijos vieta yra mišri gija, sudaryta iš kelių fizinių gijų" + +# AI Translated +msgid "Mixed filament components" +msgstr "Mišrios gijos komponentai" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Kableliais atskirti komponentinių gijų indeksai, skaičiuojami nuo 1, pvz. \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Mišrios gijos posluoksnių santykiai" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Kableliais atskirtos santykio reikšmės, kurių suma lygi 1.0, pvz. \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Mišrios gijos gradientas" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Įjungia gradiento režimą Z kryptimi mišrios gijos posluoksniams. Įjungus posluoksnių santykiai tarp sluoksnių kinta tiesiškai." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Mišrios gijos gradiento intervalas" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Pirmojo komponento pradinis ir galutinis santykis gradiento režimu. Kableliu atskirta pora, pvz. \"0.10,0.90\" reiškia nuo 10% iki 90%." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Mišrios gijos gradiento kreivė" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Neprivaloma pasirinktinė Photoshop stiliaus kreivė, susiejanti Z eigą su pirmojo komponento santykiu. Užrašoma kaip vertikaliais brūkšniais atskirti valdymo taškai, formatu \"x,y\" (senasis) arba \"x,y,m_in,m_out\", kai reikia nustatyti liestinę (tuščia reikšmė arba \"nan\" reiškia numatytąjį PCHIP). x priklauso [0,1]; y apribojamas iki nustatyto santykių intervalo, pvz. \"0,0.15|0.5,0.50|1,0.85\". Jei palikta tuščia, naudojamas tiesinis gradient_range." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Mišrios gijos gradientas kiekvienai daliai" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Kai gradiento režimas įjungtas, gradientas taikomas kiekvienai surinkimo daliai atskirai, o ne visam surinkimui kaip vienam Z intervalui." + msgid "Filament printable" msgstr "Gija tinkama spausdinti" @@ -15518,6 +15635,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "Leidžiama didžiausia Y ašies išvesties jėga" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -15530,6 +15648,7 @@ msgid "The machine bed mass load of Y axis" msgstr "Įrenginio pagrindo masės apkrova Y ašiai" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -17098,6 +17217,14 @@ msgstr "" "\n" "Jei žemiau esančiame nustatyme „Įtraukimo kiekis prieš nuvalymą“ nurodysite reikšmę, perteklinis gijos įtraukimas bus atliktas prieš nuvalymą, kitu atveju – po jo." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Mišrios spalvos posluoksnis" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Įjungia skaidymą į mišrios spalvos posluoksnius. Įjungus sluoksniai, kuriuose yra mišrios spalvos gijų, skaidomi į posluoksnius, kad būtų pasiektas spalvų maišymo efektas." + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "Valymo bokštelis (angl. \"wiping tower\") gali būti naudojamas likučiams nuo purkštuko nuvalyti ir purkštuko viduje esančiam slėgiui stabilizuoti, siekiant išvengti išvaizdos defektų spausdinant objektus." @@ -18181,6 +18308,10 @@ msgstr "Nepavyko suformuoti modelio failo poligonažo arba jame nėra tinkamos g msgid "The supplied file couldn't be read because it's empty." msgstr "Pateikto failo nepavyko nuskaityti, nes jis yra tuščias." +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "Failo formatas nesuderinamas ir jo nepavyksta perskaityti." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Nežinomas failo formatas: įvesties failas privalo turėti .stl, .obj arba .amf(.xml) plėtinį." @@ -20447,8 +20578,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "Įjungti išmanųjį gijos priskyrimą: priskirkite vieną giją keliems purkštukams, kad sutaupytumėte kuo daugiau" # AI Translated -msgid "Fila Saving" -msgstr "Gijos taupymas" +msgid "File Saving" +msgstr "Failo įrašymas" msgid "Don't remind me again" msgstr "Daugiau neberodyti šio priminimo" @@ -20813,6 +20944,9 @@ msgstr "Paleisti iš naujo dabar" msgid "NO RAMMING AT ALL" msgstr "VISIŠKAI NENAUDOTI SUTANKINIMO" +msgid "s" +msgstr "s" + msgid "Volumetric speed" msgstr "Tūrinis greitis" @@ -21435,6 +21569,39 @@ msgstr "" "Venkite deformacijų (warping)\n" "Ar žinojote, kad spausdinant medžiagas, kurios yra linkusios trauktis ir riestis (pvz., ABS), tinkamas kaitinamojo pagrindo temperatūros padidinimas gali sumažinti deformacijų (warping) tikimybę?" +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "Tiesioginei „Native Wayland“ peržiūrai reikalingas „GStreamer GTK“ vaizdo sinchronizatorius (video sink). Įdiekite „GStreamer“ skirtą „gtksink“ papildinį, tada iš naujo paleiskite „OrcaSlicer“." + +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "Nepavyko inicijuoti „native Wayland GStreamer“ vaizdo sinchronizatoriaus (video sink). Patikrinkite „GStreamer GTK“ papildinio įdiegimą." + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "Šiai užduočiai atlikti reikalingas \"Windows Media Player\"! Ar norite įjungti \"Windows Media Player\" savo operacinėje sistemoje?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "„BambuSource“ neteisingai užregistruotas medijos atkūrimui! Paspauskite „Taip“, kad jį perregistruotumėte. Jums reikės patvirtinti du kartus." + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "Trūksta BambuSource komponento, užregistruoto medijos atkūrimui! Iš naujo įdiekite OrcaSlicer arba kreipkitės pagalbos į bendruomenę." + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "Naudojant \"BambuSource\" iš kito diegimo šaltinio, vaizdo įrašų atkūrimas gali būti neteisingas! Paspauskite Taip, kad tai ištaisytumėte." + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "Jūsų sistemoje nėra \"GStreamer\" H.264 kodekų, reikalingų vaizdo įrašams atkurti. (Pabandykite įdiegti gstreamer1.0-plugins-bad arba gstreamer1.0-libav paketus, tada iš naujo paleiskite \"Orca Slicer\")" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "Gijos taupymas" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/nl/OrcaSlicer_nl.po b/localization/i18n/nl/OrcaSlicer_nl.po index 4284378cd1..4fd3601c0e 100644 --- a/localization/i18n/nl/OrcaSlicer_nl.po +++ b/localization/i18n/nl/OrcaSlicer_nl.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -3197,6 +3197,10 @@ msgstr "Bewerken" msgid "Merge with" msgstr "Samenvoegen met" +# AI Translated +msgid "Decompose Color" +msgstr "Kleur ontleden" + # AI Translated msgid "Delete this filament" msgstr "Dit filament verwijderen" @@ -3519,6 +3523,10 @@ msgstr "Montage" msgid "Merge parts to an object" msgstr "Onderdelen samenvoegen tot een object" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "Het gebruik van variabele laaghoogte in combinatie met de sublaag met gemengde kleur kan de kwaliteit van de kleurmenging verslechteren." + # AI Translated msgid "Add layers" msgstr "Lagen toevoegen" @@ -8552,6 +8560,10 @@ msgstr "Huidig printbed aanpassen" msgid "The %s nozzle can not print %s." msgstr "Het %s-mondstuk kan %s niet printen." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "Het printen van filament met gemengde kleur op een printer met één extruder vereist frequente filamentwissels en spoelbeurten, wat het afval en het risico op verstopping van het mondstuk of de afvalgoot aanzienlijk kan vergroten." + # AI Translated #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" @@ -8695,6 +8707,26 @@ msgstr "Synchroniseer filamentlijst vanuit AMS" msgid "Set filaments to use" msgstr "Stel filamenten in om te gebruiken" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Gemengd filament toevoegen" + +# AI Translated +msgid "Mixed Filament" +msgstr "Gemengd filament" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Laatste gemengde filament verwijderen" + +# AI Translated +msgid "Add mixed filament" +msgstr "Gemengd filament toevoegen" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "Het gemengde filament bevat ongeldige of niet-overeenkomende componenten. Bewerk de betrokken items opnieuw." + msgid "Search plate, object and part." msgstr "Zoek plaat, object en onderdeel." @@ -8702,6 +8734,18 @@ msgstr "Zoek plaat, object en onderdeel." msgid "Pellets" msgstr "Pellets" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "Het gemengde filament bevat ongeldige componentverwijzingen" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Bewerken / Verwijderen / Samenvoegen" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "Het gemengde doelfilament gebruikt dit fysieke filament als component. Bij het samenvoegen wordt dit fysieke filament verwijderd en kan het gemengde filament ongeldig worden. Doorgaan?" + # AI Translated #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." @@ -8903,6 +8947,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Object met meerdere onderdelen gedetecteerd" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Texturen aan filamenten koppelen" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Waarschuwing bij importeren van textuur" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Wilt u deze bestanden laden als een enkel object bestaande uit meerdere onderdelen?\n" @@ -9134,6 +9186,22 @@ msgstr "" msgid "Sync now" msgstr "Nu synchroniseren" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "Het importeren van de textuur is mislukt. Het model lijkt textuurgegevens te bevatten, maar het importproces kon niet worden voltooid. Het model wordt alleen als geometrie geïmporteerd." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Textuurkleuren toepassen..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "3D-weergave bijwerken..." + +# AI Translated +msgid "Texture colors applied." +msgstr "Textuurkleuren toegepast." + msgid "You can keep the modified presets for the new project or discard them" msgstr "Je kunt de aangepaste voorinstellingen bewaren voor het nieuwe project of ze laten vervallen" @@ -10527,6 +10595,10 @@ msgstr "Spiraalvaas" msgid "First layer filament sequence" msgstr "Eerste laag filamentvolgorde" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "De filamentlijst bevat gemengde filamenten. De aangepaste filamentvolgorde wordt niet toegepast." + msgid "By Layer" msgstr "Op laag" @@ -12618,33 +12690,6 @@ msgstr "Volumes reinigen voor filament wijziging" msgid "Please choose the filament colour" msgstr "Kies de filamentkleur" -# AI Translated -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "Voor de native Wayland-liveview is de GStreamer GTK-videosink nodig. Installeer de gtksink-plug-in voor GStreamer en start OrcaSlicer opnieuw." - -# AI Translated -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Initialiseren van de native Wayland GStreamer-videosink is mislukt. Controleer de installatie van uw GStreamer GTK-plug-in." - -# AI Translated -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "Voor deze taak is Windows Media Player vereist! Wilt u 'Windows Media Player' inschakelen voor uw besturingssysteem?" - -# AI Translated -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource is niet correct geregistreerd voor het afspelen van media! Klik op Ja om het opnieuw te registreren. U krijgt twee keer een melding" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Ontbrekend BambuSource-component geregistreerd voor media afspelen! Installeer OrcaSlicer opnieuw of zoek hulp in de community." - -# AI Translated -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Er wordt een BambuSource van een andere installatie gebruikt; het afspelen van video werkt mogelijk niet correct! Klik op Ja om dit te herstellen." - -# AI Translated -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "Op uw systeem ontbreken H.264-codecs voor GStreamer, die nodig zijn om video af te spelen. (Probeer de pakketten gstreamer1.0-plugins-bad of gstreamer1.0-libav te installeren en Orca Slicer opnieuw te starten.)" - # AI Translated msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "De cloudagent is niet beschikbaar. Start OrcaSlicer opnieuw en probeer het nogmaals." @@ -13410,6 +13455,10 @@ msgstr "Als u toch wilt printen, kunt u de optie inschakelen via Voorkeuren / Be msgid "No extrusions under current settings." msgstr "Geen extrusion onder de huidige instellingen" +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "Er wordt een gemengd filament met verloop gebruikt, maar 'Sublaag met gemengde kleur' is uitgeschakeld. Het verloop wordt niet geprint." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "Vloeiende modus van timelapse wordt niet ondersteund wanneer \"per object\" sequentie is ingeschakeld." @@ -13452,6 +13501,10 @@ msgstr "Verklein eventueel uw model of wijzig de huidige printinstellingen en pr msgid "Variable layer height is not supported with Organic supports." msgstr "Variabele laaghoogte wordt niet ondersteund met organische steunen." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "Het filament van het afveegblok mag geen gemengd filament zijn." + # AI Translated msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Verschillende mondstukdiameters en verschillende filamentdiameters werken mogelijk niet goed wanneer de prime toren is ingeschakeld. Dit is zeer experimenteel; ga daarom voorzichtig te werk." @@ -13843,27 +13896,21 @@ msgstr "mm of %" msgid "Other layers" msgstr "Andere lagen" -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "Bedtemperatuur voor alle lagen behalve de eerste. Een waarde van 0 betekent dat het filament printen op de Cool Plate SuperTack niet ondersteunt." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "Dit is de bedtemperatuur voor alle lagen behalve de eerste. Een waarde van 0 betekent dat het filament het afdrukken op de Cool Plate niet ondersteunt." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured Cool Plate." msgstr "Dit is de bedtemperatuur voor alle lagen behalve de eerste. Een waarde van 0 betekent dat het filament printen op de Textured Cool Plate niet ondersteunt." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Engineering Plate." msgstr "Dit is de bedtemperatuur voor lagen, behalve voor de eerste. Een waarde van 0 betekent dat het filament afdrukken op de Engineering Plate niet ondersteunt." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the High Temp Plate." msgstr "Dit is de bedtemperatuur voor lagen, behalve voor de eerste. Een waarde van 0 betekent dat het filament printen op de High Temp Plate niet ondersteunt." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured PEI Plate." msgstr "Bedtemperatuur na de eerste laag. 0 betekent dat het filament niet wordt ondersteund op de getextureerde PEI-plaat." @@ -15369,6 +15416,8 @@ msgstr "Laag tijd" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "De printkop ventilator wordt ingeschakeld voor lagen waarvan de geschatte printtijd korter is dan deze waarde. Ventilatorsnelheid wordt geïnterpoleerd tussen de minimale en maximale ventilatorsnelheden volgens de printtijd van de laag" +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -15728,6 +15777,62 @@ msgstr "Support materiaal" msgid "Support material is commonly used to print supports and support interfaces." msgstr "Support materiaal wordt vaak gebruikt om support en support interfaces af te drukken." +# AI Translated +msgid "Is mixed filament" +msgstr "Is gemengd filament" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Geeft aan of dit filamentslot een gemengd filament is dat uit meerdere fysieke filamenten bestaat" + +# AI Translated +msgid "Mixed filament components" +msgstr "Componenten van gemengd filament" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Door komma's gescheiden indexen van de componentfilamenten, beginnend bij 1, bijv. \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Sublaagverhoudingen van gemengd filament" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Door komma's gescheiden verhoudingswaarden die samen 1.0 zijn, bijv. \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Verloop van gemengd filament" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Schakelt de verloopmodus in Z-richting in voor de sublagen van gemengd filament. Wanneer ingeschakeld variëren de sublaagverhoudingen lineair over de lagen." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Verloopbereik van gemengd filament" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Begin- en eindverhouding van de eerste component in de verloopmodus. Door een komma gescheiden paar, bijv. \"0.10,0.90\" betekent 10% tot 90%." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Verloopcurve van gemengd filament" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Optionele aangepaste curve in Photoshop-stijl die de Z-voortgang koppelt aan de verhouding van de eerste component. Gecodeerd als door verticale strepen gescheiden controlepunten, in de vorm \"x,y\" (verouderd) of \"x,y,m_in,m_out\" wanneer de raaklijn moet worden overschreven (een lege waarde of \"nan\" gebruikt de PCHIP-standaard). x ligt in [0,1]; y wordt begrensd tot het ingestelde verhoudingsbereik, bijv. \"0,0.15|0.5,0.50|1,0.85\". Wanneer het veld leeg is, wordt het lineaire gradient_range gebruikt." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Verloop per onderdeel van gemengd filament" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Wanneer de verloopmodus is ingeschakeld, wordt het verloop op elk onderdeel van een montage afzonderlijk toegepast in plaats van de hele montage als één Z-bereik te behandelen." + # AI Translated msgid "Filament printable" msgstr "Filament printbaar" @@ -17166,6 +17271,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "De maximaal toegestane uitgangskracht van de Y-as" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -17176,6 +17282,7 @@ msgid "The machine bed mass load of Y axis" msgstr "De massabelasting van het machinebed op de Y-as" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -18951,6 +19058,14 @@ msgstr "" "\n" "Als u hieronder een waarde instelt bij de terugtrekhoeveelheid vóór het vegen, wordt de overtollige terugtrekking vóór het vegen uitgevoerd; anders gebeurt dat erna." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Sublaag met gemengde kleur" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Schakelt het opsplitsen in sublagen met gemengde kleur in. Wanneer ingeschakeld worden lagen die filamenten met gemengde kleur bevatten opgesplitst in sublagen om kleurmengeffecten te bereiken." + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "De veegtoren kan worden gebruikt om resten op het mondstuk te verwijderen en de druk in het mondstuk te stabiliseren om uiterlijke gebreken bij het printen van objecten te voorkomen." @@ -20217,6 +20332,10 @@ msgstr "Het meshen van een modelbestand is mislukt of er is geen geldige vorm." msgid "The supplied file couldn't be read because it's empty." msgstr "Het opgegeven bestand kon niet worden gelezen omdat het leeg is." +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "De bestandsindeling is niet compatibel en kan niet worden gelezen." + # AI Translated msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Onbekende bestandsindeling: het invoerbestand moet de extensie .stl, .obj of .amf(.xml) hebben." @@ -22765,8 +22884,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "Slimme filamenttoewijzing inschakelen: wijs één filament aan meerdere mondstukken toe om de besparing te maximaliseren" # AI Translated -msgid "Fila Saving" -msgstr "Filamentbesparing" +msgid "File Saving" +msgstr "Bestand opslaan" # AI Translated msgid "Don't remind me again" @@ -23221,6 +23340,9 @@ msgstr "Nu opnieuw starten" msgid "NO RAMMING AT ALL" msgstr "HELEMAAL GEEN RAMMING" +msgid "s" +msgstr "s" + # AI Translated msgid "Volumetric speed" msgstr "Volumetrische snelheid" @@ -23887,6 +24009,45 @@ msgstr "" "Kromtrekken voorkomen\n" "Wist je dat bij het printen van materialen die gevoelig zijn voor kromtrekken, zoals ABS, een juiste verhoging van de temperatuur van het warmtebed de kans op kromtrekken kan verkleinen?" +# AI Translated +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "Voor de native Wayland-liveview is de GStreamer GTK-videosink nodig. Installeer de gtksink-plug-in voor GStreamer en start OrcaSlicer opnieuw." + +# AI Translated +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "Initialiseren van de native Wayland GStreamer-videosink is mislukt. Controleer de installatie van uw GStreamer GTK-plug-in." + +# AI Translated +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "Voor deze taak is Windows Media Player vereist! Wilt u 'Windows Media Player' inschakelen voor uw besturingssysteem?" + +# AI Translated +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource is niet correct geregistreerd voor het afspelen van media! Klik op Ja om het opnieuw te registreren. U krijgt twee keer een melding" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "Ontbrekend BambuSource-component geregistreerd voor media afspelen! Installeer OrcaSlicer opnieuw of zoek hulp in de community." + +# AI Translated +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "Er wordt een BambuSource van een andere installatie gebruikt; het afspelen van video werkt mogelijk niet correct! Klik op Ja om dit te herstellen." + +# AI Translated +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "Op uw systeem ontbreken H.264-codecs voor GStreamer, die nodig zijn om video af te spelen. (Probeer de pakketten gstreamer1.0-plugins-bad of gstreamer1.0-libav te installeren en Orca Slicer opnieuw te starten.)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "Filamentbesparing" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/pl/OrcaSlicer_pl.po b/localization/i18n/pl/OrcaSlicer_pl.po index cc88aac759..0f6fa10e3b 100644 --- a/localization/i18n/pl/OrcaSlicer_pl.po +++ b/localization/i18n/pl/OrcaSlicer_pl.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: OrcaSlicer 2.3.0-rc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: \n" "Last-Translator: Krzysztof Morga <<tlumaczeniebs@gmail.com>>\n" "Language-Team: \n" @@ -3012,6 +3012,10 @@ msgstr "Edytuj" msgid "Merge with" msgstr "Scal z" +# AI Translated +msgid "Decompose Color" +msgstr "Rozłóż kolor" + msgid "Delete this filament" msgstr "Usuń ten filament" @@ -3319,6 +3323,10 @@ msgstr "Złożenie" msgid "Merge parts to an object" msgstr "Scal części w obiekt" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "Użycie zmiennej wysokości warstwy razem z podwarstwą mieszanego koloru może pogorszyć jakość mieszania kolorów." + # AI Translated msgid "Add layers" msgstr "Dodaj warstwy" @@ -8030,6 +8038,10 @@ msgstr "Dostosuj bieżący stół" msgid "The %s nozzle can not print %s." msgstr "Dysza %s nie może drukować %s." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "Drukowanie filamentu o mieszanym kolorze na drukarce z jednym ekstruderem wymaga częstych zmian filamentu i płukania, co może znacznie zwiększyć ilość odpadów oraz ryzyko zatkania dyszy lub rynny na odpady." + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "Mieszanie %1% z %2% podczas druku nie jest zalecane.\n" @@ -8156,12 +8168,44 @@ msgstr "Synchronizuj listę filamentów z AMS" msgid "Set filaments to use" msgstr "Wybierz filamenty do użycia" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Dodaj filament mieszany" + +# AI Translated +msgid "Mixed Filament" +msgstr "Filament mieszany" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Usuń ostatni filament mieszany" + +# AI Translated +msgid "Add mixed filament" +msgstr "Dodaj filament mieszany" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "Filament mieszany ma nieprawidłowe lub niezgodne składniki. Proszę ponownie edytować odpowiednie pozycje." + msgid "Search plate, object and part." msgstr "Szukaj stołu, obiektu i części." msgid "Pellets" msgstr "Granulat" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "Filament mieszany ma uszkodzone odwołania do składników" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Edytuj / Usuń / Scal" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "Docelowy filament mieszany używa tego fizycznego filamentu jako składnika. Scalenie usunie ten fizyczny filament i może unieważnić filament mieszany. Kontynuować?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "Po zakończeniu operacji projekt %s zostanie zamknięty i zostanie utworzony nowy projekt." @@ -8351,6 +8395,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Wykryto obiekt składający się z wielu części" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Dopasowywanie tekstur do filamentów" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Ostrzeżenie importu tekstury" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Czy wczytać te pliki jako pojedynczy obiekt składający się z wielu części?\n" @@ -8579,6 +8631,22 @@ msgstr "" msgid "Sync now" msgstr "Synchronizuj teraz" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "Import tekstury nie powiódł się. Model zdaje się zawierać dane tekstury, ale nie udało się ukończyć procesu importu. Model zostanie zaimportowany wyłącznie jako geometria." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Stosowanie kolorów tekstury..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "Aktualizowanie widoku 3D..." + +# AI Translated +msgid "Texture colors applied." +msgstr "Zastosowano kolory tekstury." + msgid "You can keep the modified presets for the new project or discard them" msgstr "Można zachować zmodyfikowane profile w nowym projekcie lub je odrzucić." @@ -9922,6 +9990,10 @@ msgstr "Tryb wazy" msgid "First layer filament sequence" msgstr "Sekwencja koloru pierwszej warstwy" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "Lista filamentów zawiera filamenty mieszane. Niestandardowa kolejność filamentów nie zostanie zastosowana." + msgid "By Layer" msgstr "Wg warstwy" @@ -11896,30 +11968,6 @@ msgstr "Objętości płukania przy zmianie filamentu" msgid "Please choose the filament colour" msgstr "Proszę wybrać kolor filamentu" -# AI Translated -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "Natywny podgląd na żywo w Wayland wymaga ujścia wideo GStreamer GTK. Zainstaluj wtyczkę gtksink dla GStreamer, a następnie uruchom ponownie OrcaSlicer." - -# AI Translated -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Nie udało się zainicjować natywnego ujścia wideo GStreamer dla Wayland. Sprawdź instalację wtyczki GStreamer GTK." - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "Do wykonania tego zadania wymagany jest Windows Media Player! Czy włączyć „Windows Media Player” dla systemu operacyjnego?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource nie został poprawnie zarejestrowany do odtwarzania mediów! Naciśnij Tak, aby ponownie go zarejestrować. Będziesz poproszony dwa razy." - -# AI Translated -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Brak zarejestrowanego komponentu BambuSource do odtwarzania multimediów! Zainstaluj ponownie OrcaSlicer lub poszukaj pomocy w społeczności." - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Jeśli używasz BambuSource z innej instalacji programu, odtwarzanie wideo może nie działać poprawnie! Naciśnij Tak, aby to naprawić." - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "Twój system nie posiada kodeków H.264 dla GStreamer, które są wymagane do odtwarzania wideo. (Spróbuj zainstalować pakiety gstreamer1.0-plugins-bad lub gstreamer1.0-libav, a następnie zrestartuj Orca Slicer?)" - # AI Translated msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "Agent chmury jest niedostępny. Uruchom ponownie OrcaSlicer i spróbuj jeszcze raz." @@ -12646,6 +12694,10 @@ msgstr "Jeśli mimo to chcesz drukować, możesz włączyć opcję w Preferencje msgid "No extrusions under current settings." msgstr "Brak ekstruzji przy obecnych ustawieniach." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "Używany jest filament mieszany z gradientem, ale opcja 'Podwarstwa mieszanego koloru' jest wyłączona. Gradient nie zostanie wydrukowany." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "Tryb „Wygładzony” timelapse nie jest obsługiwany, gdy włączona jest sekwencja druku „według obiektu”." @@ -12684,6 +12736,10 @@ msgstr "Może być konieczne zmniejszenie rozmiaru modelu lub zmiana bieżących msgid "Variable layer height is not supported with Organic supports." msgstr "Zmienna wysokość warstwy nie jest dostępna w przypadku podpór organicznych." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "Filament wieży czyszczącej nie może być filamentem mieszanym." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Różne średnice dysz i filamentu mogą nie działać poprawnie, gdy włączona jest wieża czyszcząca. Jest to mocno eksperymentalna funkcja, więc zaleca się ostrożność." @@ -13060,27 +13116,21 @@ msgstr "mm lub %" msgid "Other layers" msgstr "Pozostałe warstwy" -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "Temperatura stołu dla warstw poza pierwszą. Wartość 0 oznacza, że filament nie obsługuje druku na Cool Plate SuperTack." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "Temperatura stołu dla warstw poza pierwszą. Wartość 0 oznacza, że filament nie obsługuje drukowania na Cool Plate." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured Cool Plate." msgstr "Temperatura stołu dla warstw, z wyjątkiem pierwszej. Wartość 0 oznacza, że filament nie nadaje się do druku na Textured Cool Plate." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Engineering Plate." msgstr "Temperatura stołu dla warstw poza pierwszą. Wartość 0 oznacza, że filament nie obsługuje drukowania na Engineering Plate." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the High Temp Plate." msgstr "Temperatura stołu dla warstw poza pierwszą. Wartość 0 oznacza, że filament nie obsługuje drukowania na High Temp Plate." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured PEI Plate." msgstr "Temperatura stołu dla warstw poza pierwszą. Wartość 0 oznacza, że filament nie obsługuje drukowania na Textured PEI Plate." @@ -14482,6 +14532,8 @@ msgstr "Czas warstwy" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "Wentylator chłodzący części zostanie włączony dla warstw, których szacowany czas jest krótszy niż ta wartość. Prędkość wentylatora jest interpolowana między minimalną a maksymalną prędkością wentylatora zgodnie z czasem druku warstwy" +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -14792,6 +14844,62 @@ msgstr "Materiał podporowy" msgid "Support material is commonly used to print supports and support interfaces." msgstr "Materiał podporowy jest powszechnie używany do drukowania podpór i warstw łączących podpory z modelem" +# AI Translated +msgid "Is mixed filament" +msgstr "Jest filamentem mieszanym" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Określa, czy to gniazdo filamentu jest filamentem mieszanym złożonym z kilku fizycznych filamentów" + +# AI Translated +msgid "Mixed filament components" +msgstr "Składniki filamentu mieszanego" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Rozdzielone przecinkami indeksy filamentów składowych liczone od 1, np. \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Proporcje podwarstw filamentu mieszanego" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Rozdzielone przecinkami wartości proporcji sumujące się do 1.0, np. \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Gradient filamentu mieszanego" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Włącza tryb gradientu w kierunku Z dla podwarstw filamentu mieszanego. Po włączeniu proporcje podwarstw zmieniają się liniowo między warstwami." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Zakres gradientu filamentu mieszanego" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Początkowa i końcowa proporcja pierwszego składnika w trybie gradientu. Para rozdzielona przecinkiem, np. \"0.10,0.90\" oznacza od 10% do 90%." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Krzywa gradientu filamentu mieszanego" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Opcjonalna własna krzywa w stylu Photoshopa odwzorowująca postęp w osi Z na proporcję pierwszego składnika. Zapisywana jako punkty kontrolne rozdzielone pionowymi kreskami, w postaci \"x,y\" (starszy format) lub \"x,y,m_in,m_out\", gdy potrzebne jest nadpisanie stycznej (pusta wartość lub \"nan\" oznacza domyślną wartość PCHIP). x należy do [0,1]; y jest ograniczane do skonfigurowanego zakresu proporcji, np. \"0,0.15|0.5,0.50|1,0.85\". Gdy pole jest puste, używany jest liniowy gradient_range." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Gradient filamentu mieszanego dla każdej części" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Gdy tryb gradientu jest włączony, gradient jest stosowany do każdej części złożenia niezależnie, zamiast traktować całe złożenie jako jeden zakres Z." + msgid "Filament printable" msgstr "Filament do druku" @@ -16112,6 +16220,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "Dopuszczalna maksymalna siła wyjściowa na osi Y" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -16122,6 +16231,7 @@ msgid "The machine bed mass load of Y axis" msgstr "Obciążenie masowe stołu maszyny na osi Y" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -17762,6 +17872,14 @@ msgstr "" "\n" "Ustawienie wartości w ilości cofania przed ustawieniem czyszczenia poniżej spowoduje wykonanie nadmiernego cofania przed czyszczeniem, w przeciwnym razie zostanie wykonane po nim." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Podwarstwa mieszanego koloru" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Włącza podział na podwarstwy mieszanego koloru. Po włączeniu warstwy zawierające filamenty o mieszanym kolorze są dzielone na podwarstwy w celu uzyskania efektu mieszania kolorów." + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "Wieża czyszcząca może być używana do czyszczenia resztek na dyszy i stabilizacji ciśnienia w komorze wewnątrz dyszy, aby uniknąć defektów wyglądu podczas drukowania obiektów." @@ -18863,6 +18981,10 @@ msgstr "Siatkowanie pliku modelu nie powiodło się lub nie ma prawidłowego ksz msgid "The supplied file couldn't be read because it's empty." msgstr "Dostarczony plik nie mógł być odczytany, ponieważ jest pusty" +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "Format pliku jest niezgodny i nie można go odczytać." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Nieznany format pliku. Plik wejściowy musi mieć rozszerzenie .stl, .obj, .amf(.xml)." @@ -21264,8 +21386,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "Włącz inteligentne przypisywanie filamentu: przypisz jeden filament do wielu dysz, aby zmaksymalizować oszczędności" # AI Translated -msgid "Fila Saving" -msgstr "Oszczędność fil." +msgid "File Saving" +msgstr "Zapisywanie pliku" msgid "Don't remind me again" msgstr "Nie przypominaj mi ponownie" @@ -21696,6 +21818,9 @@ msgstr "Uruchom ponownie teraz" msgid "NO RAMMING AT ALL" msgstr "BRAK WYCISKANIA" +msgid "s" +msgstr "s" + msgid "Volumetric speed" msgstr "Prędkości Przepływu" @@ -22341,6 +22466,42 @@ msgstr "" "Unikaj odkształceń\n" "Czy wiesz, że podczas drukowania filamentami podatnymi na odkształcenia, takimi jak ABS, odpowiednie zwiększenie temperatury podgrzewanej płyty może zmniejszyć prawdopodobieństwo odkształceń?" +# AI Translated +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "Natywny podgląd na żywo w Wayland wymaga ujścia wideo GStreamer GTK. Zainstaluj wtyczkę gtksink dla GStreamer, a następnie uruchom ponownie OrcaSlicer." + +# AI Translated +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "Nie udało się zainicjować natywnego ujścia wideo GStreamer dla Wayland. Sprawdź instalację wtyczki GStreamer GTK." + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "Do wykonania tego zadania wymagany jest Windows Media Player! Czy włączyć „Windows Media Player” dla systemu operacyjnego?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource nie został poprawnie zarejestrowany do odtwarzania mediów! Naciśnij Tak, aby ponownie go zarejestrować. Będziesz poproszony dwa razy." + +# AI Translated +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "Brak zarejestrowanego komponentu BambuSource do odtwarzania multimediów! Zainstaluj ponownie OrcaSlicer lub poszukaj pomocy w społeczności." + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "Jeśli używasz BambuSource z innej instalacji programu, odtwarzanie wideo może nie działać poprawnie! Naciśnij Tak, aby to naprawić." + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "Twój system nie posiada kodeków H.264 dla GStreamer, które są wymagane do odtwarzania wideo. (Spróbuj zainstalować pakiety gstreamer1.0-plugins-bad lub gstreamer1.0-libav, a następnie zrestartuj Orca Slicer?)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "Oszczędność fil." + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po index 5b9b7dcc42..0d9698d746 100644 --- a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po +++ b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: 2026-07-26 11:14-0300\n" "Last-Translator: Alexandre Folle de Menezes\n" "Language-Team: Portuguese, Brazilian\n" @@ -2836,6 +2836,10 @@ msgstr "Editar" msgid "Merge with" msgstr "Mesclar com" +# AI Translated +msgid "Decompose Color" +msgstr "Decompor Cor" + msgid "Delete this filament" msgstr "Apagar este filamento" @@ -3118,6 +3122,10 @@ msgstr "Montagem" msgid "Merge parts to an object" msgstr "Mesclar peças com um objeto" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "Usar altura de camada variável junto com a subcamada de cor mista pode resultar em uma mistura de cores de baixa qualidade." + msgid "Add layers" msgstr "Adicionar camadas" @@ -7631,6 +7639,10 @@ msgstr "Personalizar a placa atual" msgid "The %s nozzle can not print %s." msgstr "O bico %s não pode imprimir %s." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "Imprimir filamento de cor mista em uma impressora de extrusora única exige trocas de filamento e purgas frequentes, o que pode aumentar significativamente o desperdício e o risco de entupimento do bico ou da calha de resíduos." + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "Misturar %1% com %2% na impressão não é recomendado.\n" @@ -7755,12 +7767,44 @@ msgstr "Sincronizar lista de filamentos do AMS" msgid "Set filaments to use" msgstr "Definir filamentos para usar" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Adicionar Filamento Misto" + +# AI Translated +msgid "Mixed Filament" +msgstr "Filamento Misto" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Remover o último filamento misto" + +# AI Translated +msgid "Add mixed filament" +msgstr "Adicionar filamento misto" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "O filamento misto tem componentes inválidos ou incompatíveis. Edite novamente as entradas afetadas." + msgid "Search plate, object and part." msgstr "Pesquisar placa, objeto e peça." msgid "Pellets" msgstr "Pellets" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "O filamento misto tem referências de componentes quebradas" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Editar / Excluir / Mesclar" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "O filamento misto de destino usa este filamento físico como componente. Mesclar removerá este filamento físico e poderá invalidar o filamento misto. Continuar?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "Após a conclusão da sua operação, o projeto %s será encerrado e um novo projeto será criado." @@ -7939,6 +7983,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Objeto multi-peça detectado" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Associando texturas aos filamentos" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Aviso de Importação de Textura" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Carregar esses arquivos como um único objeto com múltiplas peças?\n" @@ -8146,6 +8198,22 @@ msgstr "" msgid "Sync now" msgstr "Sincronizar agora" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "Falha ao importar a textura. O modelo parece conter dados de textura, mas o processo de importação não pôde ser concluído. O modelo será importado apenas como geometria." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Aplicando cores de textura..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "Atualizando a visualização 3D..." + +# AI Translated +msgid "Texture colors applied." +msgstr "Cores de textura aplicadas." + msgid "You can keep the modified presets for the new project or discard them" msgstr "Você pode manter as predefinições modificadas no novo projeto ou descartá-las" @@ -9379,6 +9447,10 @@ msgstr "Vaso espiral" msgid "First layer filament sequence" msgstr "Sequência de filamento da primeira camada" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "A lista de filamentos contém filamentos mistos. A sequência de filamentos personalizada não terá efeito." + msgid "By Layer" msgstr "Por Camada" @@ -11255,27 +11327,6 @@ msgstr "Volumes de purga para troca de filamento" msgid "Please choose the filament colour" msgstr "Escolha a cor do filamento" -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "A visualização ao vivo nativa do Wayland requer o receptor de vídeo GTK do GStreamer. Instale o plugin gtksink para GStreamer e reinicie o OrcaSlicer." - -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Falha ao inicializar o receptor de vídeo nativo do Wayland GStreamer. Verifique a instalação do plugin GStreamer GTK." - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "O Windows Media Player é necessário para esta tarefa! Você quer habilitar o 'Windows Media Player' para seu sistema operacional?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource não foi registrado corretamente para reprodução de mídia! Pressione Sim para registrá-lo novamente. Você será promovido duas vezes" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Componente BambuSource registrado para reprodução de mídia não encontrado! Por favor, reinstale o OrcaSlicer ou procure ajuda da comunidade." - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Usando um BambuSource de uma instalação diferente, a reprodução de vídeo pode não funcionar corretamente! Pressione Sim para consertar." - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "Seu sistema não possui codecs H.264 para o GStreamer, que são necessários para reproduzir vídeos. (Tente instalar os pacotes gstreamer1.0-plugins-bad ou gstreamer1.0-libav e depois reinicie o OrcaSlicer?)" - msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "O agente na nuvem não está disponível. Reinicie o OrcaSlicer e tente novamente." @@ -11973,6 +12024,10 @@ msgstr "Se ainda assim desejar imprimir, você pode ativar a opção em Preferê msgid "No extrusions under current settings." msgstr "Nenhuma extrusão com as configurações atuais." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "Um filamento misto com gradiente está em uso, mas 'Subcamada de cor mista' está desativado. O gradiente não será impresso." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "O modo suave do timelapse não é suportado quando a sequência \"por objeto\" está ativada." @@ -12009,6 +12064,10 @@ msgstr "Você pode querer reduzir o tamanho do seu modelo ou alterar as configur msgid "Variable layer height is not supported with Organic supports." msgstr "A altura de camada variável não é suportada com suportes Orgânicos." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "O filamento da torre de purga não pode ser um filamento misto." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Diferentes diâmetros de bico e diferentes diâmetros de filamento podem não funcionar bem quando a torre de purga estiver habilitada. É muito experimental, então prossiga com cautela." @@ -13702,6 +13761,8 @@ msgstr "Tempo da camada" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "A ventoinha de resfriamento de peças será ativado para camadas cujo tempo estimado seja mais curto que esse valor. A velocidade da ventoinha é interpolada entre as velocidades mínima e máxima da ventoinha de acordo com o tempo de impressão da camada." +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -14007,6 +14068,62 @@ msgstr "Material de suporte" msgid "Support material is commonly used to print supports and support interfaces." msgstr "O material de suporte é comumente usado para imprimir suportes e interfaces de suporte." +# AI Translated +msgid "Is mixed filament" +msgstr "É filamento misto" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Define se este slot de filamento é um filamento misto composto por vários filamentos físicos" + +# AI Translated +msgid "Mixed filament components" +msgstr "Componentes do filamento misto" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Índices (começando em 1) dos filamentos componentes, separados por vírgulas; ex.: \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Proporções de subcamada do filamento misto" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Valores de proporção separados por vírgulas cuja soma seja 1.0; ex.: \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Gradiente do filamento misto" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Ativa o modo de gradiente na direção Z para as subcamadas do filamento misto. Quando ativado, as proporções das subcamadas variam linearmente ao longo das camadas." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Faixa do gradiente do filamento misto" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Proporções inicial e final do primeiro componente no modo de gradiente. Par separado por vírgula; ex.: \"0.10,0.90\" significa de 10% a 90%." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Curva do gradiente do filamento misto" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Curva personalizada opcional, no estilo do Photoshop, que mapeia o progresso em Z para a proporção do primeiro componente. Codificada como pontos de controle separados por barras verticais, no formato \"x,y\" (legado) ou \"x,y,m_in,m_out\" quando é necessário substituir a tangente (um valor vazio ou \"nan\" usa o padrão PCHIP). x está em [0,1]; y é limitado à faixa de proporção configurada; ex.: \"0,0.15|0.5,0.50|1,0.85\". Quando vazio, o gradient_range linear é usado." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Gradiente por peça do filamento misto" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Quando o modo de gradiente está ativado, aplica o gradiente a cada peça de uma montagem de forma independente, em vez de tratar toda a montagem como uma única faixa Z." + msgid "Filament printable" msgstr "Filamento imprimível" @@ -15243,6 +15360,8 @@ msgstr "Força máxima do eixo Y" msgid "The allowed maximum output force of Y axis" msgstr "A força máxima de saída permitida do eixo Y" +# AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -15252,6 +15371,8 @@ msgstr "Massa da mesa do eixo Y" msgid "The machine bed mass load of Y axis" msgstr "A carga de massa da mesa do equipamento no eixo Y" +# AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -16802,6 +16923,14 @@ msgstr "" "\n" "Definir um valor na configuração de quantidade de retração antes da limpeza abaixo executará qualquer retração em excesso antes da limpeza, caso contrário, será realizada após." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Subcamada de cor mista" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Ativa a divisão em subcamadas de cor mista. Quando ativado, as camadas que contêm filamentos de cor mista são divididas em subcamadas para obter efeitos de mistura de cores." + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "A torre de purga pode ser usada para limpar o resíduo no bico e estabilizar a pressão na câmara dentro do bico, a fim de evitar defeitos de aparência ao imprimir objetos." @@ -17858,6 +17987,10 @@ msgstr "A geração da malha do arquivo do modelo falhou ou não há forma váli msgid "The supplied file couldn't be read because it's empty." msgstr "O arquivo fornecido não pôde ser lido porque está vazio." +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "O formato do arquivo é incompatível e não pode ser lido." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Formato de arquivo desconhecido: o arquivo de entrada deve ter extensão .stl, .obj, .amf(.xml)." @@ -20105,8 +20238,9 @@ msgstr "Removido" msgid "Enable smart filament assign: Assign one filament to multiple nozzles to maximize savings" msgstr "Ativar atribuição inteligente de filamento: Atribui um filamento a vários bicos para maximizar a economia" -msgid "Fila Saving" -msgstr "Econo Filamento" +# AI Translated +msgid "File Saving" +msgstr "Salvamento de Arquivo" msgid "Don't remind me again" msgstr "Não me avise novamente" @@ -20465,6 +20599,9 @@ msgstr "Reiniciar Agora" msgid "NO RAMMING AT ALL" msgstr "SEM NENHUM MOLDEAMENTO" +msgid "s" +msgstr "s" + msgid "Volumetric speed" msgstr "Velocidade volumétrica" @@ -21041,6 +21178,36 @@ msgstr "" "Evitar empenamento\n" "Você sabia que ao imprimir materiais propensos ao empenamento como ABS, aumentar adequadamente a temperatura da mesa aquecida pode reduzir a probabilidade de empenamento?" +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "A visualização ao vivo nativa do Wayland requer o receptor de vídeo GTK do GStreamer. Instale o plugin gtksink para GStreamer e reinicie o OrcaSlicer." + +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "Falha ao inicializar o receptor de vídeo nativo do Wayland GStreamer. Verifique a instalação do plugin GStreamer GTK." + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "O Windows Media Player é necessário para esta tarefa! Você quer habilitar o 'Windows Media Player' para seu sistema operacional?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource não foi registrado corretamente para reprodução de mídia! Pressione Sim para registrá-lo novamente. Você será promovido duas vezes" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "Componente BambuSource registrado para reprodução de mídia não encontrado! Por favor, reinstale o OrcaSlicer ou procure ajuda da comunidade." + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "Usando um BambuSource de uma instalação diferente, a reprodução de vídeo pode não funcionar corretamente! Pressione Sim para consertar." + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "Seu sistema não possui codecs H.264 para o GStreamer, que são necessários para reproduzir vídeos. (Tente instalar os pacotes gstreamer1.0-plugins-bad ou gstreamer1.0-libav e depois reinicie o OrcaSlicer?)" + +#~ msgid "N" +#~ msgstr "N" + +#~ msgid "g" +#~ msgstr "g" + +#~ msgid "Fila Saving" +#~ msgstr "Econo Filamento" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/ru/OrcaSlicer_ru.po b/localization/i18n/ru/OrcaSlicer_ru.po index 200d3cbb42..112fbc2834 100644 --- a/localization/i18n/ru/OrcaSlicer_ru.po +++ b/localization/i18n/ru/OrcaSlicer_ru.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: OrcaSlicer V2.5.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: 2026-02-25 13:38+0300\n" "Last-Translator: Felix14_v2\n" "Language-Team: Felix14_v2 (ДС/ТГ: @felix14_v2, почта: aleks111001@list.ru), Andylg <andylg@yandex.ru>\n" @@ -2911,6 +2911,10 @@ msgstr "Правка" msgid "Merge with" msgstr "Объединить с" +# AI Translated +msgid "Decompose Color" +msgstr "Разложить цвет" + msgid "Delete this filament" msgstr "Удалить материал" @@ -3222,6 +3226,10 @@ msgstr "Сборка" msgid "Merge parts to an object" msgstr "Сборка моделей" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "Использование переменной высоты слоя вместе с подслоем смешанного цвета может ухудшить качество смешивания цветов." + # Запись в истории действий msgid "Add layers" msgstr "Добавление слоёв" @@ -7891,6 +7899,10 @@ msgstr "Настроить стол" msgid "The %s nozzle can not print %s." msgstr "Внимание: «%s» экструдер не может печатать %s." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "Печать материала смешанного цвета на принтере с одним экструдером требует частой смены материала и прочистки, что может значительно увеличить количество отходов и риск засорения сопла или жёлоба для отходов." + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "Совмещение %1% с %2% при печати не рекомендуется.\n" @@ -8021,12 +8033,44 @@ msgstr "Синхронизировать материалы" msgid "Set filaments to use" msgstr "Выбрать материал" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Добавить смешанный материал" + +# AI Translated +msgid "Mixed Filament" +msgstr "Смешанный материал" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Удалить последний смешанный материал" + +# AI Translated +msgid "Add mixed filament" +msgstr "Добавить смешанный материал" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "У смешанного материала недопустимые или несовпадающие компоненты. Пожалуйста, отредактируйте затронутые записи заново." + msgid "Search plate, object and part." msgstr "Поиск стола, модели или части..." msgid "Pellets" msgstr "Гранулы" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "У смешанного материала нарушены ссылки на компоненты" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Изменить / Удалить / Объединить" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "Целевой смешанный материал использует этот физический материал в качестве компонента. Объединение удалит этот физический материал и может сделать смешанный материал недействительным. Продолжить?" + # Порядок слов сильно зависит от контекста; не могу воспроизвести в интерфейсе. По идее, выводится при bool Sidebar::is_new_project_in_gcode3mf(), но что-либо менять в нарезанном .gcode.3mf вообще нельзя #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." @@ -8211,6 +8255,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Обнаружена модель, состоящая из нескольких частей" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Сопоставление текстур с материалами" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Предупреждение при импорте текстуры" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Загрузить эти файлы как единую модель, состоящую из нескольких частей?\n" @@ -8425,6 +8477,22 @@ msgstr "" msgid "Sync now" msgstr "Синхронизировать" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "Не удалось импортировать текстуру. Похоже, модель содержит данные текстуры, но завершить импорт не удалось. Модель будет импортирована только как геометрия." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Применение цветов текстуры..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "Обновление 3D-вида..." + +# AI Translated +msgid "Texture colors applied." +msgstr "Цвета текстуры применены." + msgid "You can keep the modified presets for the new project or discard them" msgstr "Вы можете перенести сделанные изменения в новый проект или отказаться от их сохранения" @@ -9671,6 +9739,10 @@ msgstr "Режим вазы" msgid "First layer filament sequence" msgstr "Очерёдность материалов на первом слое" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "Список материалов содержит смешанные материалы. Пользовательская последовательность материалов не будет применена." + msgid "By Layer" msgstr "Послойно" @@ -11586,27 +11658,6 @@ msgstr "Объёмы прочистки при смене материала" msgid "Please choose the filament colour" msgstr "Изменение цвета" -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "Для нативного отображения трансляции в Wayland требуется gtksink (плагин для GStreamer). Установите необходимый пакет плагинов и перезапустите OrcaSlicer." - -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Не удалось запустить нативную трансляцию GSteramer через Wayland. Проверьте наличие установленного пакета плагинов GStreamer." - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "Для этой задачи требуется Windows Media Player! Хотите включить его в своей ОС?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "Компонент BambuSource неправильно зарегистрирован для воспроизведения медиафайлов! Нажмите «Да», чтобы повторно зарегистрировать его" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Отсутствует компонент BambuSource для воспроизведения медиа. Переустановите OrcaSlicer или обратитесь за помощью к сообществу." - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "При использовании компонентов BambuSource из другого инсталлятора, воспроизведение видео может работать некорректно! Нажмите «Да», чтобы исправить это." - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "В вашей системе отсутствуют кодеки H.264 для GStreamer, которые необходимы для воспроизведения видео (попробуйте установить пакеты gstreamer1.0-plugins-bad или gstreamer1.0-libav, а затем перезапустить Orca Slicer)." - msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "Облачный агент недоступен. Перезапустите OrcaSlicer и повторите попытку." @@ -12303,6 +12354,10 @@ msgstr "Если вас это не пугает, эту проверку мож msgid "No extrusions under current settings." msgstr "При текущих настройках экструзия отсутствует." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "Используется смешанный материал с градиентом, но параметр «Подслой смешанного цвета» отключён. Градиент не будет напечатан." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "Плавный режим таймлапса не поддерживается, когда включена последовательность печати моделей по очереди." @@ -12341,6 +12396,10 @@ msgstr "Попробуйте уменьшить размер модели или msgid "Variable layer height is not supported with Organic supports." msgstr "Функция переменной высоты слоя несовместима с органическим стилем древовидных поддержек." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "Материал черновой башни не может быть смешанным материалом." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Совместное использование черновой башни с разными диаметрами сопел и прутков может привести к некорректной нарезке при включённой черновой башне. Этот метод работы экспериментальный, поэтому будьте осторожны при использовании." @@ -14159,6 +14218,8 @@ msgstr "Время слоя" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "Вентилятор охлаждения моделей будет включён для слоёв, расчётное время которых меньше этого значения. Скорость вентилятора интерполируется между минимальной и максимальной скоростями зависимости от времени печати слоя." +# AI Translated +msgctxt "second" msgid "s" msgstr "с" @@ -14488,6 +14549,62 @@ msgstr "Материал поддержки" msgid "Support material is commonly used to print supports and support interfaces." msgstr "Обычно используется для печати поддержки и связующего слоя (интерфейса)." +# AI Translated +msgid "Is mixed filament" +msgstr "Является смешанным материалом" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Определяет, является ли этот слот материала смешанным материалом, состоящим из нескольких физических материалов" + +# AI Translated +msgid "Mixed filament components" +msgstr "Компоненты смешанного материала" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Разделённые запятыми индексы материалов-компонентов, начиная с 1, например \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Доли подслоёв смешанного материала" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Разделённые запятыми значения долей, дающие в сумме 1.0, например \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Градиент смешанного материала" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Включает режим градиента по оси Z для подслоёв смешанного материала. При включении доли подслоёв линейно меняются от слоя к слою." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Диапазон градиента смешанного материала" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Начальная и конечная доли первого компонента в режиме градиента. Пара значений через запятую, например \"0.10,0.90\" означает от 10% до 90%." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Кривая градиента смешанного материала" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Необязательная пользовательская кривая в стиле Photoshop, сопоставляющая прогресс по оси Z с долей первого компонента. Задаётся как контрольные точки, разделённые вертикальной чертой, в виде \"x,y\" (устаревший формат) или \"x,y,m_in,m_out\", если требуется переопределить касательную (пустое значение или \"nan\" означает использование значения PCHIP по умолчанию). x лежит в [0,1]; y ограничивается заданным диапазоном долей, например \"0,0.15|0.5,0.50|1,0.85\". Если поле пустое, вместо этого используется линейный gradient_range." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Градиент смешанного материала по частям" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Если включён режим градиента, градиент применяется к каждой части сборки отдельно, а не ко всей сборке как к единому диапазону Z." + # ??? Настройка в режиме разработчика. Должна отображаться где-то в настройках # профиля, но поиском не ищется. msgid "Filament printable" @@ -15878,6 +15995,8 @@ msgstr "Максимальное усилие оси Y" msgid "The allowed maximum output force of Y axis" msgstr "Максимально допустимое усилие по оси Y." +# AI Translated +msgctxt "Newton" msgid "N" msgstr "Н" @@ -15887,6 +16006,8 @@ msgstr "Масса стола (оси Y)" msgid "The machine bed mass load of Y axis" msgstr "Пассивная нагрузка механики оси Y массой стола." +# AI Translated +msgctxt "gram" msgid "g" msgstr "г" @@ -17660,6 +17781,14 @@ msgstr "" "\n" "Внимание: процент первичного отката будет увеличен, если длины очистки окажется недостаточно при текущей скорости отката (или из-за иных ограничений)." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Подслой смешанного цвета" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Включает разбиение на подслои смешанного цвета. При включении слои, содержащие материалы смешанного цвета, разбиваются на подслои для получения эффекта смешивания цветов." + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "Черновая башня – специальная структура, которая используется для прочистки сопла от остатков материала и стабилизации давления внутри сопла при смене экструдера, чтобы избежать дефектов на поверхности печатаемой модели." @@ -18818,6 +18947,10 @@ msgstr "Не удалось обнаружить форму или создат msgid "The supplied file couldn't be read because it's empty." msgstr "Невозможно прочитать файл, так как он пуст." +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "Формат файла несовместим и не может быть прочитан." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Неизвестный формат файла: входной файл должен иметь расширение *.stl, *.obj или *.amf(.xml)." @@ -21120,8 +21253,9 @@ msgstr "Удалено" msgid "Enable smart filament assign: Assign one filament to multiple nozzles to maximize savings" msgstr "Включить умное назначение материалов: назначить один материал нескольким соплам для максимальной экономии" -msgid "Fila Saving" -msgstr "Экономия материала" +# AI Translated +msgid "File Saving" +msgstr "Сохранение файла" msgid "Don't remind me again" msgstr "Больше не показывать" @@ -21486,6 +21620,9 @@ msgstr "Перезапустить сейчас" msgid "NO RAMMING AT ALL" msgstr "Рэмминг отключён" +msgid "s" +msgstr "с" + # Тянется только в окно настроек рэмминга msgid "Volumetric speed" msgstr "Объёмный расход" @@ -22081,6 +22218,36 @@ msgstr "" "Предотвращение коробления материала\n" "Знаете ли вы, что при печати материалами, склонными к короблению, таких как ABS, повышение температуры подогреваемого стола может снизить эту вероятность?" +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "Для нативного отображения трансляции в Wayland требуется gtksink (плагин для GStreamer). Установите необходимый пакет плагинов и перезапустите OrcaSlicer." + +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "Не удалось запустить нативную трансляцию GSteramer через Wayland. Проверьте наличие установленного пакета плагинов GStreamer." + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "Для этой задачи требуется Windows Media Player! Хотите включить его в своей ОС?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "Компонент BambuSource неправильно зарегистрирован для воспроизведения медиафайлов! Нажмите «Да», чтобы повторно зарегистрировать его" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "Отсутствует компонент BambuSource для воспроизведения медиа. Переустановите OrcaSlicer или обратитесь за помощью к сообществу." + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "При использовании компонентов BambuSource из другого инсталлятора, воспроизведение видео может работать некорректно! Нажмите «Да», чтобы исправить это." + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "В вашей системе отсутствуют кодеки H.264 для GStreamer, которые необходимы для воспроизведения видео (попробуйте установить пакеты gstreamer1.0-plugins-bad или gstreamer1.0-libav, а затем перезапустить Orca Slicer)." + +#~ msgid "N" +#~ msgstr "Н" + +#~ msgid "g" +#~ msgstr "г" + +#~ msgid "Fila Saving" +#~ msgstr "Экономия материала" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/sv/OrcaSlicer_sv.po b/localization/i18n/sv/OrcaSlicer_sv.po index fce8c33b10..7ec20d136d 100644 --- a/localization/i18n/sv/OrcaSlicer_sv.po +++ b/localization/i18n/sv/OrcaSlicer_sv.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -3289,6 +3289,10 @@ msgstr "Redigera" msgid "Merge with" msgstr "Slå ihop med" +# AI Translated +msgid "Decompose Color" +msgstr "Dela upp färg" + # AI Translated msgid "Delete this filament" msgstr "Radera detta filament" @@ -3610,6 +3614,10 @@ msgstr "Montering" msgid "Merge parts to an object" msgstr "Slå ihop delar till ett objekt" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "Att använda variabel lagerhöjd tillsammans med underlager med blandad färg kan ge sämre färgblandningskvalitet." + # AI Translated msgid "Add layers" msgstr "Lägg till lager" @@ -8644,6 +8652,10 @@ msgstr "Anpassa aktuell platta" msgid "The %s nozzle can not print %s." msgstr "Nozzeln %s kan inte skriva ut %s." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "Att skriva ut filament med blandad färg på en skrivare med en enda extruder kräver täta filamentbyten och rensningar, vilket kan öka spillet och risken för stopp i nozzeln eller avfallsrännan avsevärt." + # AI Translated #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" @@ -8787,6 +8799,26 @@ msgstr "Synkronisera filament listan från AMS" msgid "Set filaments to use" msgstr "Ställ in filament som ska användas" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Lägg till blandat filament" + +# AI Translated +msgid "Mixed Filament" +msgstr "Blandat filament" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Ta bort det senaste blandade filamentet" + +# AI Translated +msgid "Add mixed filament" +msgstr "Lägg till blandat filament" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "Det blandade filamentet har ogiltiga eller inkompatibla komponenter. Redigera de berörda posterna igen." + msgid "Search plate, object and part." msgstr "Sök platta, objekt och del." @@ -8794,6 +8826,18 @@ msgstr "Sök platta, objekt och del." msgid "Pellets" msgstr "Pellets" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "Det blandade filamentet har trasiga komponentreferenser" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Redigera / Radera / Slå ihop" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "Det blandade målfilamentet använder detta fysiska filament som komponent. Sammanslagningen tar bort det fysiska filamentet och kan göra det blandade filamentet ogiltigt. Fortsätt?" + # AI Translated #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." @@ -8994,6 +9038,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Objekt i flera delar har upptäckts" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Matchar texturer mot filament" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Varning vid texturimport" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Ladda dessa filer som ett enkelt objekt med multipla delar?\n" @@ -9223,6 +9275,22 @@ msgstr "" msgid "Sync now" msgstr "Synkronisera nu" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "Texturimporten misslyckades. Modellen verkar innehålla texturdata, men importprocessen kunde inte slutföras. Modellen importeras endast som geometri." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Tillämpar texturfärger..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "Uppdaterar 3D-vyn..." + +# AI Translated +msgid "Texture colors applied." +msgstr "Texturfärger tillämpade." + msgid "You can keep the modified presets for the new project or discard them" msgstr "Fortsätt med redigerings inställningarna till nytt projekt eller avfärda dem" @@ -10641,6 +10709,10 @@ msgstr "Spiral vas" msgid "First layer filament sequence" msgstr "Första lagrets filament sekvens" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "Filamentlistan innehåller blandade filament. Den anpassade filamentordningen får ingen effekt." + msgid "By Layer" msgstr "Per lager" @@ -12783,33 +12855,6 @@ msgstr "Rensnings volym för filament byte" msgid "Please choose the filament colour" msgstr "Välj filamentfärg" -# AI Translated -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "Liveview i Wayland kräver GStreamers GTK-videosink. Installera insticksmodulen gtksink för GStreamer och starta sedan om OrcaSlicer." - -# AI Translated -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Det gick inte att initiera Waylands GStreamer-videosink. Kontrollera installationen av din GStreamer GTK-insticksmodul." - -# AI Translated -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "Windows Media Player krävs för den här uppgiften! Vill du aktivera 'Windows Media Player' i ditt operativsystem?" - -# AI Translated -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource har inte registrerats korrekt för mediauppspelning! Tryck på Ja för att registrera om den. Du får två frågor" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Saknad BambuSource-komponent registrerad för mediauppspelning! Installera om OrcaSlicer eller sök hjälp i gemenskapen." - -# AI Translated -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Du använder en BambuSource från en annan installation, videouppspelningen kanske inte fungerar korrekt! Tryck på Ja för att åtgärda det." - -# AI Translated -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "Ditt system saknar H.264-kodekar för GStreamer, som krävs för att spela upp video. (Prova att installera paketen gstreamer1.0-plugins-bad eller gstreamer1.0-libav och starta sedan om Orca Slicer.)" - # AI Translated msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "Molnagenten är inte tillgänglig. Starta om OrcaSlicer och försök igen." @@ -13572,6 +13617,10 @@ msgstr "Om du ändå vill skriva ut kan du aktivera alternativet i Inställninga msgid "No extrusions under current settings." msgstr "Nuvarande inställning har ingen extrudering." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "Ett blandat filament med gradient används, men 'Underlager med blandad färg' är inaktiverat. Gradienten kommer inte att skrivas ut." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "Smooth läge för timelapse stöds inte när ”per objekt” -sekvens är aktiverad." @@ -13614,6 +13663,10 @@ msgstr "Du kan behöva minska modellens storlek eller ändra de aktuella utskrif msgid "Variable layer height is not supported with Organic supports." msgstr "Variabel lagerhöjd stöds inte med organiska support." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "Filamentet för prime tornet kan inte vara ett blandat filament." + # AI Translated msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Olika nozzeldiametrar och olika filamentdiametrar kanske inte fungerar bra när prime tornet är aktiverat. Det är mycket experimentellt, så var försiktig." @@ -14012,27 +14065,21 @@ msgstr "mm eller %" msgid "Other layers" msgstr "Andra lager" -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "Byggplattans temperatur för alla lager utom det första. Värdet 0 innebär att filamentet inte stöder utskrift på Cool Plate SuperTack." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate." msgstr "Detta är byggplattans temperatur för lager förutom det första. Värdet 0 betyder att filamentet inte stöder utskrift på Cool Plate." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured Cool Plate." msgstr "Detta är byggplattans temperatur för lager förutom det första. Värdet 0 betyder att filamentet inte stöder utskrift på Textured Cool Plate." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Engineering Plate." msgstr "Detta är byggplattans temperatur för lager förutom det första. Ett värde på 0 betyder att filamentet inte stöder utskrift på Engineering Plate." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the High Temp Plate." msgstr "Detta är byggplattans temperatur för lager förutom det första. Värdet 0 betyder att filamentet inte stöder utskrift på High Temp Plate." -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Textured PEI Plate." msgstr "Byggplattans temperatur efter det första lagret. 0 betyder att filamentet inte stöds på den texturerade PEI-plattan." @@ -15538,6 +15585,8 @@ msgstr "Lager tid" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "Del kylfläkten kommer att aktiveras för lager vars beräknade tid är kortare än detta värde. Fläkthastigheten interpoleras mellan den lägsta och högsta fläkthastigheten enligt utskriftstiden för lager" +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -15916,6 +15965,62 @@ msgstr "Supportmaterial" msgid "Support material is commonly used to print supports and support interfaces." msgstr "Support material används ofta för att skriva ut support och stödja gränssnittet" +# AI Translated +msgid "Is mixed filament" +msgstr "Är blandat filament" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Anger om denna filamentplats är ett blandat filament som består av flera fysiska filament" + +# AI Translated +msgid "Mixed filament components" +msgstr "Komponenter i blandat filament" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Kommaseparerade index för komponentfilamenten, med start på 1, t.ex. \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Underlagerandelar för blandat filament" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Kommaseparerade andelsvärden vars summa är 1.0, t.ex. \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Gradient för blandat filament" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Aktiverar gradientläge i Z-riktningen för det blandade filamentets underlager. När det är aktiverat varierar underlagrens andelar linjärt över lagren." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Gradientintervall för blandat filament" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Start- och slutandel för den första komponenten i gradientläge. Kommaseparerat par, t.ex. \"0.10,0.90\" betyder 10% till 90%." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Gradientkurva för blandat filament" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Valfri anpassad kurva i Photoshop-stil som mappar Z-förloppet till den första komponentens andel. Kodas som kontrollpunkter separerade med lodstreck, antingen \"x,y\" (äldre format) eller \"x,y,m_in,m_out\" när tangenten behöver åsidosättas (ett tomt värde eller \"nan\" använder PCHIP-standarden). x ligger i [0,1]; y begränsas till det konfigurerade andelsintervallet, t.ex. \"0,0.15|0.5,0.50|1,0.85\". Om fältet är tomt används det linjära gradient_range i stället." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Gradient per del för blandat filament" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "När gradientläget är aktiverat tillämpas gradienten på varje del i en montering separat i stället för att behandla hela monteringen som ett enda Z-intervall." + # AI Translated msgid "Filament printable" msgstr "Filament utskrivbart" @@ -17363,6 +17468,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "Den maximalt tillåtna utgående kraften för Y-axeln" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -17373,6 +17479,7 @@ msgid "The machine bed mass load of Y axis" msgstr "Maskinbäddens massbelastning på Y-axeln" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -19172,6 +19279,14 @@ msgstr "" "\n" "Om du anger ett värde i inställningen reduktionsmängd före avtorkning nedan utförs eventuell överskjutande reduktion före avtorkningen, annars utförs den efteråt." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Underlager med blandad färg" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Aktiverar uppdelning i underlager med blandad färg. När det är aktiverat delas lager som innehåller filament med blandad färg upp i underlager för att skapa färgblandningseffekter." + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "Avstryknings tornet kan användas för att avlägsna rester på munstycket och stabilisera kammartrycket inuti munstycket för att undvika utseendefel vid utskrift av objekt." @@ -20445,6 +20560,10 @@ msgstr "Det gick inte att skapa mesh från modellfilen, eller så saknas en gilt msgid "The supplied file couldn't be read because it's empty." msgstr "Den medföljande filen kunde inte läsas eftersom den är tom." +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "Filformatet är inkompatibelt och kan inte tolkas." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Okänt filformat: indata filen måste ha tillägget .stl, .obj eller .amf(.xml)." @@ -23021,8 +23140,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "Aktivera smart filamenttilldelning: Tilldela ett filament till flera nozzlar för att maximera besparingen" # AI Translated -msgid "Fila Saving" -msgstr "Filamentbesparing" +msgid "File Saving" +msgstr "Filsparande" # AI Translated msgid "Don't remind me again" @@ -23495,6 +23614,9 @@ msgstr "Starta om nu" msgid "NO RAMMING AT ALL" msgstr "INGEN RAMMING ALLS" +msgid "s" +msgstr "s" + # AI Translated msgid "Volumetric speed" msgstr "Volymetrisk hastighet" @@ -24175,6 +24297,45 @@ msgstr "" "Undvik vridning\n" "Visste du att när du skriver ut material som är benägna att vrida, såsom ABS, kan en lämplig ökning av värmebäddens temperatur minska sannolikheten för vridning?" +# AI Translated +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "Liveview i Wayland kräver GStreamers GTK-videosink. Installera insticksmodulen gtksink för GStreamer och starta sedan om OrcaSlicer." + +# AI Translated +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "Det gick inte att initiera Waylands GStreamer-videosink. Kontrollera installationen av din GStreamer GTK-insticksmodul." + +# AI Translated +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "Windows Media Player krävs för den här uppgiften! Vill du aktivera 'Windows Media Player' i ditt operativsystem?" + +# AI Translated +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource har inte registrerats korrekt för mediauppspelning! Tryck på Ja för att registrera om den. Du får två frågor" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "Saknad BambuSource-komponent registrerad för mediauppspelning! Installera om OrcaSlicer eller sök hjälp i gemenskapen." + +# AI Translated +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "Du använder en BambuSource från en annan installation, videouppspelningen kanske inte fungerar korrekt! Tryck på Ja för att åtgärda det." + +# AI Translated +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "Ditt system saknar H.264-kodekar för GStreamer, som krävs för att spela upp video. (Prova att installera paketen gstreamer1.0-plugins-bad eller gstreamer1.0-libav och starta sedan om Orca Slicer.)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "Filamentbesparing" + # AI Translated #~ msgid "" #~ "Layer height is too small.\n" diff --git a/localization/i18n/th/OrcaSlicer_th.po b/localization/i18n/th/OrcaSlicer_th.po index ca12a4ced2..16dcb17ab1 100644 --- a/localization/i18n/th/OrcaSlicer_th.po +++ b/localization/i18n/th/OrcaSlicer_th.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: 2026-06-19 13:40+0700\n" "Last-Translator: Icezaza\n" "Language-Team: Thai\n" @@ -2942,6 +2942,10 @@ msgstr "แก้ไข" msgid "Merge with" msgstr "รวมกับ" +# AI Translated +msgid "Decompose Color" +msgstr "แยกสี" + msgid "Delete this filament" msgstr "ลบเส้นพลาสติกนี้" @@ -3237,6 +3241,10 @@ msgstr "การประกอบ" msgid "Merge parts to an object" msgstr "รวมชิ้นส่วนเป็นวัตถุเดียว" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "การใช้ความสูงเลเยอร์แบบแปรผันร่วมกับซับเลเยอร์สีผสมอาจทำให้คุณภาพการผสมสีไม่ดี" + # AI Translated msgid "Add layers" msgstr "เพิ่มเลเยอร์" @@ -7807,6 +7815,10 @@ msgstr "ปรับแต่งแผ่นปัจจุบัน" msgid "The %s nozzle can not print %s." msgstr "หัวฉีด %s ไม่สามารถพิมพ์ %s ได้" +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "การพิมพ์เส้นพลาสติกสีผสมบนเครื่องพิมพ์ที่มีชุดดันเส้นเดียวต้องเปลี่ยนเส้นพลาสติกและไล่เส้นบ่อยครั้ง ซึ่งอาจเพิ่มเศษวัสดุและความเสี่ยงที่หัวฉีดหรือช่องทิ้งเศษวัสดุจะอุดตันอย่างมาก" + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "ไม่แนะนำให้ผสม %1% กับ %2% ในการพิมพ์\n" @@ -7932,12 +7944,44 @@ msgstr "ประสานรายการเส้นพลาสติกจ msgid "Set filaments to use" msgstr "ตั้งค่าเส้นพลาสติกที่จะใช้" +# AI Translated +msgid "Add Mixed Filament" +msgstr "เพิ่มเส้นพลาสติกผสม" + +# AI Translated +msgid "Mixed Filament" +msgstr "เส้นพลาสติกผสม" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "ลบเส้นพลาสติกผสมล่าสุด" + +# AI Translated +msgid "Add mixed filament" +msgstr "เพิ่มเส้นพลาสติกผสม" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "เส้นพลาสติกผสมมีส่วนประกอบที่ไม่ถูกต้องหรือไม่ตรงกัน กรุณาแก้ไขรายการที่ได้รับผลกระทบอีกครั้ง" + msgid "Search plate, object and part." msgstr "ค้นหาจาน วัตถุ และชิ้นส่วน" msgid "Pellets" msgstr "เม็ด" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "เส้นพลาสติกผสมมีการอ้างอิงส่วนประกอบที่เสียหาย" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "แก้ไข / ลบ / รวม" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "เส้นพลาสติกผสมปลายทางใช้เส้นพลาสติกจริงนี้เป็นส่วนประกอบ การรวมจะลบเส้นพลาสติกจริงนี้และอาจทำให้เส้นพลาสติกผสมใช้ไม่ได้ ดำเนินการต่อหรือไม่?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "หลังจากเสร็จสิ้นการดำเนินการของคุณ โครงการ %s จะถูกปิดและสร้างโครงการใหม่" @@ -8116,6 +8160,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "ตรวจพบวัตถุที่มีหลายส่วน" +# AI Translated +msgid "Matching textures to filaments" +msgstr "กำลังจับคู่พื้นผิวกับเส้นพลาสติก" + +# AI Translated +msgid "Texture Import Warning" +msgstr "คำเตือนการนำเข้าพื้นผิว" + msgid "Load these files as a single object with multiple parts?\n" msgstr "โหลดไฟล์เหล่านี้เป็นออบเจ็กต์เดียวที่มีหลายส่วนใช่ไหม\n" @@ -8326,6 +8378,22 @@ msgstr "" msgid "Sync now" msgstr "ซิงค์เลย" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "การนำเข้าพื้นผิวล้มเหลว โมเดลดูเหมือนจะมีข้อมูลพื้นผิว แต่ไม่สามารถดำเนินการนำเข้าพื้นผิวจนเสร็จสิ้นได้ โมเดลจะถูกนำเข้าเป็นเรขาคณิตเท่านั้น" + +# AI Translated +msgid "Applying texture colors..." +msgstr "กำลังใช้สีพื้นผิว..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "กำลังอัปเดตมุมมอง 3D..." + +# AI Translated +msgid "Texture colors applied." +msgstr "ใช้สีพื้นผิวแล้ว" + msgid "You can keep the modified presets for the new project or discard them" msgstr "คุณสามารถเก็บค่าที่ตั้งไว้ล่วงหน้าที่แก้ไขแล้วไว้ในโปรเจ็กต์ใหม่หรือทิ้งก็ได้" @@ -9568,6 +9636,10 @@ msgstr "แจกันเกลียว" msgid "First layer filament sequence" msgstr "ลำดับเส้นพลาสติกชั้นแรก" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "รายการเส้นพลาสติกมีเส้นพลาสติกผสมอยู่ ลำดับเส้นพลาสติกที่กำหนดเองจะไม่มีผล" + msgid "By Layer" msgstr "โดยเลเยอร์" @@ -11469,27 +11541,6 @@ msgstr "ปริมาณการไล่เส้นชิ่งสำหร msgid "Please choose the filament colour" msgstr "กรุณาเลือกสีเส้นพลาสติก" -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "Native Wayland liveview ต้องใช้ GStreamer GTK video sink โปรดติดตั้งปลั๊กอิน gtksink สำหรับ GStreamer จากนั้นรีสตาร์ท OrcaSlicer" - -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "ไม่สามารถเริ่มต้น sink วิดีโอ Wayland GStreamer ดั้งเดิมได้ โปรดตรวจสอบการติดตั้งปลั๊กอิน GStreamer GTK ของคุณ" - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "งานนี้ต้องใช้ Windows Media Player! คุณต้องการเปิดใช้งาน 'Windows Media Player' สำหรับระบบปฏิบัติการของคุณหรือไม่?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource ยังไม่ได้รับการลงทะเบียนอย่างถูกต้องสำหรับการเล่นสื่อ! กดใช่เพื่อลงทะเบียนใหม่ คุณจะได้รับการเลื่อนตำแหน่งสองครั้ง" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "ไม่มีส่วนประกอบ BambuSource ที่ลงทะเบียนสำหรับการเล่นสื่อ! โปรดติดตั้ง OrcaSlicer ใหม่หรือขอความช่วยเหลือจากชุมชน" - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "การใช้ BambuSource จากการติดตั้งอื่น การเล่นวิดีโออาจทำงานไม่ถูกต้อง! กดใช่เพื่อแก้ไข" - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "ระบบของคุณไม่มีตัวแปลงสัญญาณ H.264 สำหรับ GStreamer ซึ่งจำเป็นในการเล่นวิดีโอ (ลองติดตั้งแพ็คเกจ gstreamer1.0-plugins-bad หรือ gstreamer1.0-libav จากนั้นรีสตาร์ท Orca Slicer หรือไม่)" - msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "ตัวแทนระบบคลาวด์ไม่พร้อมใช้งาน โปรดรีสตาร์ท OrcaSlicer แล้วลองอีกครั้ง" @@ -12193,6 +12244,10 @@ msgstr "หากคุณยังต้องการพิมพ์ คุ msgid "No extrusions under current settings." msgstr "ไม่มีการอัดขึ้นรูปภายใต้การตั้งค่าปัจจุบัน" +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "มีการใช้เส้นพลาสติกผสมแบบเกรเดียนต์ แต่ 'ซับเลเยอร์สีผสม' ถูกปิดใช้งาน เกรเดียนต์จะไม่ถูกพิมพ์" + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "ไม่รองรับโหมดไทม์แลปส์แบบราบรื่นเมื่อเปิดใช้งานลำดับ \"ตามวัตถุ\"" @@ -12229,6 +12284,10 @@ msgstr "คุณอาจต้องการลดขนาดแบบจำ msgid "Variable layer height is not supported with Organic supports." msgstr "ไม่รองรับความสูงของเลเยอร์ที่แปรผันได้ด้วยการรองรับแบบออร์แกนิก" +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "เส้นพลาสติกของ Wipe Tower ไม่สามารถเป็นเส้นพลาสติกผสมได้" + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "เส้นผ่านศูนย์กลางของหัวฉีดที่แตกต่างกันและเส้นผ่านศูนย์กลางของเส้นพลาสติกที่แตกต่างกันอาจทำงานได้ไม่ดีนักเมื่อเปิดใช้งาน Prime Tower ยังเป็นการทดลองอยู่มาก ดังนั้นโปรดดำเนินการด้วยความระมัดระวัง" @@ -13941,6 +14000,8 @@ msgstr "เวลาเลเยอร์" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "พัดลมระบายความร้อนบางส่วนจะถูกเปิดใช้งานสำหรับเลเยอร์ที่เวลาโดยประมาณสั้นกว่าค่านี้ ความเร็วพัดลมจะถูกประมาณค่าระหว่างความเร็วพัดลมขั้นต่ำและสูงสุดตามเวลาการพิมพ์เลเยอร์" +# AI Translated +msgctxt "second" msgid "s" msgstr "วินาที" @@ -14248,6 +14309,62 @@ msgstr "วัสดุส่วนรองรับ" msgid "Support material is commonly used to print supports and support interfaces." msgstr "วัสดุรองรับมักใช้ในการพิมพ์ส่วนรองรับและอินเทอร์เฟซรองรับ" +# AI Translated +msgid "Is mixed filament" +msgstr "เป็นเส้นพลาสติกผสมหรือไม่" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "กำหนดว่าช่องเส้นพลาสติกนี้เป็นเส้นพลาสติกผสมที่ประกอบด้วยเส้นพลาสติกจริงหลายเส้นหรือไม่" + +# AI Translated +msgid "Mixed filament components" +msgstr "ส่วนประกอบของเส้นพลาสติกผสม" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "ลำดับของเส้นพลาสติกส่วนประกอบโดยเริ่มจาก 1 คั่นด้วยเครื่องหมายจุลภาค เช่น \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "สัดส่วนซับเลเยอร์ของเส้นพลาสติกผสม" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "ค่าสัดส่วนที่คั่นด้วยเครื่องหมายจุลภาคและรวมกันได้ 1.0 เช่น \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "เกรเดียนต์ของเส้นพลาสติกผสม" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "เปิดใช้โหมดเกรเดียนต์ในแนวแกน Z สำหรับซับเลเยอร์ของเส้นพลาสติกผสม เมื่อเปิดใช้ สัดส่วนของซับเลเยอร์จะเปลี่ยนแปลงเชิงเส้นตามเลเยอร์" + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "ช่วงเกรเดียนต์ของเส้นพลาสติกผสม" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "สัดส่วนเริ่มต้นและสิ้นสุดของส่วนประกอบแรกในโหมดเกรเดียนต์ เป็นคู่ค่าที่คั่นด้วยเครื่องหมายจุลภาค เช่น \"0.10,0.90\" หมายถึง 10% ถึง 90%" + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "เส้นโค้งเกรเดียนต์ของเส้นพลาสติกผสม" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "เส้นโค้งกำหนดเองสไตล์ Photoshop (ไม่บังคับ) ที่แมปความคืบหน้าในแกน Z กับสัดส่วนของส่วนประกอบแรก เข้ารหัสเป็นจุดควบคุมที่คั่นด้วยเครื่องหมายขีดตั้ง ในรูปแบบ \"x,y\" (รูปแบบเดิม) หรือ \"x,y,m_in,m_out\" เมื่อจำเป็นต้องกำหนดค่าแทนเจนต์เอง (ค่าว่างหรือ \"nan\" หมายถึงใช้ค่าเริ่มต้นของ PCHIP) x อยู่ในช่วง [0,1] ส่วน y จะถูกจำกัดให้อยู่ในช่วงสัดส่วนที่ตั้งค่าไว้ เช่น \"0,0.15|0.5,0.50|1,0.85\" หากเว้นว่างไว้ จะใช้ gradient_range แบบเชิงเส้นแทน" + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "เกรเดียนต์แยกตามชิ้นส่วนของเส้นพลาสติกผสม" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "เมื่อเปิดใช้โหมดเกรเดียนต์ จะใช้เกรเดียนต์กับแต่ละชิ้นส่วนของการประกอบแยกกัน แทนที่จะถือว่าการประกอบทั้งหมดเป็นช่วง Z เดียว" + msgid "Filament printable" msgstr "พิมพ์เส้นพลาสติกได้" @@ -15502,8 +15619,9 @@ msgid "The allowed maximum output force of Y axis" msgstr "แรงขับออกสูงสุดที่อนุญาตของแกน Y" # AI Translated +msgctxt "Newton" msgid "N" -msgstr "N" +msgstr "นิวตัน" # AI Translated msgid "Bed mass of the Y axis" @@ -15514,8 +15632,9 @@ msgid "The machine bed mass load of Y axis" msgstr "ภาระมวลฐานของเครื่องบนแกน Y" # AI Translated +msgctxt "gram" msgid "g" -msgstr "g" +msgstr "กรัม" # AI Translated msgid "The allowed max printed mass" @@ -17088,6 +17207,14 @@ msgstr "" "\n" "การตั้งค่าในจำนวนการถอนก่อนการล้างการตั้งค่าด้านล่างจะทำการถอนส่วนที่เกินก่อนการล้าง มิฉะนั้นจะดำเนินการหลังจากนั้น" +# AI Translated +msgid "Mixed color sublayer" +msgstr "ซับเลเยอร์สีผสม" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "เปิดใช้การแบ่งซับเลเยอร์สีผสม เมื่อเปิดใช้ เลเยอร์ที่มีเส้นพลาสติกสีผสมจะถูกแบ่งเป็นซับเลเยอร์เพื่อให้เกิดเอฟเฟกต์การผสมสี" + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "Wipe Tower สามารถใช้เพื่อทำความสะอาดสิ่งตกค้างบนหัวฉีด และทำให้แรงดันในห้องภายในหัวฉีดคงที่ เพื่อหลีกเลี่ยงข้อบกพร่องในลักษณะที่ปรากฏเมื่อพิมพ์วัตถุ" @@ -18171,6 +18298,10 @@ msgstr "การประสานไฟล์โมเดลล้มเหล msgid "The supplied file couldn't be read because it's empty." msgstr "ไม่สามารถอ่านไฟล์ที่ให้มาได้เนื่องจากไฟล์ว่างเปล่า" +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "รูปแบบไฟล์ไม่รองรับ จึงไม่สามารถอ่านข้อมูลได้" + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "รูปแบบไฟล์ที่ไม่รู้จัก ไฟล์อินพุตต้องมีนามสกุล .stl, .obj, .amf(.xml)" @@ -20473,8 +20604,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "เปิดใช้การกำหนดเส้นพลาสติกอัจฉริยะ: กำหนดเส้นพลาสติกหนึ่งชนิดให้กับหัวฉีดหลายตัวเพื่อประหยัดสูงสุด" # AI Translated -msgid "Fila Saving" -msgstr "การประหยัดเส้นพลาสติก" +msgid "File Saving" +msgstr "การบันทึกไฟล์" msgid "Don't remind me again" msgstr "ไม่ต้องเตือนฉันอีก" @@ -20839,6 +20970,9 @@ msgstr "เริ่มใหม่ตอนนี้" msgid "NO RAMMING AT ALL" msgstr "ไม่มีการกระแทกเลย" +msgid "s" +msgstr "วินาที" + msgid "Volumetric speed" msgstr "ความเร็วปริมาตร" @@ -21463,6 +21597,39 @@ msgstr "" "หลีกเลี่ยงการบิดเบี้ยว\n" "คุณรู้หรือไม่ว่าเมื่อพิมพ์วัสดุที่มีแนวโน้มที่จะเกิดการบิดเบี้ยว เช่น ABS การเพิ่มอุณหภูมิฐานพิมพ์อย่างเหมาะสมสามารถลดความน่าจะเป็นของการบิดเบี้ยวได้" +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "Native Wayland liveview ต้องใช้ GStreamer GTK video sink โปรดติดตั้งปลั๊กอิน gtksink สำหรับ GStreamer จากนั้นรีสตาร์ท OrcaSlicer" + +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "ไม่สามารถเริ่มต้น sink วิดีโอ Wayland GStreamer ดั้งเดิมได้ โปรดตรวจสอบการติดตั้งปลั๊กอิน GStreamer GTK ของคุณ" + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "งานนี้ต้องใช้ Windows Media Player! คุณต้องการเปิดใช้งาน 'Windows Media Player' สำหรับระบบปฏิบัติการของคุณหรือไม่?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource ยังไม่ได้รับการลงทะเบียนอย่างถูกต้องสำหรับการเล่นสื่อ! กดใช่เพื่อลงทะเบียนใหม่ คุณจะได้รับการเลื่อนตำแหน่งสองครั้ง" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "ไม่มีส่วนประกอบ BambuSource ที่ลงทะเบียนสำหรับการเล่นสื่อ! โปรดติดตั้ง OrcaSlicer ใหม่หรือขอความช่วยเหลือจากชุมชน" + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "การใช้ BambuSource จากการติดตั้งอื่น การเล่นวิดีโออาจทำงานไม่ถูกต้อง! กดใช่เพื่อแก้ไข" + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "ระบบของคุณไม่มีตัวแปลงสัญญาณ H.264 สำหรับ GStreamer ซึ่งจำเป็นในการเล่นวิดีโอ (ลองติดตั้งแพ็คเกจ gstreamer1.0-plugins-bad หรือ gstreamer1.0-libav จากนั้นรีสตาร์ท Orca Slicer หรือไม่)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "การประหยัดเส้นพลาสติก" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/tr/OrcaSlicer_tr.po b/localization/i18n/tr/OrcaSlicer_tr.po index b7a2c5b682..0e51b7ca9c 100644 --- a/localization/i18n/tr/OrcaSlicer_tr.po +++ b/localization/i18n/tr/OrcaSlicer_tr.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: 2026-08-21 23:18+0300\n" "Last-Translator: GlauTech\n" "Language-Team: \n" @@ -2969,6 +2969,10 @@ msgstr "Düzenle" msgid "Merge with" msgstr "Şununla birleştir" +# AI Translated +msgid "Decompose Color" +msgstr "Rengi ayrıştır" + msgid "Delete this filament" msgstr "Bu filamenti sil" @@ -3269,6 +3273,10 @@ msgstr "Birleştir" msgid "Merge parts to an object" msgstr "Parçaları bir nesnede birleştir" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "Değişken katman yüksekliğinin karışık renk alt katmanı ile birlikte kullanılması renk karışımının kalitesini düşürebilir." + # AI Translated msgid "Add layers" msgstr "Katman ekle" @@ -7897,6 +7905,10 @@ msgstr "Mevcut plakayı özelleştir" msgid "The %s nozzle can not print %s." msgstr "%s püskürtme ucu %s'yi yazdıramıyor." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "Karışık renkli filamenti tek ekstruderli bir yazıcıda basmak sık filament değişimi ve yıkama gerektirir; bu da atığı ve nozul ya da atık oluğu tıkanma riskini önemli ölçüde artırabilir." + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "Yazdırmada %1% ile %2%'nin karıştırılması önerilmez.\n" @@ -8022,12 +8034,44 @@ msgstr "Filament listesini AMS'den senkronize edin" msgid "Set filaments to use" msgstr "Kullanılacak filamentleri ayarla" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Karışık Filament Ekle" + +# AI Translated +msgid "Mixed Filament" +msgstr "Karışık Filament" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Son karışık filamenti kaldır" + +# AI Translated +msgid "Add mixed filament" +msgstr "Karışık filament ekle" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "Karışık filamentte geçersiz veya uyumsuz bileşenler var. Lütfen etkilenen girdileri yeniden düzenleyin." + msgid "Search plate, object and part." msgstr "Arama plakası, nesne ve parça." msgid "Pellets" msgstr "Peletler" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "Karışık filamentin bileşen referansları bozuk" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Düzenle / Sil / Birleştir" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "Hedef karışık filament bu fiziksel filamenti bileşen olarak kullanıyor. Birleştirme bu fiziksel filamenti kaldıracak ve karışık filamenti geçersiz kılabilir. Devam edilsin mi?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "İşleminizi tamamladıktan sonra %s projesi kapatılacak ve yeni bir proje oluşturulacak." @@ -8214,6 +8258,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Çok parçalı nesne algılandı" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Dokular filamentlerle eşleştiriliyor" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Doku İçe Aktarma Uyarısı" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Bu dosyalar birden fazla parçadan oluşan tek bir nesne olarak mı yüklensin?\n" @@ -8425,6 +8477,22 @@ msgstr "" msgid "Sync now" msgstr "Şimdi senkronize et" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "Doku içe aktarılamadı. Model doku verisi içeriyor gibi görünüyor, ancak içe aktarma işlemi tamamlanamadı. Model yalnızca geometri olarak içe aktarılacak." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Doku renkleri uygulanıyor..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "3D görünüm güncelleniyor..." + +# AI Translated +msgid "Texture colors applied." +msgstr "Doku renkleri uygulandı." + msgid "You can keep the modified presets for the new project or discard them" msgstr "Değiştirilen ön ayarları yeni projede tutabilir veya silebilirsiniz" @@ -9712,6 +9780,10 @@ msgstr "Spiral vazo" msgid "First layer filament sequence" msgstr "İlk katman filament dizisi" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "Filament listesi karışık filamentler içeriyor. Özel filament sırası etkili olmayacak." + msgid "By Layer" msgstr "Katmana göre" @@ -11653,29 +11725,6 @@ msgstr "Filament değişimi için temizleme hacmi" msgid "Please choose the filament colour" msgstr "Lütfen filament rengini seçin" -# AI Translated -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "Yerel Wayland canlı görüntüsü, GStreamer GTK video alıcısını gerektirir. Lütfen GStreamer için gtksink eklentisini yükleyin ve ardından OrcaSlicer'ı yeniden başlatın." - -# AI Translated -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Yerel Wayland GStreamer video alıcısı başlatılamadı. Lütfen GStreamer GTK eklentisi kurulumunuzu denetleyin." - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "Bu görev için Windows Media Player gereklidir! İşletim sisteminiz için ‘Windows Media Player’ı etkinleştirmek istiyor musunuz?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource medya oynatımı için doğru şekilde kaydedilmemiş! Yeniden kaydetmek için Evet’e basın" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Medya oynatma için kayıtlı BambuSource bileşeni eksik! Lütfen OrcaSlicer'ı yeniden yükleyin veya topluluk yardımı isteyin." - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Farklı bir kurulumdan bir BambuSource kullanıyorsunuz, video oynatma doğru çalışmayabilir! Düzeltmek için Evet’e basın." - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "Sisteminizde video oynatmak için gerekli olan GStreamer H.264 codec bileşenleri eksik. (gstreamer1.0-plugins-bad veya gstreamer1.0-libav paketlerini kurmayı deneyin, ardından Orca Slicer’ı yeniden başlatın)" - # AI Translated msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "Bulut aracısı kullanılamıyor. Lütfen OrcaSlicer'ı yeniden başlatıp yeniden deneyin." @@ -12401,6 +12450,10 @@ msgstr "Yine de yazdırmak istiyorsanız Tercihler / Denetim / Dilimleme / Karı msgid "No extrusions under current settings." msgstr "Mevcut ayarlarda ekstrüzyon yok." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "Gradyanlı bir karışık filament kullanılıyor ancak 'Karışık renk alt katmanı' devre dışı. Gradyan basılmayacak." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "\"Nesneye göre\" dizisi etkinleştirildiğinde, hızlandırılmış çekimin yumuşak modu desteklenmez." @@ -12437,6 +12490,10 @@ msgstr "Modelinizin boyutunu küçültmek veya mevcut yazdırma ayarlarını de msgid "Variable layer height is not supported with Organic supports." msgstr "Değişken katman yüksekliği Organik desteklerle desteklenmez." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "Silme kulesi filamenti karışık filament olamaz." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Farklı püskürtme ucu çapları ve farklı filament çapları, ana kule etkinleştirildiğinde iyi çalışmayabilir. Oldukça deneysel olduğundan lütfen dikkatli ilerleyin." @@ -14193,6 +14250,8 @@ msgstr "Katman süresi" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "Tahmini süresi bu değerden kısa olan katlarda parça soğutma fanı devreye girecektir. Fan hızı, katman yazdırma süresine göre minimum ve maksimum fan hızları arasında enterpole edilir." +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -14502,6 +14561,62 @@ msgstr "Destek malzemesi" msgid "Support material is commonly used to print supports and support interfaces." msgstr "Destek malzemesi yaygın olarak destek ve destek arayüzünü yazdırmak için kullanılır." +# AI Translated +msgid "Is mixed filament" +msgstr "Karışık filament mi" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Bu filament yuvasının birden fazla fiziksel filamentten oluşan bir karışık filament olup olmadığını belirler" + +# AI Translated +msgid "Mixed filament components" +msgstr "Karışık filament bileşenleri" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Bileşen filamentlerin virgülle ayrılmış, 1'den başlayan sıra numaraları; ör. \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Karışık filament alt katman oranları" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Toplamı 1.0 olan, virgülle ayrılmış oran değerleri; ör. \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Karışık filament gradyanı" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Karışık filamentin alt katmanları için Z yönünde gradyan modunu etkinleştirir. Etkinleştirildiğinde alt katman oranları katmanlar boyunca doğrusal olarak değişir." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Karışık filament gradyan aralığı" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Gradyan modunda ilk bileşenin başlangıç ve bitiş oranları. Virgülle ayrılmış çift; ör. \"0.10,0.90\" %10 ile %90 arasını ifade eder." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Karışık filament gradyan eğrisi" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Z ilerlemesini ilk bileşenin oranına eşleyen, isteğe bağlı Photoshop tarzı özel eğri. Dikey çizgiyle ayrılmış kontrol noktaları olarak kodlanır; \"x,y\" (eski) veya teğetin geçersiz kılınması gerektiğinde \"x,y,m_in,m_out\" biçiminde (boş değer ya da \"nan\" varsayılan PCHIP değerini kullanır). x [0,1] aralığındadır; y yapılandırılmış oran aralığına kırpılır; ör. \"0,0.15|0.5,0.50|1,0.85\". Boş bırakıldığında bunun yerine doğrusal gradient_range kullanılır." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Karışık filamentte parça başına gradyan" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Gradyan modu etkinleştirildiğinde, gradyan montajın tamamı tek bir Z aralığı olarak ele alınmak yerine montajdaki her parçaya bağımsız olarak uygulanır." + msgid "Filament printable" msgstr "Filament yazdırılabilir" @@ -15793,6 +15908,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "Y ekseninin izin verilen maksimum çıkış kuvveti" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -15805,6 +15921,7 @@ msgid "The machine bed mass load of Y axis" msgstr "Y ekseninin makine yatağı kütle yükü" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -17417,6 +17534,14 @@ msgstr "" "\n" "Aşağıdaki silme ayarından önce geri çekme miktarına bir değer ayarlamak, silme işleminden önce aşırı geri çekme işlemini gerçekleştirecektir, aksi takdirde silme işleminden sonra gerçekleştirilecektir." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Karışık renk alt katmanı" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Karışık renk alt katmanlarına bölmeyi etkinleştirir. Etkinleştirildiğinde, karışık renkli filament içeren katmanlar renk karışımı efektleri elde etmek için alt katmanlara bölünür." + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "Temizleme kulesi, nesneleri yazdırırken görünüm kusurlarını önlemek amacıyla nozul üzerindeki kalıntıları temizlemek ve nozul içindeki oda basıncını dengelemek için kullanılabilir." @@ -18505,6 +18630,10 @@ msgstr "Bir model dosyasının meshlenmesi başarısız oldu veya geçerli bir msgid "The supplied file couldn't be read because it's empty." msgstr "Seçilen dosya boş olduğundan okunamıyor." +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "Dosya biçimi uyumsuz olduğundan ayrıştırılamıyor." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Bilinmeyen dosya formatı. Giriş dosyası .stl, .obj, .amf(.xml) uzantılı olmalıdır." @@ -20859,8 +20988,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "Akıllı filament atamasını etkinleştir: Tasarrufu en üst düzeye çıkarmak için bir filamenti birden çok nozula atayın" # AI Translated -msgid "Fila Saving" -msgstr "Filament Tasarrufu" +msgid "File Saving" +msgstr "Dosya Kaydetme" msgid "Don't remind me again" msgstr "Bana bir daha hatırlatma" @@ -21268,6 +21397,9 @@ msgstr "Şimdi Yeniden Başlat" msgid "NO RAMMING AT ALL" msgstr "HİÇBİR ŞEKİLDE ÇARPMA YOK" +msgid "s" +msgstr "s" + msgid "Volumetric speed" msgstr "Hacimsel hız" @@ -21829,7 +21961,8 @@ msgstr "" "Baskılarınızı plakalara ayırın\n" "Çok sayıda parçası olan bir modeli baskıya hazır ayrı kalıplara bölebileceğinizi biliyor muydunuz? Bu, tüm parçaları takip etme sürecini basitleştirecektir." -#: resources/data/hints.ini: [hint:Speed up your print with Adaptive Layer Height] +#: resources/data/hints.ini: [hint:Speed up your print with Adaptive Layer +#: Height] msgid "" "Speed up your print with Adaptive Layer Height\n" "Did you know that you can print a model even faster by using the Adaptive Layer Height option? Check it out!" @@ -21902,7 +22035,8 @@ msgstr "" "Gücü artırın\n" "Modelin gücünü artırmak için daha fazla duvar halkası ve daha yüksek seyrek dolgu yoğunluğu kullanabileceğinizi biliyor muydunuz?" -#: resources/data/hints.ini: [hint:When do you need to print with the printer door opened] +#: resources/data/hints.ini: [hint:When do you need to print with the printer +#: door opened] msgid "" "When do you need to print with the printer door opened?\n" "Did you know that opening the printer door can reduce the probability of extruder/hotend clogging when printing lower temperature filament with a higher enclosure temperature? There is more info about this in the Wiki." @@ -21918,6 +22052,41 @@ msgstr "" "Eğilmeyi önleyin\n" "ABS gibi bükülmeye yatkın malzemelere baskı yaparken, ısıtma yatağı sıcaklığının uygun şekilde arttırılmasının bükülme olasılığını azaltabileceğini biliyor muydunuz?" +# AI Translated +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "Yerel Wayland canlı görüntüsü, GStreamer GTK video alıcısını gerektirir. Lütfen GStreamer için gtksink eklentisini yükleyin ve ardından OrcaSlicer'ı yeniden başlatın." + +# AI Translated +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "Yerel Wayland GStreamer video alıcısı başlatılamadı. Lütfen GStreamer GTK eklentisi kurulumunuzu denetleyin." + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "Bu görev için Windows Media Player gereklidir! İşletim sisteminiz için ‘Windows Media Player’ı etkinleştirmek istiyor musunuz?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource medya oynatımı için doğru şekilde kaydedilmemiş! Yeniden kaydetmek için Evet’e basın" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "Medya oynatma için kayıtlı BambuSource bileşeni eksik! Lütfen OrcaSlicer'ı yeniden yükleyin veya topluluk yardımı isteyin." + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "Farklı bir kurulumdan bir BambuSource kullanıyorsunuz, video oynatma doğru çalışmayabilir! Düzeltmek için Evet’e basın." + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "Sisteminizde video oynatmak için gerekli olan GStreamer H.264 codec bileşenleri eksik. (gstreamer1.0-plugins-bad veya gstreamer1.0-libav paketlerini kurmayı deneyin, ardından Orca Slicer’ı yeniden başlatın)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "Filament Tasarrufu" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/uk/OrcaSlicer_uk.po b/localization/i18n/uk/OrcaSlicer_uk.po index 8393e92947..3d23f7bbb1 100644 --- a/localization/i18n/uk/OrcaSlicer_uk.po +++ b/localization/i18n/uk/OrcaSlicer_uk.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: orcaslicerua\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: 2026-07-17 16:25+0300\n" "Last-Translator: Andrij Mizyk <andm1zyk@proton.me>\n" "Language-Team: Ukrainian\n" @@ -2906,6 +2906,10 @@ msgstr "Змінити" msgid "Merge with" msgstr "Обʼєднати з" +# AI Translated +msgid "Decompose Color" +msgstr "Розкласти колір" + msgid "Delete this filament" msgstr "Видалити цей філамент" @@ -3197,6 +3201,10 @@ msgstr "Збірка" msgid "Merge parts to an object" msgstr "Обʼєднати частини в обʼєкт" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "Використання змінної висоти шару разом із підшаром змішаного кольору може погіршити якість змішування кольорів." + msgid "Add layers" msgstr "Додати шари" @@ -7891,6 +7899,10 @@ msgstr "Пристосувати поточну пластину" msgid "The %s nozzle can not print %s." msgstr "Сопло %s не може друкувати %s." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "Друк філаменту змішаного кольору на принтері з одним екструдером потребує частої зміни філаменту та промивок, що може суттєво збільшити кількість відходів і ризик засмічення сопла або жолоба для відходів." + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "Змішування %1% з %2% в друці не рекомендується.\n" @@ -8019,12 +8031,44 @@ msgstr "Синхронізувати список ниток з AMS" msgid "Set filaments to use" msgstr "Встановити філаменти для використання" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Додати змішаний філамент" + +# AI Translated +msgid "Mixed Filament" +msgstr "Змішаний філамент" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Вилучити останній змішаний філамент" + +# AI Translated +msgid "Add mixed filament" +msgstr "Додати змішаний філамент" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "У змішаного філаменту недійсні або невідповідні компоненти. Будь ласка, відредагуйте відповідні записи ще раз." + msgid "Search plate, object and part." msgstr "Пошук пластини, об’єкта і деталі." msgid "Pellets" msgstr "Гранули" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "У змішаного філаменту пошкоджені посилання на компоненти" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Редагувати / Видалити / Обʼєднати" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "Цільовий змішаний філамент використовує цей фізичний філамент як компонент. Обʼєднання вилучить цей фізичний філамент і може зробити змішаний філамент недійсним. Продовжити?" + # AI Translated #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." @@ -8223,6 +8267,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Виявлено обʼєкт, що складається з кількох частин" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Зіставлення текстур із філаментами" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Попередження під час імпорту текстури" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Завантажити ці файли як єдиний обʼєкт з кількома частинами?\n" @@ -8433,6 +8485,22 @@ msgstr "" msgid "Sync now" msgstr "Синхронізувати зараз" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "Не вдалося імпортувати текстуру. Схоже, модель містить дані текстури, але завершити процес імпорту не вдалося. Модель буде імпортовано лише як геометрію." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Застосування кольорів текстури..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "Оновлення 3D-вигляду..." + +# AI Translated +msgid "Texture colors applied." +msgstr "Кольори текстури застосовано." + msgid "You can keep the modified presets for the new project or discard them" msgstr "Ви можете зберегти змінені пресети у новому проекті або відмовитися від них" @@ -9714,6 +9782,10 @@ msgstr "Спіральна ваза" msgid "First layer filament sequence" msgstr "Послідовність філаменту першого шару" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "Список філаментів містить змішані філаменти. Власна послідовність філаментів не діятиме." + msgid "By Layer" msgstr "По шарах" @@ -11717,30 +11789,6 @@ msgstr "Обʼєми промивки для зміни філаменту" msgid "Please choose the filament colour" msgstr "Будь ласка, виберіть колір філаменту" -# AI Translated -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "Нативний перегляд у Wayland потребує відеоприймача GStreamer GTK. Встановіть плагін gtksink для GStreamer, а потім перезапустіть OrcaSlicer." - -# AI Translated -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Не вдалося ініціалізувати нативний відеоприймач GStreamer для Wayland. Перевірте встановлення плагіна GStreamer GTK." - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "Для виконання цього завдання потрібен Windows Media Player! Бажаєте увімкнути 'Windows Media Player' для вашої операційної системи?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource не було правильно зареєстровано для відтворення медіафайлів! Натисніть \"Так\", щоб зареєструвати його повторно. Вас буде сповіщено двічі" - -# AI Translated -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Відсутній компонент BambuSource, зареєстрований для відтворення медіа! Перевстановіть OrcaSlicer або зверніться по допомогу до спільноти." - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Використовується BambuSource з іншої інсталяції, відтворення відео може працювати неправильно! Натисніть \"Так\", щоб виправити це." - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "Вашій системі бракує кодеків H.264 для GStreamer, які необхідні для відтворення відео. (Спробуйте встановити пакети gstreamer1.0-plugins-bad або gstreamer1.0-libav, а потім перезапустіть Orca Slicer?)" - # AI Translated msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "Хмарний агент недоступний. Перезапустіть OrcaSlicer і спробуйте ще раз." @@ -12462,6 +12510,10 @@ msgstr "Якщо ви все одно хочете друкувати, може msgid "No extrusions under current settings." msgstr "Немає екструзій під час поточних налаштувань." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "Використовується змішаний філамент із градієнтом, але параметр «Підшар змішаного кольору» вимкнено. Градієнт не буде надруковано." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "Плавний режим таймлапсу не підтримується, коли послідовність \"по обʼєкт\" увімкнено." @@ -12502,6 +12554,10 @@ msgstr "Можливо, ви захочете зменшити розмір мо msgid "Variable layer height is not supported with Organic supports." msgstr "Змінна висота шару не підтримується з Органічними підтримками." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "Філамент вежі протирання не може бути змішаним філаментом." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Різні діаметри сопел та різні діаметри філаменту можуть працювати некоректно коли ввімкнена підготовча вежа. Це експериментальна функція, тому використовуйте її з обережністю." @@ -14295,8 +14351,10 @@ msgstr "Час шару" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "Вентилятор охолодження деталей вмикається для шарів, розрахунковий час яких менший за це значення. Швидкість вентилятора інтерполюється між мінімальною та максимальною швидкістю вентилятора відповідно до часу друку шару" +# AI Translated +msgctxt "second" msgid "s" -msgstr "c" +msgstr "с" msgid "Default color" msgstr "Типовий колір" @@ -14626,6 +14684,62 @@ msgstr "Матеріал підтримки" msgid "Support material is commonly used to print supports and support interfaces." msgstr "Допоміжний матеріал зазвичай використовується для друку підтримки" +# AI Translated +msgid "Is mixed filament" +msgstr "Є змішаним філаментом" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Визначає, чи є цей слот філаменту змішаним філаментом, складеним з кількох фізичних філаментів" + +# AI Translated +msgid "Mixed filament components" +msgstr "Компоненти змішаного філаменту" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Розділені комами індекси філаментів-компонентів, починаючи з 1, наприклад \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Частки підшарів змішаного філаменту" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Розділені комами значення часток, сума яких дорівнює 1.0, наприклад \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Градієнт змішаного філаменту" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Вмикає режим градієнта за віссю Z для підшарів змішаного філаменту. Коли увімкнено, частки підшарів змінюються лінійно від шару до шару." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Діапазон градієнта змішаного філаменту" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Початкова та кінцева частки першого компонента в режимі градієнта. Пара значень через кому, наприклад \"0.10,0.90\" означає від 10% до 90%." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Крива градієнта змішаного філаменту" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Необовʼязкова власна крива у стилі Photoshop, що зіставляє поступ за віссю Z із часткою першого компонента. Записується як контрольні точки, розділені вертикальними рисками, у вигляді \"x,y\" (застарілий формат) або \"x,y,m_in,m_out\", коли потрібно перевизначити дотичну (порожнє значення або \"nan\" означає типове значення PCHIP). x належить до [0,1]; y обмежується налаштованим діапазоном часток, наприклад \"0,0.15|0.5,0.50|1,0.85\". Якщо поле порожнє, замість цього використовується лінійний gradient_range." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Градієнт змішаного філаменту для кожної частини" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Коли режим градієнта увімкнено, градієнт застосовується до кожної частини збірки окремо, а не до всієї збірки як до єдиного діапазону Z." + msgid "Filament printable" msgstr "Філамент придатний для друку" @@ -15972,8 +16086,9 @@ msgid "The allowed maximum output force of Y axis" msgstr "Максимальна дозволена вихідна сила осі Y" # AI Translated +msgctxt "Newton" msgid "N" -msgstr "N" +msgstr "Н" msgid "Bed mass of the Y axis" msgstr "Маса столу осі Y" @@ -15981,6 +16096,8 @@ msgstr "Маса столу осі Y" msgid "The machine bed mass load of Y axis" msgstr "Маса навантаження столу машини на вісь Y" +# AI Translated +msgctxt "gram" msgid "g" msgstr "г" @@ -17621,6 +17738,14 @@ msgstr "" "\n" "Якщо встановити значення у параметрі \"Кількість втягування перед витиранням\" нижче, надлишкове втягування буде виконано перед витиранням, інакше воно буде виконано після нього." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Підшар змішаного кольору" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Вмикає розбиття на підшари змішаного кольору. Коли увімкнено, шари, що містять філаменти змішаного кольору, розбиваються на підшари для отримання ефекту змішування кольорів." + # AI Translated msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "Вежа протирання може використовуватися для очищення залишків на соплі та стабілізації тиску в камері всередині сопла, щоб уникнути дефектів зовнішнього вигляду під час друку обʼєктів." @@ -18727,6 +18852,10 @@ msgstr "Не вдалося побудувати сітку файлу моде msgid "The supplied file couldn't be read because it's empty." msgstr "Наданий файл не вдалося прочитати, оскільки він порожній" +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "Формат файлу несумісний, і його не вдається прочитати." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Невідомий формат файлу: вхідний файл повинен мати розширення .stl, .obj або .amf (.xml)." @@ -21073,8 +21202,9 @@ msgstr "Вилучено" msgid "Enable smart filament assign: Assign one filament to multiple nozzles to maximize savings" msgstr "Дозволити розумне призначення філаменту: Призначте одну нитку до кількох сопел, щоб максимально заощадити" -msgid "Fila Saving" -msgstr "Збереження філаменту" +# AI Translated +msgid "File Saving" +msgstr "Збереження файлу" msgid "Don't remind me again" msgstr "Не нагадувати мені більше" @@ -21444,6 +21574,9 @@ msgstr "Перезапустити зараз" msgid "NO RAMMING AT ALL" msgstr "ВЗАГАЛІ БЕЗ УТРАМБУВАННЯ" +msgid "s" +msgstr "c" + msgid "Volumetric speed" msgstr "Обʼємна швидкість" @@ -22080,6 +22213,40 @@ msgstr "" "Уникнення деформації\n" "Чи знаєте ви, що при друку матеріалами, схильними до деформації, такими як ABS, відповідне підвищення температури столу може зменшити ймовірність деформації?" +# AI Translated +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "Нативний перегляд у Wayland потребує відеоприймача GStreamer GTK. Встановіть плагін gtksink для GStreamer, а потім перезапустіть OrcaSlicer." + +# AI Translated +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "Не вдалося ініціалізувати нативний відеоприймач GStreamer для Wayland. Перевірте встановлення плагіна GStreamer GTK." + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "Для виконання цього завдання потрібен Windows Media Player! Бажаєте увімкнути 'Windows Media Player' для вашої операційної системи?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource не було правильно зареєстровано для відтворення медіафайлів! Натисніть \"Так\", щоб зареєструвати його повторно. Вас буде сповіщено двічі" + +# AI Translated +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "Відсутній компонент BambuSource, зареєстрований для відтворення медіа! Перевстановіть OrcaSlicer або зверніться по допомогу до спільноти." + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "Використовується BambuSource з іншої інсталяції, відтворення відео може працювати неправильно! Натисніть \"Так\", щоб виправити це." + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "Вашій системі бракує кодеків H.264 для GStreamer, які необхідні для відтворення відео. (Спробуйте встановити пакети gstreamer1.0-plugins-bad або gstreamer1.0-libav, а потім перезапустіть Orca Slicer?)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +#~ msgid "g" +#~ msgstr "г" + +#~ msgid "Fila Saving" +#~ msgstr "Збереження філаменту" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/vi/OrcaSlicer_vi.po b/localization/i18n/vi/OrcaSlicer_vi.po index 936bb590c5..8ec3447568 100644 --- a/localization/i18n/vi/OrcaSlicer_vi.po +++ b/localization/i18n/vi/OrcaSlicer_vi.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: 2025-10-02 17:43+0700\n" "Last-Translator: \n" "Language-Team: hainguyen.ts13@gmail.com\n" @@ -3077,6 +3077,10 @@ msgstr "Chỉnh sửa" msgid "Merge with" msgstr "Gộp với" +# AI Translated +msgid "Decompose Color" +msgstr "Phân tách màu" + # AI Translated msgid "Delete this filament" msgstr "Xóa filament này" @@ -3389,6 +3393,10 @@ msgstr "Lắp ráp" msgid "Merge parts to an object" msgstr "Gộp các phần thành một vật thể" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "Sử dụng chiều cao lớp biến đổi cùng với lớp con màu pha trộn có thể làm giảm chất lượng pha màu." + # AI Translated msgid "Add layers" msgstr "Thêm lớp" @@ -8288,6 +8296,10 @@ msgstr "Tùy chỉnh bản hiện tại" msgid "The %s nozzle can not print %s." msgstr "Đầu phun %s không thể in %s." +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "Việc in filament màu pha trộn trên máy in một extruder đòi hỏi thay filament và xả thường xuyên, điều này có thể làm tăng đáng kể lượng phế liệu và nguy cơ tắc đầu phun / máng chứa phế liệu." + # AI Translated #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" @@ -8430,12 +8442,44 @@ msgstr "Đồng bộ danh sách filament từ AMS" msgid "Set filaments to use" msgstr "Đặt filament để sử dụng" +# AI Translated +msgid "Add Mixed Filament" +msgstr "Thêm filament pha trộn" + +# AI Translated +msgid "Mixed Filament" +msgstr "Filament pha trộn" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "Xóa filament pha trộn cuối cùng" + +# AI Translated +msgid "Add mixed filament" +msgstr "Thêm filament pha trộn" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "Filament pha trộn có thành phần không hợp lệ hoặc không khớp. Vui lòng chỉnh sửa lại các mục bị ảnh hưởng." + msgid "Search plate, object and part." msgstr "Tìm kiếm bản, đối tượng và phần." msgid "Pellets" msgstr "Viên" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "Filament pha trộn có tham chiếu thành phần bị lỗi" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "Chỉnh sửa / Xóa / Gộp" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "Filament pha trộn đích sử dụng filament vật lý này làm thành phần. Việc gộp sẽ xóa filament vật lý này và có thể làm filament pha trộn không còn hợp lệ. Tiếp tục?" + # AI Translated #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." @@ -8628,6 +8672,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "Phát hiện đối tượng nhiều phần" +# AI Translated +msgid "Matching textures to filaments" +msgstr "Đang khớp kết cấu với filament" + +# AI Translated +msgid "Texture Import Warning" +msgstr "Cảnh báo nhập kết cấu" + msgid "Load these files as a single object with multiple parts?\n" msgstr "Tải các file này như một đối tượng đơn với nhiều phần?\n" @@ -8857,6 +8909,22 @@ msgstr "" msgid "Sync now" msgstr "Đồng bộ ngay" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "Nhập kết cấu thất bại. Mô hình có vẻ chứa dữ liệu kết cấu, nhưng không thể hoàn tất quá trình nhập kết cấu. Mô hình sẽ chỉ được nhập dưới dạng hình học." + +# AI Translated +msgid "Applying texture colors..." +msgstr "Đang áp dụng màu kết cấu..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "Đang cập nhật khung nhìn 3D..." + +# AI Translated +msgid "Texture colors applied." +msgstr "Đã áp dụng màu kết cấu." + msgid "You can keep the modified presets for the new project or discard them" msgstr "Bạn có thể giữ các preset đã chỉnh sửa cho dự án mới hoặc loại bỏ chúng" @@ -10227,6 +10295,10 @@ msgstr "Bình xoắn ốc" msgid "First layer filament sequence" msgstr "Trình tự filament lớp đầu tiên" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "Danh sách filament có chứa filament pha trộn. Trình tự filament tùy chỉnh sẽ không có hiệu lực." + msgid "By Layer" msgstr "Theo lớp" @@ -12266,29 +12338,6 @@ msgstr "Khối lượng xả khi thay filament" msgid "Please choose the filament colour" msgstr "Vui lòng chọn màu filament" -# AI Translated -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "Xem trực tiếp trên Wayland thuần cần GStreamer GTK video sink. Vui lòng cài đặt plugin gtksink cho GStreamer, sau đó khởi động lại OrcaSlicer." - -# AI Translated -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "Khởi tạo GStreamer video sink trên Wayland thuần thất bại. Vui lòng kiểm tra việc cài đặt plugin GStreamer GTK của bạn." - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "Windows Media Player là cần thiết cho tác vụ này! Bạn có muốn bật 'Windows Media Player' cho hệ điều hành của bạn?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource chưa được đăng ký chính xác để phát media! Nhấn Có để đăng ký lại. Bạn sẽ được nhắc hai lần" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "Thiếu thành phần BambuSource đã đăng ký để phát media! Vui lòng cài đặt lại OrcaSlicer hoặc tìm kiếm sự giúp đỡ từ cộng đồng." - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "Đang sử dụng BambuSource từ cài đặt khác, phát video có thể không hoạt động đúng! Nhấn Có để sửa nó." - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "Hệ thống của bạn thiếu codec H.264 cho GStreamer, cần thiết để phát video. (Hãy thử cài đặt gói gstreamer1.0-plugins-bad hoặc gstreamer1.0-libav, sau đó khởi động lại Orca Slicer?)" - # AI Translated msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "Tác nhân cloud không khả dụng. Vui lòng khởi động lại OrcaSlicer rồi thử lại." @@ -13037,6 +13086,10 @@ msgstr "Nếu bạn vẫn muốn in, bạn có thể bật tùy chọn trong Tù msgid "No extrusions under current settings." msgstr "Không có đùn dưới cài đặt hiện tại." +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "Đang dùng filament pha trộn có gradient, nhưng 'Lớp con màu pha trộn' đã bị tắt. Gradient sẽ không được in." + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "Chế độ mượt của timelapse không được hỗ trợ khi trình tự \"theo đối tượng\" được bật." @@ -13075,6 +13128,10 @@ msgstr "Bạn có thể muốn giảm kích thước model của mình hoặc th msgid "Variable layer height is not supported with Organic supports." msgstr "Chiều cao lớp thay đổi không được hỗ trợ với support hữu cơ." +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "Filament của wipe tower không thể là filament pha trộn." + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "Đường kính đầu phun khác nhau và đường kính filament khác nhau có thể không hoạt động tốt khi prime tower được bật. Nó rất thử nghiệm, vì vậy vui lòng tiến hành thận trọng." @@ -14857,6 +14914,8 @@ msgstr "Thời gian lớp" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "Quạt làm mát phần sẽ được bật cho các lớp có thời gian ước tính ngắn hơn giá trị này. Tốc độ quạt được nội suy giữa tốc độ quạt tối thiểu và tối đa theo thời gian in lớp." +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -15196,6 +15255,62 @@ msgstr "Vật liệu support" msgid "Support material is commonly used to print supports and support interfaces." msgstr "Vật liệu support thường được sử dụng để in support và giao diện support." +# AI Translated +msgid "Is mixed filament" +msgstr "Là filament pha trộn" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "Xác định xem khe filament này có phải là filament pha trộn gồm nhiều filament vật lý hay không" + +# AI Translated +msgid "Mixed filament components" +msgstr "Thành phần của filament pha trộn" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "Chỉ số của các filament thành phần, bắt đầu từ 1, phân tách bằng dấu phẩy, ví dụ \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "Tỷ lệ lớp con của filament pha trộn" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "Các giá trị tỷ lệ phân tách bằng dấu phẩy, có tổng bằng 1.0, ví dụ \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "Gradient của filament pha trộn" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "Bật chế độ gradient theo phương Z cho các lớp con của filament pha trộn. Khi bật, tỷ lệ các lớp con thay đổi tuyến tính qua các lớp." + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "Phạm vi gradient của filament pha trộn" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "Tỷ lệ đầu và cuối của thành phần thứ nhất ở chế độ gradient. Cặp giá trị phân tách bằng dấu phẩy, ví dụ \"0.10,0.90\" nghĩa là từ 10% đến 90%." + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "Đường cong gradient của filament pha trộn" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "Đường cong tùy chỉnh kiểu Photoshop (tùy chọn) ánh xạ tiến trình theo Z sang tỷ lệ của thành phần thứ nhất. Được mã hóa dưới dạng các điểm điều khiển phân tách bằng dấu gạch đứng, theo dạng \"x,y\" (kiểu cũ) hoặc \"x,y,m_in,m_out\" khi cần ghi đè tiếp tuyến (giá trị trống hoặc \"nan\" nghĩa là dùng mặc định PCHIP). x nằm trong [0,1]; y bị giới hạn trong phạm vi tỷ lệ đã cấu hình, ví dụ \"0,0.15|0.5,0.50|1,0.85\". Khi để trống, gradient_range tuyến tính sẽ được dùng thay thế." + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "Gradient theo từng phần của filament pha trộn" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "Khi chế độ gradient được bật, áp dụng gradient cho từng phần của một cụm lắp ráp một cách độc lập thay vì coi toàn bộ cụm lắp ráp là một phạm vi Z duy nhất." + # AI Translated msgid "Filament printable" msgstr "Filament in được" @@ -16508,6 +16623,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "Lực đầu ra tối đa cho phép của trục Y" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -16520,6 +16636,7 @@ msgid "The machine bed mass load of Y axis" msgstr "Tải khối lượng bàn máy của trục Y" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -18140,6 +18257,14 @@ msgstr "" "\n" "Đặt giá trị trong cài đặt lượng rút trước khi lau bên dưới sẽ thực hiện bất kỳ rút dư nào trước khi lau, nếu không nó sẽ được thực hiện sau." +# AI Translated +msgid "Mixed color sublayer" +msgstr "Lớp con màu pha trộn" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "Bật việc chia thành lớp con màu pha trộn. Khi bật, các lớp có chứa filament màu pha trộn sẽ được chia thành các lớp con để tạo hiệu ứng pha màu." + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "Wipe tower có thể được sử dụng để làm sạch cặn trên đầu phun và ổn định áp suất buồng bên trong đầu phun, để tránh khuyết điểm bề ngoài khi in đối tượng." @@ -19260,6 +19385,10 @@ msgstr "Tạo lưới cho file mô hình thất bại hoặc không có hình d msgid "The supplied file couldn't be read because it's empty." msgstr "File được cung cấp không thể đọc được vì nó trống" +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "Định dạng tệp không tương thích nên không thể phân tích." + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "Định dạng file không xác định. File đầu vào phải có phần mở rộng .stl, .obj, .amf(.xml)." @@ -21681,8 +21810,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "Bật gán filament thông minh: Gán một filament cho nhiều đầu phun để tối đa hóa tiết kiệm" # AI Translated -msgid "Fila Saving" -msgstr "Tiết kiệm fila" +msgid "File Saving" +msgstr "Lưu tệp" # AI Translated msgid "Don't remind me again" @@ -22138,6 +22267,9 @@ msgstr "Khởi động lại ngay" msgid "NO RAMMING AT ALL" msgstr "HOÀN TOÀN KHÔNG RAMMING" +msgid "s" +msgstr "s" + # AI Translated msgid "Volumetric speed" msgstr "Tốc độ thể tích" @@ -22804,6 +22936,41 @@ msgstr "" "Tránh cong vênh\n" "Bạn có biết rằng khi in vật liệu dễ cong vênh như ABS, tăng nhiệt độ bàn nóng một cách thích hợp có thể giảm xác suất cong vênh không?" +# AI Translated +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "Xem trực tiếp trên Wayland thuần cần GStreamer GTK video sink. Vui lòng cài đặt plugin gtksink cho GStreamer, sau đó khởi động lại OrcaSlicer." + +# AI Translated +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "Khởi tạo GStreamer video sink trên Wayland thuần thất bại. Vui lòng kiểm tra việc cài đặt plugin GStreamer GTK của bạn." + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "Windows Media Player là cần thiết cho tác vụ này! Bạn có muốn bật 'Windows Media Player' cho hệ điều hành của bạn?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource chưa được đăng ký chính xác để phát media! Nhấn Có để đăng ký lại. Bạn sẽ được nhắc hai lần" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "Thiếu thành phần BambuSource đã đăng ký để phát media! Vui lòng cài đặt lại OrcaSlicer hoặc tìm kiếm sự giúp đỡ từ cộng đồng." + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "Đang sử dụng BambuSource từ cài đặt khác, phát video có thể không hoạt động đúng! Nhấn Có để sửa nó." + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "Hệ thống của bạn thiếu codec H.264 cho GStreamer, cần thiết để phát video. (Hãy thử cài đặt gói gstreamer1.0-plugins-bad hoặc gstreamer1.0-libav, sau đó khởi động lại Orca Slicer?)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "Tiết kiệm fila" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po index 99a6cadd67..81cd5a402b 100644 --- a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po +++ b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Slic3rPE\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: 2026-06-11 12:37-0300\n" "Last-Translator: Handle <mail@bysb.net>\n" "Language-Team: \n" @@ -2843,6 +2843,10 @@ msgstr "编辑" msgid "Merge with" msgstr "与其合并" +# AI Translated +msgid "Decompose Color" +msgstr "分解颜色" + msgid "Delete this filament" msgstr "移除此耗材" @@ -3124,6 +3128,10 @@ msgstr "组合体" msgid "Merge parts to an object" msgstr "合并零件到对象" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "同时使用可变层高与混色子层可能导致混色质量不佳。" + msgid "Add layers" msgstr "添加层" @@ -7638,6 +7646,10 @@ msgstr "自定义当前盘" msgid "The %s nozzle can not print %s." msgstr "%s 喷嘴无法打印 %s。" +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "在单挤出机打印机上打印混色耗材丝需要频繁换料和冲刷,可能显著增加废料以及喷嘴/废料槽堵塞的风险。" + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "不建议在打印时将 %1% 与 %2% 混合。\n" @@ -7763,12 +7775,44 @@ msgstr "从AMS同步材料列表" msgid "Set filaments to use" msgstr "配置可选择的材料" +# AI Translated +msgid "Add Mixed Filament" +msgstr "添加混合耗材丝" + +# AI Translated +msgid "Mixed Filament" +msgstr "混合耗材丝" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "移除最后一个混合耗材丝" + +# AI Translated +msgid "Add mixed filament" +msgstr "添加混合耗材丝" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "混合耗材丝的组分无效或不匹配。请重新编辑受影响的条目。" + msgid "Search plate, object and part." msgstr "搜索盘、模型和零件。" msgid "Pellets" msgstr "颗粒" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "混合耗材丝的组分引用已失效" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "编辑 / 删除 / 合并" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "目标混合耗材丝将此物理耗材丝用作组分。合并将移除此物理耗材丝,并可能使该混合耗材丝失效。是否继续?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "完成操作后,%s 项目将关闭并创建一个新项目。" @@ -7949,6 +7993,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "检测到多部分对象" +# AI Translated +msgid "Matching textures to filaments" +msgstr "正在将纹理匹配到耗材丝" + +# AI Translated +msgid "Texture Import Warning" +msgstr "纹理导入警告" + msgid "Load these files as a single object with multiple parts?\n" msgstr "将这些文件加载为一个多零件对象?\n" @@ -8154,6 +8206,22 @@ msgstr "" msgid "Sync now" msgstr "立即同步" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "纹理导入失败。模型中似乎包含纹理数据,但纹理导入过程未能完成。将仅导入模型的几何数据。" + +# AI Translated +msgid "Applying texture colors..." +msgstr "正在应用纹理颜色..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "正在更新 3D 视图..." + +# AI Translated +msgid "Texture colors applied." +msgstr "纹理颜色已应用。" + msgid "You can keep the modified presets for the new project or discard them" msgstr "您可以保留修改的预设到新项目中或者忽略这些修改" @@ -9389,6 +9457,10 @@ msgstr "旋转花瓶" msgid "First layer filament sequence" msgstr "首层耗材打印顺序" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "耗材丝列表中包含混合耗材丝。自定义耗材丝顺序将不会生效。" + msgid "By Layer" msgstr "逐层" @@ -11258,27 +11330,6 @@ msgstr "耗材丝更换时的冲刷体积" msgid "Please choose the filament colour" msgstr "请选择耗材丝颜色" -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "原生 Wayland 实时画面需要 GStreamer GTK 视频接收器。请安装 GStreamer 的 gtksink 插件,然后重启 OrcaSlicer。" - -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "原生 Wayland GStreamer 视频接收器初始化失败。请检查您的 GStreamer GTK 插件安装情况。" - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "此任务需要 Windows Media Player!您是否要为您的操作系统启用'Windows Media Player'?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "BambuSource 未正确注册用于媒体播放!按是重新注册它。您将被提示两次" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "缺少用于媒体播放的已注册 BambuSource 组件!请重新安装 OrcaSlicer 或寻求社区帮助。" - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "使用来自不同安装的 BambuSource,视频播放可能无法正常工作!按是修复它。" - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "您的系统缺少 GStreamer 所需的 H.264 编解码器,这是播放视频所必需的。(尝试安装 gstreamer1.0-plugins-bad 或 gstreamer1.0-libav 软件包,然后重新启动 Orca Slicer?)" - msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "云代理不可用。请重启 OrcaSlicer 后重试。" @@ -11991,6 +12042,10 @@ msgstr "如果您仍要打印,可以在 偏好设置 / 控制 / 切片 / 移 msgid "No extrusions under current settings." msgstr "根据当前设置,不会生成任何打印。" +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "使用了渐变混合耗材丝,但“混色子层”已关闭。渐变将不会被打印。" + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "平滑模式的延时摄影不支持在逐件打印模式下使用。" @@ -12027,6 +12082,10 @@ msgstr "或许您想要缩小模型的尺寸,或者更改当前打印设置, msgid "Variable layer height is not supported with Organic supports." msgstr "Organic支撑不支持可变层高。" +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "擦拭塔耗材丝不能是混合耗材丝。" + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "当启用擦拭塔时,不同的喷嘴直径和不同的耗材丝直径可能无法很好地工作。这是非常实验性的,所以请谨慎操作。" @@ -12374,7 +12433,6 @@ msgstr "mm 或 %" msgid "Other layers" msgstr "其它层" -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "除首层外的其他层的热床温度。0值表示该耗材丝不支持在Cool Plate SuperTack上打印。" @@ -13696,6 +13754,8 @@ msgstr "层时间" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "当层预估打印时间小于该数值时,部件冷却风扇将会被开启。风扇转速将根据层打印时间在最大和最小风扇转速之间插值获得" +# AI Translated +msgctxt "second" msgid "s" msgstr "s" @@ -14014,6 +14074,62 @@ msgstr "支撑材料" msgid "Support material is commonly used to print supports and support interfaces." msgstr "支撑材料通常用于打印支撑体和支撑接触面" +# AI Translated +msgid "Is mixed filament" +msgstr "是否为混合耗材丝" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "该耗材丝槽位是否为由多种物理耗材丝组成的混合耗材丝" + +# AI Translated +msgid "Mixed filament components" +msgstr "混合耗材丝组分" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "以逗号分隔的组分耗材丝序号(从 1 开始),例如 \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "混合耗材丝子层比例" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "以逗号分隔、总和为 1.0 的比例值,例如 \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "混合耗材丝渐变" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "为混合耗材丝的子层启用 Z 方向渐变模式。启用后,子层比例会随层数线性变化。" + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "混合耗材丝渐变范围" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "渐变模式下第一个组分的起始和结束比例。以逗号分隔的一对数值,例如 \"0.10,0.90\" 表示从 10% 到 90%。" + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "混合耗材丝渐变曲线" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "可选的 Photoshop 风格自定义曲线,将 Z 方向进度映射到第一个组分的比例。以竖线分隔的控制点进行编码,格式为 \"x,y\"(旧格式)或在需要覆盖切线时使用 \"x,y,m_in,m_out\"(留空或填 \"nan\" 表示使用 PCHIP 默认值)。x 取值范围为 [0,1];y 会被限制在所配置的比例范围内,例如 \"0,0.15|0.5,0.50|1,0.85\"。留空时改用线性的 gradient_range。" + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "混合耗材丝逐零件渐变" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "启用渐变模式时,对组合体中的每个零件分别应用渐变,而不是将整个组合体视为一个 Z 范围。" + msgid "Filament printable" msgstr "可打印耗材" @@ -15265,6 +15381,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "Y 轴允许的最大输出力" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -15277,6 +15394,7 @@ msgid "The machine bed mass load of Y axis" msgstr "Y 轴的机器热床质量负载" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -16848,6 +16966,14 @@ msgstr "" "\n" "在下方的擦拭前回抽量设置中输入一个数值,将在擦拭动作之前执行任何超出部分的回抽,否则超出部分的回抽将在擦拭之后执行。" +# AI Translated +msgid "Mixed color sublayer" +msgstr "混色子层" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "启用混色子层拆分。启用后,含有混色耗材丝的层将被拆分为子层,以实现混色效果。" + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "擦拭塔可以用来清理喷嘴上的残留料和让喷嘴内部的腔压达到稳定状态,以避免打印物体时出现外观瑕疵。" @@ -17923,6 +18049,10 @@ msgstr "模型文件的网格划分失败,或缺少有效的形状。" msgid "The supplied file couldn't be read because it's empty." msgstr "无法读取提供的文件,因为该文件内容为空。" +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "文件格式不兼容,无法解析。" + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "未知的文件格式。输入文件的扩展名必须为 .stl、.obj 或 .amf(.xml)。" @@ -20222,8 +20352,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "启用智能耗材分配:将一种耗材分配给多个喷嘴以最大化节省" # AI Translated -msgid "Fila Saving" -msgstr "耗材节省" +msgid "File Saving" +msgstr "文件保存" msgid "Don't remind me again" msgstr "不再提醒" @@ -20588,6 +20718,9 @@ msgstr "立即重启" msgid "NO RAMMING AT ALL" msgstr "完全不挤压" +msgid "s" +msgstr "s" + msgid "Volumetric speed" msgstr "体积流量" @@ -21212,6 +21345,39 @@ msgstr "" "避免翘曲\n" "您知道吗?打印ABS这类易翘曲材料时,适当提高热床温度可以降低翘曲的概率。" +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "原生 Wayland 实时画面需要 GStreamer GTK 视频接收器。请安装 GStreamer 的 gtksink 插件,然后重启 OrcaSlicer。" + +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "原生 Wayland GStreamer 视频接收器初始化失败。请检查您的 GStreamer GTK 插件安装情况。" + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "此任务需要 Windows Media Player!您是否要为您的操作系统启用'Windows Media Player'?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "BambuSource 未正确注册用于媒体播放!按是重新注册它。您将被提示两次" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "缺少用于媒体播放的已注册 BambuSource 组件!请重新安装 OrcaSlicer 或寻求社区帮助。" + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "使用来自不同安装的 BambuSource,视频播放可能无法正常工作!按是修复它。" + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "您的系统缺少 GStreamer 所需的 H.264 编解码器,这是播放视频所必需的。(尝试安装 gstreamer1.0-plugins-bad 或 gstreamer1.0-libav 软件包,然后重新启动 Orca Slicer?)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "耗材节省" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" diff --git a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po index 86f5263b1b..ded90c8950 100644 --- a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po +++ b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-19 14:07-0300\n" +"POT-Creation-Date: 2026-09-02 09:39-0300\n" "PO-Revision-Date: 2025-11-28 13:48-0600\n" "Last-Translator: tntchn <15895303+tntchn@users.noreply.github.com>\n" "Language-Team: \n" @@ -2913,6 +2913,10 @@ msgstr "編輯" msgid "Merge with" msgstr "合併到" +# AI Translated +msgid "Decompose Color" +msgstr "分解顏色" + msgid "Delete this filament" msgstr "刪除此線材" @@ -3209,6 +3213,10 @@ msgstr "組合體" msgid "Merge parts to an object" msgstr "合併零件為物件" +# AI Translated +msgid "Using variable layer height together with mixed color sublayer may result in poor color mixing quality." +msgstr "同時使用可變層高與混色子層可能導致混色品質不佳。" + # AI Translated msgid "Add layers" msgstr "新增層" @@ -7799,6 +7807,10 @@ msgstr "自訂列印板參數" msgid "The %s nozzle can not print %s." msgstr "%s 噴嘴無法列印 %s。" +# AI Translated +msgid "Printing mixed-color filament on a single-extruder printer requires frequent filament changes and flushing, which may significantly increase waste and the risk of nozzle / waste-chute clogging." +msgstr "在單擠出機列印裝置上列印混色線材需要頻繁換料與清理,可能大幅增加廢料以及噴嘴/廢料槽堵塞的風險。" + #, boost-format msgid "Mixing %1% with %2% in printing is not recommended.\n" msgstr "不建議在列印時混用 %1% 和 %2%。\n" @@ -7924,12 +7936,44 @@ msgstr "從 AMS 同步線材清單" msgid "Set filaments to use" msgstr "設定可選擇的線材" +# AI Translated +msgid "Add Mixed Filament" +msgstr "新增混合線材" + +# AI Translated +msgid "Mixed Filament" +msgstr "混合線材" + +# AI Translated +msgid "Remove last mixed filament" +msgstr "移除最後一個混合線材" + +# AI Translated +msgid "Add mixed filament" +msgstr "新增混合線材" + +# AI Translated +msgid "Mixed filament has invalid or mismatched components. Please re-edit affected entries." +msgstr "混合線材的成分無效或不相符。請重新編輯受影響的項目。" + msgid "Search plate, object and part." msgstr "搜尋列印板、物件和零件。" msgid "Pellets" msgstr "顆粒" +# AI Translated +msgid "Mixed filament has broken component references" +msgstr "混合線材的成分參照已失效" + +# AI Translated +msgid "Edit / Delete / Merge" +msgstr "編輯 / 刪除 / 合併" + +# AI Translated +msgid "The target mixed filament uses this physical filament as a component. Merging will remove this physical filament and may invalidate the mixed filament. Continue?" +msgstr "目標混合線材使用此實體線材作為成分。合併將移除此實體線材,並可能使該混合線材失效。是否繼續?" + #, c-format, boost-format msgid "After completing your operation, %s project will be closed and create a new project." msgstr "完成操作後,%s 專案將關閉並建立新專案。" @@ -8110,6 +8154,14 @@ msgstr "" msgid "Multi-part object detected" msgstr "偵測到多部分物件" +# AI Translated +msgid "Matching textures to filaments" +msgstr "正在將紋理對應到線材" + +# AI Translated +msgid "Texture Import Warning" +msgstr "紋理匯入警告" + msgid "Load these files as a single object with multiple parts?\n" msgstr "將這些檔案載入為一個多零件物件?\n" @@ -8320,6 +8372,22 @@ msgstr "" msgid "Sync now" msgstr "立即同步" +# AI Translated +msgid "Texture import failed. The model appears to contain texture data, but the texture import process could not be completed. The model will be imported as geometry only." +msgstr "紋理匯入失敗。模型中似乎包含紋理資料,但紋理匯入程序未能完成。將僅匯入模型的幾何資料。" + +# AI Translated +msgid "Applying texture colors..." +msgstr "正在套用紋理顏色..." + +# AI Translated +msgid "Updating 3D view..." +msgstr "正在更新 3D 檢視..." + +# AI Translated +msgid "Texture colors applied." +msgstr "紋理顏色已套用。" + msgid "You can keep the modified presets for the new project or discard them" msgstr "您可以將修改後的預設檔保留到新專案中或者忽略這些修改" @@ -9563,6 +9631,10 @@ msgstr "螺旋花瓶模式" msgid "First layer filament sequence" msgstr "首層線材列印順序" +# AI Translated +msgid "The filament list contains mixed filaments. Custom filament sequence will not take effect." +msgstr "線材清單中包含混合線材。自訂線材順序將不會生效。" + msgid "By Layer" msgstr "逐層" @@ -11466,27 +11538,6 @@ msgstr "線材更換時產生的廢料體積" msgid "Please choose the filament colour" msgstr "請選擇線材顏色" -msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." -msgstr "原生 Wayland 即時檢視需要 GStreamer GTK 視訊接收器。請為 GStreamer 安裝 gtksink 外掛程式,然後重新啟動 OrcaSlicer。" - -msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." -msgstr "無法初始化原生 Wayland GStreamer 視訊接收器。請檢查您的 GStreamer GTK 外掛程式安裝。" - -msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" -msgstr "執行此設定需要 Windows Media Player!您是否要啟用 Windows Media Player?" - -msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" -msgstr "「BambuSource 未正確註冊為媒體播放模組!請點選『是』進行重新註冊,過程中會有兩次提示" - -msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." -msgstr "缺少用於媒體播放的已註冊 BambuSource 元件!請重新安裝 OrcaSlicer 或尋求社群協助。" - -msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." -msgstr "BambuSource 來自其他安裝版本,可能導致影片播放異常!請點選『是』進行修復。" - -msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" -msgstr "您的系統缺少 GStreamer 的 H.264 編解碼器,這是播放影片所必需的。(請嘗試安裝 gstreamer1.0-plugins-bad 或 gstreamer1.0-libav 套件,然後重新啟動 Orca Slicer。)" - msgid "Cloud agent is not available. Please restart OrcaSlicer and try again." msgstr "雲端代理無法使用。請重新啟動 OrcaSlicer 後再試一次。" @@ -12195,6 +12246,10 @@ msgstr "如果您仍想列印,可以在「偏好設定 / 控制 / 切片 / 移 msgid "No extrusions under current settings." msgstr "根據目前設定,不會進行任何列印。" +# AI Translated +msgid "A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed." +msgstr "使用了漸層混合線材,但「混色子層」已停用。漸層將不會列印。" + msgid "Smooth mode of timelapse is not supported when \"by object\" sequence is enabled." msgstr "逐件列印模式下不支援使用平滑模式的縮時錄影。" @@ -12231,6 +12286,10 @@ msgstr "您可能想要減小模型的尺寸或更改目前的列印設定並重 msgid "Variable layer height is not supported with Organic supports." msgstr "有機樹支撐不支持可變層高。" +# AI Translated +msgid "The wipe tower filament cannot be a mixed filament." +msgstr "換料塔線材不能是混合線材。" + msgid "Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution." msgstr "當啟用換料時,不同的噴嘴直徑和線材直徑可能無法正常配合。此功能屬於實驗性階段,請小心使用。" @@ -12578,7 +12637,6 @@ msgstr "mm 或 %" msgid "Other layers" msgstr "其它層" -#, fuzzy msgid "This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack." msgstr "除首層外的其他層的熱床溫度。0值表示該線材不支援在低溫增穩列印板上列印。" @@ -13909,6 +13967,8 @@ msgstr "每一層列印時間" msgid "The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time." msgstr "當層預估列印時間小於該數值時,物件冷卻風扇將會被開啟。風扇轉速將根據層列印時間在最大和最小風扇轉速之間自動調整" +# AI Translated +msgctxt "second" msgid "s" msgstr "秒" @@ -14214,6 +14274,62 @@ msgstr "支撐材料" msgid "Support material is commonly used to print supports and support interfaces." msgstr "支撐材料通常用於列印支撐體和支撐接觸面" +# AI Translated +msgid "Is mixed filament" +msgstr "是否為混合線材" + +# AI Translated +msgid "Whether this filament slot is a mixed filament composed of multiple physical filaments" +msgstr "此線材槽是否為由多種實體線材組成的混合線材" + +# AI Translated +msgid "Mixed filament components" +msgstr "混合線材成分" + +# AI Translated +msgid "Comma-separated 1-based indices of component filaments, e.g. \"1,3\"" +msgstr "以逗號分隔的成分線材序號(從 1 開始),例如 \"1,3\"" + +# AI Translated +msgid "Mixed filament sublayer ratios" +msgstr "混合線材子層比例" + +# AI Translated +msgid "Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"" +msgstr "以逗號分隔、總和為 1.0 的比例值,例如 \"0.7,0.3\"" + +# AI Translated +msgid "Mixed filament gradient" +msgstr "混合線材漸層" + +# AI Translated +msgid "Enable Z-direction gradient mode for mixed filament sub-layers. When enabled, the sub-layer ratios vary linearly across layers." +msgstr "為混合線材的子層啟用 Z 方向漸層模式。啟用後,子層比例會隨層數線性變化。" + +# AI Translated +msgid "Mixed filament gradient range" +msgstr "混合線材漸層範圍" + +# AI Translated +msgid "Start and end ratios for the first component in gradient mode. Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%." +msgstr "漸層模式下第一個成分的起始與結束比例。以逗號分隔的一對數值,例如 \"0.10,0.90\" 表示從 10% 到 90%。" + +# AI Translated +msgid "Mixed filament gradient curve" +msgstr "混合線材漸層曲線" + +# AI Translated +msgid "Optional Photoshop-style custom curve mapping Z progress to the first component ratio. Encoded as pipe-separated control points, either \"x,y\" (legacy) or \"x,y,m_in,m_out\" when a tangent override is needed (empty token or \"nan\" means use PCHIP default). x in [0,1]; y is clamped to the configured ratio range, e.g. \"0,0.15|0.5,0.50|1,0.85\". When empty, the linear gradient_range is used instead." +msgstr "選用的 Photoshop 風格自訂曲線,將 Z 方向進度對應到第一個成分的比例。以直立線分隔的控制點進行編碼,格式為 \"x,y\"(舊格式)或在需要覆寫切線時使用 \"x,y,m_in,m_out\"(留空或填入 \"nan\" 表示使用 PCHIP 預設值)。x 的取值範圍為 [0,1];y 會被限制在所設定的比例範圍內,例如 \"0,0.15|0.5,0.50|1,0.85\"。留空時改用線性的 gradient_range。" + +# AI Translated +msgid "Mixed filament per-part gradient" +msgstr "混合線材逐零件漸層" + +# AI Translated +msgid "When gradient mode is enabled, apply the gradient to each part of an assembly independently rather than treating the whole assembly as one Z range." +msgstr "啟用漸層模式時,對組合體中的每個零件分別套用漸層,而不是將整個組合體視為單一 Z 範圍。" + msgid "Filament printable" msgstr "線材可列印" @@ -15466,6 +15582,7 @@ msgid "The allowed maximum output force of Y axis" msgstr "Y 軸允許的最大輸出力" # AI Translated +msgctxt "Newton" msgid "N" msgstr "N" @@ -15478,6 +15595,7 @@ msgid "The machine bed mass load of Y axis" msgstr "Y 軸的機器床台質量負載" # AI Translated +msgctxt "gram" msgid "g" msgstr "g" @@ -17042,6 +17160,14 @@ msgstr "" "\n" "在以下的『擦拭前的回抽量』設定中設定一個值,將在擦拭之前執行任何額外的回抽操作;否則,將在擦拭之後執行。" +# AI Translated +msgid "Mixed color sublayer" +msgstr "混色子層" + +# AI Translated +msgid "Enable mixed color sublayer splitting. When enabled, layers containing mixed color filaments will be split into sub-layers to achieve color mixing effects." +msgstr "啟用混色子層分割。啟用後,含有混色線材的層將被分割為子層,以達成混色效果。" + msgid "The wiping tower can be used to clean up residue on the nozzle and stabilize the chamber pressure inside the nozzle in order to avoid appearance defects when printing objects." msgstr "換料塔的功能是用於清除噴嘴上的殘留物,同時穩定噴嘴內的壓力,從而避免列印物件時出現外觀瑕疵。" @@ -18111,6 +18237,10 @@ msgstr "模型檔案網格化失敗或沒有有效形狀" msgid "The supplied file couldn't be read because it's empty." msgstr "無法讀取提供的檔案,因為該檔案為空" +# AI Translated +msgid "The file format is incompatible and cannot be parsed." +msgstr "檔案格式不相容,無法解析。" + msgid "Unknown file format: input file must have .stl, .obj, or .amf(.xml) extension." msgstr "檔案格式未知。輸入的檔案必須是 .stl、.obj 或 .amf(.xml) 格式。" @@ -20415,8 +20545,8 @@ msgid "Enable smart filament assign: Assign one filament to multiple nozzles to msgstr "啟用智慧線材指派:將一種線材指派給多個噴嘴以最大化節省" # AI Translated -msgid "Fila Saving" -msgstr "線材節省" +msgid "File Saving" +msgstr "檔案儲存" msgid "Don't remind me again" msgstr "不要再提醒我" @@ -20781,6 +20911,9 @@ msgstr "立即重新啟動" msgid "NO RAMMING AT ALL" msgstr "完全不擠壓" +msgid "s" +msgstr "秒" + msgid "Volumetric speed" msgstr "體積速度" @@ -21426,6 +21559,39 @@ msgstr "" "避免翹曲\n" "您知道嗎?當列印容易翹曲的材料(如 ABS)時,適當提高熱床溫度可以降低翹曲的機率。" +#~ msgid "Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer." +#~ msgstr "原生 Wayland 即時檢視需要 GStreamer GTK 視訊接收器。請為 GStreamer 安裝 gtksink 外掛程式,然後重新啟動 OrcaSlicer。" + +#~ msgid "Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation." +#~ msgstr "無法初始化原生 Wayland GStreamer 視訊接收器。請檢查您的 GStreamer GTK 外掛程式安裝。" + +#~ msgid "Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?" +#~ msgstr "執行此設定需要 Windows Media Player!您是否要啟用 Windows Media Player?" + +#~ msgid "BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice" +#~ msgstr "「BambuSource 未正確註冊為媒體播放模組!請點選『是』進行重新註冊,過程中會有兩次提示" + +#~ msgid "Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help." +#~ msgstr "缺少用於媒體播放的已註冊 BambuSource 元件!請重新安裝 OrcaSlicer 或尋求社群協助。" + +#~ msgid "Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it." +#~ msgstr "BambuSource 來自其他安裝版本,可能導致影片播放異常!請點選『是』進行修復。" + +#~ msgid "Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)" +#~ msgstr "您的系統缺少 GStreamer 的 H.264 編解碼器,這是播放影片所必需的。(請嘗試安裝 gstreamer1.0-plugins-bad 或 gstreamer1.0-libav 套件,然後重新啟動 Orca Slicer。)" + +# AI Translated +#~ msgid "N" +#~ msgstr "N" + +# AI Translated +#~ msgid "g" +#~ msgstr "g" + +# AI Translated +#~ msgid "Fila Saving" +#~ msgstr "線材節省" + #~ msgid "" #~ "Layer height is too small.\n" #~ "It will set to min_layer_height\n" From 51fd6327fee6c8e0a7d082906c3a8c56f35c477c Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Thu, 3 Sep 2026 00:15:18 +0300 Subject: [PATCH 27/51] Fix omitted assembly parts with height ranges (#15499) --- src/libslic3r/PrintApply.cpp | 8 +++++--- src/libslic3r/PrintObjectSlice.cpp | 13 ++++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index f03271bf73..90d60b5917 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -560,9 +560,11 @@ static inline bool model_volume_solid_or_modifier(const ModelVolume &mv) static inline Transform3f trafo_for_bbox(const Transform3d &object_trafo, const Transform3d &volume_trafo) { - Transform3d m = object_trafo * volume_trafo; - m.translation().x() = 0.; - m.translation().y() = 0.; + // Orca: Keep the volume's local XY offset for multipart overlap checks, but remove the object's bed placement. + Transform3d object_trafo_local = object_trafo; + object_trafo_local.translation().x() = 0.; + object_trafo_local.translation().y() = 0.; + Transform3d m = object_trafo_local * volume_trafo; return m.cast<float>(); } diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index f6a6b43e09..d16e381604 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -304,11 +304,16 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions( float z = zs[z_idx]; int idx_first_printable_region = -1; bool complex = false; + std::vector<int> printable_region_ids; for (int idx_region = 0; idx_region < int(layer_range.volume_regions.size()); ++ idx_region) { const PrintObjectRegions::VolumeRegion ®ion = layer_range.volume_regions[idx_region]; if (region.bbox->min().z() <= z && region.bbox->max().z() >= z) { - if (idx_first_printable_region == -1 && region.model_volume->is_model_part()) + if (region.model_volume->is_model_part()) + printable_region_ids.push_back(idx_region); + + if (idx_first_printable_region == -1 && region.model_volume->is_model_part()) { idx_first_printable_region = idx_region; + } else if (idx_first_printable_region != -1) { // Test for overlap with some other region. for (int idx_region2 = idx_first_printable_region; idx_region2 < idx_region; ++ idx_region2) { @@ -324,8 +329,10 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions( if (complex) zs_complex.push_back({ z_idx, z }); else if (idx_first_printable_region >= 0) { - const PrintObjectRegions::VolumeRegion ®ion = layer_range.volume_regions[idx_first_printable_region]; - slices_by_region[region.region->print_object_region_id()][z_idx] = std::move(volume_slices_find_by_id(volume_slices, region.model_volume->id()).slices[z_idx]); + for (int printable_region_id : printable_region_ids) { + const PrintObjectRegions::VolumeRegion ®ion = layer_range.volume_regions[printable_region_id]; + append(slices_by_region[region.region->print_object_region_id()][z_idx], std::move(volume_slices_find_by_id(volume_slices, region.model_volume->id()).slices[z_idx])); + } } } } From 8bf1d3ea84253cf4a0d63d5137650e23369e6f24 Mon Sep 17 00:00:00 2001 From: Kris Austin <kris.austin@gmail.com> Date: Wed, 2 Sep 2026 16:18:17 -0500 Subject: [PATCH 28/51] fix: clear 12 warning sites that only appear away from Windows (#15437) --- src/slic3r/GUI/CreatePresetsDialog.cpp | 4 +++- src/slic3r/GUI/Field.cpp | 18 +++++++++++++++--- src/slic3r/GUI/GUI_ObjectLayers.cpp | 2 +- src/slic3r/GUI/Jobs/PlaterWorker.hpp | 5 ++++- src/slic3r/GUI/MainFrame.cpp | 14 +++++++------- 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/CreatePresetsDialog.cpp b/src/slic3r/GUI/CreatePresetsDialog.cpp index 892576f0c0..e6fb6e0782 100644 --- a/src/slic3r/GUI/CreatePresetsDialog.cpp +++ b/src/slic3r/GUI/CreatePresetsDialog.cpp @@ -599,7 +599,9 @@ static char* read_json_file(const std::string &preset_path) return NULL; } - fread(json_contents, 1, file_size, json_file); + const size_t read_bytes = fread(json_contents, 1, file_size, json_file); + if (read_bytes != static_cast<size_t>(file_size)) + BOOST_LOG_TRIVIAL(error) << "Read " << read_bytes << " of " << file_size << " bytes from the JSON file"; fclose(json_file); return json_contents; diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index b0302f2cf8..142cf70522 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -941,7 +941,11 @@ void TextCtrl::BUILD() { temp->SetToolTip(get_tooltip_text(text_value)); if (!m_opt.multiline) { - text_ctrl->Bind(wxEVT_TEXT_ENTER, ([this, temp](wxEvent &e) + text_ctrl->Bind(wxEVT_TEXT_ENTER, ([ +#if !defined(__WXGTK__) + temp, +#endif // __WXGTK__ + this](wxEvent &e) { #if !defined(__WXGTK__) e.Skip(); @@ -973,7 +977,11 @@ void TextCtrl::BUILD() { temp->GetToolTip()->Enable(flag); }), text_ctrl->GetId()); - temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent &e) + temp->Bind(wxEVT_KILL_FOCUS, ([ +#if !defined(__WXGTK__) + temp, +#endif // __WXGTK__ + this](wxEvent &e) { e.Skip(); #if !defined(__WXGTK__) @@ -2597,7 +2605,11 @@ void ColourPicker::BUILD() // // recast as a wxWindow to fit the calling convention window = dynamic_cast<wxWindow*>(temp); - temp->Bind(wxEVT_COLOURPICKER_CHANGED, ([this,temp](wxCommandEvent e) { + temp->Bind(wxEVT_COLOURPICKER_CHANGED, ([ + #ifdef __WXMSW__ + temp, + #endif + this](wxCommandEvent e) { #ifdef __WXMSW__ draw_bmp_btn(temp, temp->GetColour()); #endif diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp index bbd7294ae5..93bdeec9ee 100644 --- a/src/slic3r/GUI/GUI_ObjectLayers.cpp +++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp @@ -48,7 +48,7 @@ void ObjectLayers::select_editor(LayerRangeEditor* editor, const bool is_last_ed * And as a result we couldn't edit this control. * */ #ifdef __WXOSX__ - wxTheApp->CallAfter([editor]() { + wxTheApp->CallAfter([]() { #endif //editor->SetFocus(); //editor->SelectAll(); diff --git a/src/slic3r/GUI/Jobs/PlaterWorker.hpp b/src/slic3r/GUI/Jobs/PlaterWorker.hpp index d38a57b6a6..f22bd6d511 100644 --- a/src/slic3r/GUI/Jobs/PlaterWorker.hpp +++ b/src/slic3r/GUI/Jobs/PlaterWorker.hpp @@ -79,9 +79,12 @@ class PlaterWorker: public Worker { steady_clock::time_point finalize_end = steady_clock::now(); long long finalize_duration = duration_cast<milliseconds>(finalize_end - finalize_start).count(); + // Bound first so typeid's operand is not a call. typeid evaluates it for a + // polymorphic type, which clang reports as -Wpotentially-evaluated-expression. + const Job &job = *m_job; BOOST_LOG_TRIVIAL(info) << std::fixed // do not use scientific notations - << "Job '" << typeid(*m_job).name() << "' " + << "Job '" << typeid(job).name() << "' " << "spend " << m_process_duration + finalize_duration << "ms " << "(process " << m_process_duration << "ms + finalize " << finalize_duration << "ms)"; diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 7b8912fe5b..675bc8da27 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -3068,10 +3068,10 @@ void MainFrame::init_menubar_as_editor() "", nullptr, [this](){return can_clone(); }, this); editMenu->AppendSeparator(); append_menu_item(editMenu, wxID_ANY, _L("Duplicate Current Plate"), - _L("Duplicate the current plate"),[this, handle_key_event](wxCommandEvent&) { + _L("Duplicate the current plate"),[this](wxCommandEvent&) { m_plater->duplicate_plate(); }, - "", nullptr, [this](){return true;}, this); + "", nullptr, [](){return true;}, this); editMenu->AppendSeparator(); #endif @@ -3338,11 +3338,11 @@ void MainFrame::init_menubar_as_editor() //parent_menu->Insert(0, about_item); append_menu_item( parent_menu, wxID_ANY, _L(about_title), "", - [this](wxCommandEvent &) { Slic3r::GUI::about();}, + [](wxCommandEvent &) { Slic3r::GUI::about();}, "", nullptr, []() { return true; }, this, 0); append_menu_item( parent_menu, wxID_ANY, _L("Preferences") + "\t" + ctrl + ",", "", - [this](wxCommandEvent &) { + [](wxCommandEvent &) { wxGetApp().open_preferences(); }, "", nullptr, []() { return true; }, this, 1); @@ -3530,13 +3530,13 @@ void MainFrame::init_menubar_as_editor() into_u8(_L("Syncing presets from cloud\u2026"))); wxGetApp().restart_sync_user_preset(); }, "", nullptr, - [this]() { + []() { return wxGetApp().is_user_login() && !wxGetApp().app_config->get_stealth_mode(); }, this); fileMenu->AppendSeparator(); append_menu_item( - fileMenu, wxID_ANY, _L("Plugins"), "", [this](wxCommandEvent&) { wxGetApp().open_plugins_dialog(); }, "", nullptr, + fileMenu, wxID_ANY, _L("Plugins"), "", [](wxCommandEvent&) { wxGetApp().open_plugins_dialog(); }, "", nullptr, []() { return true; }, this); fileMenu->AppendSeparator(); @@ -3640,7 +3640,7 @@ void MainFrame::init_menubar_as_editor() [this]() {return m_plater->is_view3D_shown();; }, this); // help append_menu_item(calib_menu, wxID_ANY, _L("Calibration Guide"), _L("Calibration Guide"), - [this](wxCommandEvent&) { wxLaunchDefaultBrowser("https://www.orcaslicer.com/wiki/calibration_guide", wxBROWSER_NEW_WINDOW); }, "", nullptr, + [](wxCommandEvent&) { wxLaunchDefaultBrowser("https://www.orcaslicer.com/wiki/calibration_guide", wxBROWSER_NEW_WINDOW); }, "", nullptr, [this]() {return m_plater->is_view3D_shown();; }, this); m_menubar->Append(calib_menu,wxString::Format("&%s", _L("Calibration"))); From 3605614ee7e13a0601ff9eb9d7dcb0d2b12cbb3f Mon Sep 17 00:00:00 2001 From: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> Date: Wed, 2 Sep 2026 19:06:01 -0300 Subject: [PATCH 29/51] More Labels (#15511) --- .github/workflows/pr-label-bot.yml | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pr-label-bot.yml b/.github/workflows/pr-label-bot.yml index 1214db0776..fe74841831 100644 --- a/.github/workflows/pr-label-bot.yml +++ b/.github/workflows/pr-label-bot.yml @@ -32,13 +32,21 @@ jobs: } const allowedLabels = [ + // kind of change + 'crash', 'bug-fix', 'enhancement', - 'Localization', - 'profile', 'QoL', + 'optimization', + // area 'UI/UX', - 'dependencies' + 'profile', + 'Localization', + // infrastructure + 'build', + 'test', + 'dependencies', + 'documentation' ]; const pr = context.payload.pull_request; const labelsList = `${allowedLabels @@ -182,13 +190,21 @@ jobs: } const allowedLabels = [ + // kind of change + 'crash', 'bug-fix', 'enhancement', - 'Localization', - 'profile', 'QoL', + 'optimization', + // area 'UI/UX', - 'dependencies' + 'profile', + 'Localization', + // infrastructure + 'build', + 'test', + 'dependencies', + 'documentation' ]; const issue = context.payload.issue; From 53c26a572449e1869b824975edb8fb954139fe2e Mon Sep 17 00:00:00 2001 From: Vladislav Khmelevsky <och95v@gmail.com> Date: Thu, 3 Sep 2026 03:21:27 +0400 Subject: [PATCH 30/51] fix: save 3d mouse settings (#15397) Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> --- src/libslic3r/AppConfig.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index 2d0c6a5d8d..29eb96aa5b 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -1440,6 +1440,7 @@ void AppConfig::set_mouse_device(const std::string& name, double translation_spe it->second["invert_yaw"] = invert_yaw ? "1" : "0"; it->second["invert_pitch"] = invert_pitch ? "1" : "0"; it->second["invert_roll"] = invert_roll ? "1" : "0"; + m_dirty = true; } std::vector<std::string> AppConfig::get_mouse_device_names() const From e6501bb1cecea4459df5481bfe76216cffaae2fa Mon Sep 17 00:00:00 2001 From: Kris Austin <kris.austin@gmail.com> Date: Wed, 2 Sep 2026 19:45:16 -0500 Subject: [PATCH 31/51] build: stop rebuilding the Flatpak dependencies on every run (#15501) --- .github/workflows/build_all.yml | 14 ++++- build_flatpak.sh | 3 + scripts/build_flatpak_with_docker.sh | 3 + scripts/flatpak/.gitignore | 1 + scripts/flatpak/check_manifest_cacheable.sh | 52 ++++++++++++++++++ scripts/flatpak/com.orcaslicer.OrcaSlicer.yml | 9 +-- scripts/flatpak/make_deps_tar.sh | 55 +++++++++++++++++++ scripts/flatpak/setup_env_ubuntu24.04.sh | 7 ++- 8 files changed, 135 insertions(+), 9 deletions(-) create mode 100755 scripts/flatpak/check_manifest_cacheable.sh create mode 100755 scripts/flatpak/make_deps_tar.sh diff --git a/.github/workflows/build_all.yml b/.github/workflows/build_all.yml index d991bedca6..0ab9cfe41d 100644 --- a/.github/workflows/build_all.yml +++ b/.github/workflows/build_all.yml @@ -279,20 +279,24 @@ jobs: echo "date=$(date +'%Y%m%d')" >> $GITHUB_ENV echo "git_commit_hash=$git_commit_hash" >> $GITHUB_ENV shell: bash + - name: Compute the flatpak-builder cache key + id: fp_cache_key + run: echo "key=flatpak-builder-${{ matrix.variant.arch }}-${{ hashFiles('deps/**', 'scripts/flatpak/com.orcaslicer.OrcaSlicer.yml', 'scripts/flatpak/make_deps_tar.sh') }}" >> "$GITHUB_OUTPUT" + shell: bash # Manage flatpak-builder cache externally so PRs restore but never upload - name: Restore flatpak-builder cache if: github.event_name == 'pull_request' uses: actions/cache/restore@v6 with: path: .flatpak-builder - key: flatpak-builder-${{ matrix.variant.arch }}-${{ github.event.pull_request.base.sha }} + key: ${{ steps.fp_cache_key.outputs.key }} restore-keys: flatpak-builder-${{ matrix.variant.arch }}- - name: Save/restore flatpak-builder cache if: github.event_name != 'pull_request' uses: actions/cache@v6 with: path: .flatpak-builder - key: flatpak-builder-${{ matrix.variant.arch }}-${{ github.sha }} + key: ${{ steps.fp_cache_key.outputs.key }} restore-keys: flatpak-builder-${{ matrix.variant.arch }}- - name: Disable debug info for faster CI builds run: | @@ -304,6 +308,12 @@ jobs: sed -i "/name: OrcaSlicer/{n;s|buildsystem: simple|buildsystem: simple\n build-options:\n env:\n git_commit_hash: \"$git_commit_hash\"|}" \ scripts/flatpak/com.orcaslicer.OrcaSlicer.yml shell: bash + - name: Check the manifest keeps orca_deps cacheable + run: ./scripts/flatpak/check_manifest_cacheable.sh + shell: bash + - name: Pack deps/ for the Flatpak manifest + run: ./scripts/flatpak/make_deps_tar.sh + shell: bash - uses: flatpak/flatpak-github-actions/flatpak-builder@master with: bundle: OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak diff --git a/build_flatpak.sh b/build_flatpak.sh index b805bb3422..12ccac372b 100755 --- a/build_flatpak.sh +++ b/build_flatpak.sh @@ -260,6 +260,9 @@ if [[ ! -f "./scripts/flatpak/com.orcaslicer.OrcaSlicer.yml" ]]; then exit 1 fi +echo -e "${YELLOW}Packing deps/ for the manifest...${NC}" +./scripts/flatpak/make_deps_tar.sh + # Build the Flatpak echo -e "${YELLOW}Building Flatpak package...${NC}" echo -e "This may take a while (30+ minutes depending on your system)..." diff --git a/scripts/build_flatpak_with_docker.sh b/scripts/build_flatpak_with_docker.sh index 9e8805af2f..eedfe53692 100755 --- a/scripts/build_flatpak_with_docker.sh +++ b/scripts/build_flatpak_with_docker.sh @@ -122,6 +122,9 @@ sed "/name: OrcaSlicer/{ \1 git_commit_hash: \"$GIT_COMMIT_HASH\"| }" > "$MANIFEST_DOCKER" +# ---------- pack deps/ ---------- +./scripts/flatpak/make_deps_tar.sh + # ---------- run build in Docker ---------- DOCKER="${DOCKER:-docker}" diff --git a/scripts/flatpak/.gitignore b/scripts/flatpak/.gitignore index 3b01f15d01..21abf7a876 100644 --- a/scripts/flatpak/.gitignore +++ b/scripts/flatpak/.gitignore @@ -1,3 +1,4 @@ builddir .flatpak-builder *.docker.yml +deps.tar* diff --git a/scripts/flatpak/check_manifest_cacheable.sh b/scripts/flatpak/check_manifest_cacheable.sh new file mode 100755 index 0000000000..e82190ca81 --- /dev/null +++ b/scripts/flatpak/check_manifest_cacheable.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# Check a Flatpak manifest for `type: dir` sources at or before the orca_deps +# module. +# +# Usage: check_manifest_cacheable.sh [manifest] +# Defaults to com.orcaslicer.OrcaSlicer.yml next to this script. +# +# Exits 0 when none are found, 1 when any are, listing them as file:line, and +# 2 when the manifest is missing or has no orca_deps module. + +set -euo pipefail + +anchor=orca_deps +manifest=${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/com.orcaslicer.OrcaSlicer.yml} + +module_re='^ - name: ' +dir_re='(^|[-{,[:space:]])type:[[:space:]]*dir([,}[:space:]]|$)' + +if [ ! -f "$manifest" ]; then + echo "$manifest: no such file" >&2 + exit 2 +fi + +anchor_start=$(grep -n "${module_re}${anchor}[[:space:]]*$" "$manifest" | cut -d: -f1 || true) +if [ -z "$anchor_start" ]; then + echo "$manifest: no module named '$anchor'; this check needs updating" >&2 + exit 2 +fi + +# First module header after the anchor, or EOF if the anchor is last. +anchor_end=$(grep -n "$module_re" "$manifest" | cut -d: -f1 | + awk -v s="$anchor_start" '$1 > s { print $1; exit }') +[ -n "$anchor_end" ] || anchor_end=$(awk 'END { print NR + 1 }' "$manifest") + +violations=$(awk -v e="$anchor_end" -v f="$manifest" -v mre="$module_re" -v dre="$dir_re" ' + { sub(/\r$/, "") } + /^[[:space:]]*#/ { next } + $0 ~ mre { module = $3 } + NR < e && $0 ~ dre { + printf "%s:%d: %s (module %s)\n", f, NR, $0, module + }' "$manifest") + +if [ -n "$violations" ]; then + printf '%s\n' "$violations" >&2 + echo >&2 + echo "flatpak-builder cannot checksum a directory, so each of these makes" >&2 + echo "$anchor and every module after it rebuild from scratch on every run." >&2 + echo "See the $anchor sources in this manifest for the tarball used instead." >&2 + exit 1 +fi + +echo "manifest OK: no 'type: dir' source at or before $anchor" diff --git a/scripts/flatpak/com.orcaslicer.OrcaSlicer.yml b/scripts/flatpak/com.orcaslicer.OrcaSlicer.yml index a3efaced8c..00aa430f84 100644 --- a/scripts/flatpak/com.orcaslicer.OrcaSlicer.yml +++ b/scripts/flatpak/com.orcaslicer.OrcaSlicer.yml @@ -144,6 +144,7 @@ modules: env: BUILD_DIR: deps/build_flatpak build-commands: + - tar xf deps.tar - | cmake -S deps -B $BUILD_DIR \ -DFLATPAK=ON \ @@ -169,10 +170,10 @@ modules: - /libpython/include sources: - # OrcaSlicer deps/ directory (avoids copying .git from worktree) - - type: dir - path: ../../deps - dest: deps + # flatpak-builder cannot checksum a directory, so a `type: dir` here would + # rebuild every dependency on every run. Generated by make_deps_tar.sh. + - type: file + path: deps.tar # --------------------------------------------------------------- # Pre-downloaded dependency archives diff --git a/scripts/flatpak/make_deps_tar.sh b/scripts/flatpak/make_deps_tar.sh new file mode 100755 index 0000000000..e561da2e7b --- /dev/null +++ b/scripts/flatpak/make_deps_tar.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# Pack deps/ into scripts/flatpak/deps.tar for the Flatpak manifest's orca_deps +# module. +# +# Usage: make_deps_tar.sh +# Requires GNU tar. On macOS, brew install gnu-tar. +# +# The archive is byte-reproducible. Member order, mtimes, ownership and the +# group/other write bits are pinned, so identical deps/ contents always produce +# an identical file. deps/build* and deps/DL_CACHE are excluded. +# +# Prints the output path, size and sha256. + +set -euo pipefail + +if [ "$#" -ne 0 ]; then + echo "usage: ${0##*/}" >&2 + exit 2 +fi + +tar_bin=$(command -v gtar || command -v tar || true) +tar_version=$([ -n "$tar_bin" ] && "$tar_bin" --version 2>/dev/null || true) +case $tar_version in + *"GNU tar"*) ;; + *) echo "${0##*/}: needs GNU tar; on macOS run 'brew install gnu-tar'" >&2 + exit 2 ;; +esac + +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +repo_root=$(cd "$script_dir/../.." && pwd) +out=$script_dir/deps.tar +tmp=$out.tmp +trap 'rm -f "$tmp"' EXIT + +"$tar_bin" --format=gnu \ + --sort=name \ + --mtime=@0 \ + --owner=0 --group=0 --numeric-owner \ + --mode=go-w \ + --exclude='deps/build*' \ + --exclude='deps/DL_CACHE' \ + -cf "$tmp" \ + -C "$repo_root" deps + +mv -f "$tmp" "$out" + +if command -v sha256sum >/dev/null 2>&1; then + sum=$(sha256sum "$out" | cut -d' ' -f1) +elif command -v shasum >/dev/null 2>&1; then + sum=$(shasum -a 256 "$out" | cut -d' ' -f1) +else + sum=unavailable +fi + +echo "Wrote $out ($(du -h "$out" | cut -f1), sha256 $sum)" diff --git a/scripts/flatpak/setup_env_ubuntu24.04.sh b/scripts/flatpak/setup_env_ubuntu24.04.sh index a0ccbb9b32..74b7629f60 100755 --- a/scripts/flatpak/setup_env_ubuntu24.04.sh +++ b/scripts/flatpak/setup_env_ubuntu24.04.sh @@ -8,8 +8,9 @@ flatpak install flathub org.gnome.Platform//50 org.gnome.Sdk//50 org.freedesktop ## # in OrcaSlicer folder, run following command to build Orca -# # First time build -# flatpak-builder --state-dir=.flatpak-builder --keep-build-dirs --user --force-clean build-dir scripts/flatpak/com.orcaslicer.OrcaSlicer.yml -# # Subsequent builds (only rebuilding OrcaSlicer) +# # First time build +# ./scripts/flatpak/make_deps_tar.sh && flatpak-builder --state-dir=.flatpak-builder --keep-build-dirs --user --force-clean build-dir scripts/flatpak/com.orcaslicer.OrcaSlicer.yml + +# # Subsequent builds (only rebuilding OrcaSlicer; run make_deps_tar.sh first if deps/ changed) # flatpak-builder --state-dir=.flatpak-builder --keep-build-dirs --user build-dir scripts/flatpak/com.orcaslicer.OrcaSlicer.yml --build-only=OrcaSlicer \ No newline at end of file From 171a7213040cc0aabf8546b7364913be45cada1f Mon Sep 17 00:00:00 2001 From: Clifford Garwood <cliff@cigii.com> Date: Thu, 3 Sep 2026 00:55:03 -0400 Subject: [PATCH 32/51] Harden the IMEX helper layer and give it one mode lookup Closes review comments 3, 5, 7, 8, 18 and 19, plus the library half of 20. These share a file, so they share a commit; each is independent of the others. - 3: ::isspace(char) is undefined for bytes above 0x7F because char is signed on our targets. Three call sites now go through one strip_whitespace() using an unsigned char cast. Line 308 parses imex_head_filament_map straight out of 3MF metadata, so a non-ASCII byte reached it without passing through the UI. - 5: an imex_head_filament_map override past the end of physical_extruder_map now falls through to the printer's own routing instead of resolving to a wrong filament. Bounded in resolve_filament_for_head, where the slot count is known, rather than at the parse site, which has no count to check against; the parse site also gains the absolute MAXIMUM_EXTRUDER_NUMBER cap its sibling already had. - 7: imex_physical_heater_for's !is_imex early return is what keeps a stock BBL profile (physical_extruder_map [1,0]) out of the heater remap, and had no test. Six cases now cover it, pinning pass-through rather than get_at()'s clamp. - 8: ImexRole::Span was missing from the imex_head_transform switch, so it warned under -Wswitch. Identity is correct, not merely convenient: a Span tool prints the primary's own zone through mid-print toolchanges and has no zone to be translated into. - 18: three positionally coupled string vectors were resolved by nine open-coded lookups using three incompatible bounds idioms. None read out of bounds, but six folded the guard into the match condition, so a ragged row did not stop the scan and a later duplicate name could win. struct ImexMode + find_imex_mode() is now the only resolution rule: the names array is the roster, first match wins, a short sibling pads to empty and sets ragged, not-found is an explicit -1. - 19: the letters P/C/M/S existed in three independent copies, one of which was the writer of the on-disk format. kImexRoleTable is now the single source, read by both parsers and the serializer. Adding a role was 14 edit sites with one compiler-enforced; it is now the enum, the table entry, and four -Wswitch switches. Verified by adding a fifth enumerator and recompiling: exactly four warnings, nothing else. - 20: imex_resolve_routing() extracts the mode/primary/routing chain that Print::validate and the plater's warning collector each derived separately. The three config keys keep their names, types and on-disk representation. This is a read-side view only; presets and 3MF files are unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- src/libslic3r/IMEXHelpers.cpp | 176 +++++++- src/libslic3r/IMEXHelpers.hpp | 171 ++++++- tests/libslic3r/test_imex_helpers.cpp | 621 ++++++++++++++++++++++++++ 3 files changed, 951 insertions(+), 17 deletions(-) diff --git a/src/libslic3r/IMEXHelpers.cpp b/src/libslic3r/IMEXHelpers.cpp index 3b45d24357..159d2f505a 100644 --- a/src/libslic3r/IMEXHelpers.cpp +++ b/src/libslic3r/IMEXHelpers.cpp @@ -13,6 +13,22 @@ namespace Slic3r { +namespace { +// Strip every whitespace byte from a token in place. +// +// Not `::isspace` directly: it takes an int that must be representable as unsigned char +// (or equal EOF), and `char` is signed on all three targets, so any byte >= 0x80 is sign- +// extended to a negative int and the call is undefined. The strings parsed below come from +// printer profiles and 3MF metadata, neither of which is guaranteed ASCII, so the unsigned +// char cast is the same one the rest of the codebase already applies to std::toupper. +void strip_whitespace(std::string& token) +{ + token.erase(std::remove_if(token.begin(), token.end(), + [](unsigned char c) { return std::isspace(c) != 0; }), + token.end()); +} +} // namespace + ConfigOptionInts effective_physical_extruder_map(const ConfigOptionInts* explicit_pem, int nozzle_count) { // One entry per logical extruder, so a profile has authored a map only when its length @@ -180,6 +196,25 @@ bool has_non_primary_mmu(const ConfigOptionInts& pem, int primary_physical) return false; } +char imex_role_letter(ImexRole role) +{ + for (const ImexRoleDesc& d : kImexRoleTable) + if (d.role == role) + return d.letter; + // Only reachable if a role was added to the enum but not to kImexRoleTable. Serializing + // it as Copy keeps the string parseable rather than emitting a token no parser accepts. + return 'C'; +} + +ImexRole imex_role_from_suffix(const std::string& suffix) +{ + if (suffix.size() == 1) + for (const ImexRoleDesc& d : kImexRoleTable) + if (d.letter == suffix[0]) + return d.role; + return ImexRole::Copy; +} + std::vector<std::pair<int, ImexRole>> parse_imex_active_tools(const std::string& active_tools_for_mode) { std::vector<std::pair<int, ImexRole>> out; @@ -187,21 +222,18 @@ std::vector<std::pair<int, ImexRole>> parse_imex_active_tools(const std::string& std::istringstream ss(active_tools_for_mode); std::string tok; while (std::getline(ss, tok, ',')) { - tok.erase(std::remove_if(tok.begin(), tok.end(), ::isspace), tok.end()); + strip_whitespace(tok); if (tok.empty()) continue; const auto colon = tok.find(':'); const std::string idx_str = (colon == std::string::npos) ? tok : tok.substr(0, colon); int phys = -1; try { phys = std::stoi(idx_str); } catch (...) { continue; } if (phys < 0 || phys >= (int)MAXIMUM_EXTRUDER_NUMBER) continue; - ImexRole role = ImexRole::Copy; - if (colon != std::string::npos) { - const std::string r = tok.substr(colon + 1); - if (r == "P") role = ImexRole::Primary; - else if (r == "M") role = ImexRole::Mirror; - else if (r == "S") role = ImexRole::Span; - // "C" and anything else → Copy. - } + // A bare token (no ':') is Copy here by design -- see the header note; the + // "bare == Primary" backwards-compat rule lives in imex_primary_tool_for_mode(). + const ImexRole role = (colon == std::string::npos) + ? ImexRole::Copy + : imex_role_from_suffix(tok.substr(colon + 1)); out.emplace_back(phys, role); } return out; @@ -272,7 +304,7 @@ int imex_primary_tool_for_mode(const std::string& active_tools_for_mode) std::string token; int first_bare = -1; while (std::getline(ss, token, ',')) { - token.erase(std::remove_if(token.begin(), token.end(), ::isspace), token.end()); + strip_whitespace(token); if (token.empty()) continue; const auto colon = token.find(':'); @@ -291,8 +323,9 @@ int imex_primary_tool_for_mode(const std::string& active_tools_for_mode) first_bare = idx; continue; } - const std::string role = token.substr(colon + 1); - if (role == "P") + // Same suffix reading as parse_imex_active_tools(), so the two can never disagree + // about which letter means Primary. + if (imex_role_from_suffix(token.substr(colon + 1)) == ImexRole::Primary) return idx; } return first_bare; @@ -305,14 +338,19 @@ std::map<int,int> parse_imex_head_filament_map(const std::string& s) std::istringstream ss(s); std::string token; while (std::getline(ss, token, ',')) { - token.erase(std::remove_if(token.begin(), token.end(), ::isspace), token.end()); + strip_whitespace(token); if (token.empty()) continue; auto colon = token.find(':'); if (colon == std::string::npos) continue; try { int phys = std::stoi(token.substr(0, colon)); int slot = std::stoi(token.substr(colon + 1)); - if (phys >= 0 && slot >= 1) + // Same absolute sanity cap parse_imex_active_tools applies to its own physical + // index: neither can exceed the slicer-wide extruder ceiling. This only rejects + // nonsense; the bound that matters (slot must index a filament that exists) is + // in resolve_filament_for_head, which is the one that knows the count. + if (phys >= 0 && phys < (int) MAXIMUM_EXTRUDER_NUMBER + && slot >= 1 && slot <= (int) MAXIMUM_EXTRUDER_NUMBER) result[phys] = slot; } catch (...) {} } @@ -333,6 +371,48 @@ int imex_primary_logical_from_objects(const std::vector<int>& used_slots_1b, return -1; } +ImexRouting imex_resolve_routing(const ConfigBase& cfg, + const std::string& parallel_mode, + const std::vector<int>& used_slots_1b, + const ConfigOptionInts& pem) +{ + ImexRouting out; + // An empty mode is a plate that never carried one; kImexPrimaryMode is the reserved + // "no parallel printing" sentinel. Neither resolves a row, so neither is looked up. + if (parallel_mode.empty() || parallel_mode == kImexPrimaryMode) + return out; + out.parallel = true; + + // One lookup of the mode table, one parse of its roster, one search for the Primary + // marker. Every field below is derived from these, so no caller can re-derive one of + // them differently. + out.active_tools = find_imex_mode(cfg, parallel_mode).active_tools; + out.tools = parse_imex_active_tools(out.active_tools); + out.primary_phys = imex_primary_tool_for_mode(out.active_tools); + + if (out.primary_phys >= 0) + out.primary_logical = imex_primary_logical_from_objects(used_slots_1b, pem, out.primary_phys); + + // Bounds-checked exactly as imex_primary_logical_from_objects checks: get_at() would + // clamp an out-of-range slot to values.front(), which is how a head that nothing routes + // to can end up listed as a head something routes to. + out.routed_heads.reserve(used_slots_1b.size()); + for (int slot_1b : used_slots_1b) { + const int slot_0b = slot_1b - 1; + if (slot_0b >= 0 && slot_0b < (int) pem.values.size()) + out.routed_heads.push_back(pem.values[slot_0b]); + } + std::sort(out.routed_heads.begin(), out.routed_heads.end()); + out.routed_heads.erase(std::unique(out.routed_heads.begin(), out.routed_heads.end()), + out.routed_heads.end()); + + // The pem emptiness test is not folded into primary_logical: an unpopulated map means + // the printer has declared no routing at all, which is not the same claim as "this + // plate's filaments go somewhere else", and only the latter is an error. + out.primary_unrouted = out.primary_phys >= 0 && !pem.values.empty() && out.primary_logical < 0; + return out; +} + std::vector<int> imex_secondary_logical_slots(const std::vector<int>& active_physicals, int primary_physical, const std::map<int,int>& plate_head_filament_map, @@ -357,7 +437,16 @@ int resolve_filament_for_head(const std::map<int,int>& plate_map, auto it = plate_map.find(physical); if (it != plate_map.end()) { const int zero_based = it->second - 1; - if (zero_based >= 0) + // pem has one entry per logical filament slot, so its size IS the slot count and + // an override outside it names a filament that does not exist. Bounding here rather + // than at the parse site is deliberate: the parser is handed a raw string with no + // notion of how many filaments the project has, while every consumer of this + // function's result indexes a per-filament array. The picker only ever offers + // indices into pem (IMEXFilamentPickerPopover::build_row), so nothing the UI can + // author is rejected -- only a hand-edited or corrupt 3MF. Such an override falls + // through to the printer's own routing, i.e. it behaves as if it were absent, + // rather than resolving to a wrong filament that get_at() would silently clamp. + if (zero_based >= 0 && zero_based < (int) pem.values.size()) return zero_based; } return first_filament_for_physical_head(pem, physical); @@ -376,6 +465,14 @@ Transform3d imex_head_transform(int /*primary*/, int /*target*/, ImexRole role, { switch (role) { case ImexRole::Primary: + case ImexRole::Span: + // Span is the within-gantry multicolor partner of Primary: it prints the same + // objects in the same zone via mid-print toolchanges, so it has no zone of its own + // to be translated or reflected into. Identity is the only transform that keeps it + // on top of the primary. calc_imex_ghosts skips Span outright (no ghost is baked + // for it, since the primary's ghost already covers that zone), so today this case + // is unreachable — it is here so that a future caller which does reach it gets the + // right answer rather than the fall-through, and so -Wswitch stays quiet. return Transform3d::Identity(); case ImexRole::Copy: return Eigen::Translation3d(gantry_offset.x(), gantry_offset.y(), 0.0) @@ -422,6 +519,55 @@ Vec2d compute_imex_slice_offset(bool firmware_managed, return primary_zone_box->center(); } +namespace { +// Builds the ImexMode for row `i`, padding whatever sibling array does not reach it. +// `names` is known non-null and `i` known in range; `tools` / `gcodes` may be either. +ImexMode imex_mode_at(const ConfigOptionStrings* names, + const ConfigOptionStrings* tools, + const ConfigOptionStrings* gcodes, + size_t i) +{ + ImexMode m; + m.index = (int) i; + m.name = names->values[i]; + const bool has_tools = tools != nullptr && i < tools->values.size(); + const bool has_gcode = gcodes != nullptr && i < gcodes->values.size(); + if (has_tools) m.active_tools = tools->values[i]; + if (has_gcode) m.gcode = gcodes->values[i]; + m.ragged = !has_tools || !has_gcode; + return m; +} +} // namespace + +ImexMode find_imex_mode(const ConfigBase& cfg, const std::string& name) +{ + const auto* names = cfg.option<ConfigOptionStrings>("imex_mode_names"); + if (names == nullptr) + return {}; + // The siblings are fetched once, not per row: a missing option is the same answer for + // every row, and it is padding rather than a reason to fail the lookup. + const auto* tools = cfg.option<ConfigOptionStrings>("imex_mode_active_tools"); + const auto* gcodes = cfg.option<ConfigOptionStrings>("imex_mode_gcodes"); + for (size_t i = 0; i < names->values.size(); ++i) + if (names->values[i] == name) + return imex_mode_at(names, tools, gcodes, i); + return {}; +} + +std::vector<ImexMode> imex_mode_table(const ConfigBase& cfg) +{ + std::vector<ImexMode> table; + const auto* names = cfg.option<ConfigOptionStrings>("imex_mode_names"); + if (names == nullptr) + return table; + const auto* tools = cfg.option<ConfigOptionStrings>("imex_mode_active_tools"); + const auto* gcodes = cfg.option<ConfigOptionStrings>("imex_mode_gcodes"); + table.reserve(names->values.size()); + for (size_t i = 0; i < names->values.size(); ++i) + table.push_back(imex_mode_at(names, tools, gcodes, i)); + return table; +} + bool imex_hull_violates_zones(const std::vector<BoundingBoxf3>& zones, const Polygon& hull) { if (hull.points.empty()) diff --git a/src/libslic3r/IMEXHelpers.hpp b/src/libslic3r/IMEXHelpers.hpp index 6942e9d273..8a5b59deea 100644 --- a/src/libslic3r/IMEXHelpers.hpp +++ b/src/libslic3r/IMEXHelpers.hpp @@ -23,6 +23,69 @@ class PresetBundle; // plate mode equals this. Treat any value NOT equal to this as a parallel mode. inline constexpr const char* kImexPrimaryMode = "primary"; +// ============================================================================= +// The printer's IMEX mode table +// ============================================================================= +// `imex_mode_names`, `imex_mode_active_tools` and `imex_mode_gcodes` are three +// independent ConfigOptionStrings coupled only by POSITION: entry i of each describes +// mode i. Nothing in the config system enforces equal length, and all three are on-disk +// format, so a hand-edited preset, a profile written before a key existed, or a 3MF from +// another build can arrive with a sibling array shorter than `imex_mode_names`. +// +// ImexMode is the in-memory view of one row. It is NOT a config type — nothing +// serializes it, and the three keys keep their names, their types and their on-disk +// representation exactly as before. +// +// Resolution rule. Applied by find_imex_mode() / imex_mode_table() and NOWHERE else; +// every consumer in the tree goes through one of the two: +// * `imex_mode_names` is the roster. A mode exists iff a row of that array carries its +// name, and the FIRST such row wins. (The modes editor uniquifies names on entry, so +// duplicates only reach here from a hand-edited profile; first-match is what a +// std::find over the names array already did, and what the editor's own row order +// means.) +// * A sibling array too short to reach that row yields an EMPTY string for that field +// and sets `ragged`. It never yields an out-of-range read, and it never degrades to +// "no such mode": a missing script is a mode with no script, and the row's index +// still has to be reported to {imex_mode_index}. Callers that need tools already +// treat an empty tools string as "no tools" (imex_primary_tool_for_mode() returns -1, +// parse_imex_active_tools() returns {}), which is the behaviour they had before. +// * `ragged` separates "the profile omitted this row" from "the author wrote an empty +// entry" — a distinction every open-coded call site used to lose. +// +// Reporting: a non-Primary mode that resolves to an empty tool roster produces G-code +// that is wrong rather than merely unconfigured (no per-head temperature transition, and +// a suppressed initial T<n>), so GCode::_do_export() warns and falls back to Primary, +// exactly as it already does for a name that resolves to no row at all. +struct ImexMode +{ + // Position in `imex_mode_names`. -1 means no row carries the requested name — the + // not-found case, explicit rather than implied by an out-of-range index. + int index = -1; + // The row's entry in `imex_mode_names`. Empty when !found(). + std::string name; + // `imex_mode_active_tools[index]`, or "" when that array is shorter than index + 1. + std::string active_tools; + // `imex_mode_gcodes[index]`, or "" when that array is shorter than index + 1. + std::string gcode; + // At least one sibling array was too short to cover `index`. Always false when + // !found(). + bool ragged = false; + + bool found() const { return this->index >= 0; } + explicit operator bool() const { return this->found(); } +}; + +// Resolves `name` against the printer's mode table; see the rule above. `cfg` is any +// config carrying the printer keys (a DynamicPrintConfig, a PrintConfig, ...). A config +// with no `imex_mode_names` yields a not-found ImexMode rather than throwing, so callers +// need no null check of their own. +ImexMode find_imex_mode(const ConfigBase& cfg, const std::string& name); + +// The whole roster: one ImexMode per entry of `imex_mode_names`, in config order, padded +// by the same rule. Empty when `imex_mode_names` is absent. Use this where the caller +// wants every mode (the modes editor, the plate's mode menu) rather than one by name. +std::vector<ImexMode> imex_mode_table(const ConfigBase& cfg); + // ============================================================================= // PHYSICAL vs LOGICAL extruder indices — read this before adding a new IMEX call site // ============================================================================= @@ -189,13 +252,24 @@ int imex_primary_tool_for_mode(const std::string& active_tools_for_mode); // Parses the "phys:slot,phys:slot" serialization of imex_head_filament_map. // Keys are physical T-indices (0-based); values are 1-based filament slots. -// Returns empty map on empty/malformed input. +// Returns empty map on empty/malformed input. This string arrives straight from 3MF +// metadata, so tokens outside [0, MAXIMUM_EXTRUDER_NUMBER) are dropped here as an absolute +// sanity cap; the bound against the *project's* filament count lives in +// resolve_filament_for_head, which is where that count is actually known. std::map<int,int> parse_imex_head_filament_map(const std::string& s); // Resolves which 0-based logical filament to use for a physical head. -// 1. If the plate map overrides `physical`, returns (slot - 1) — 1-based → 0-based. +// 1. If the plate map overrides `physical` with a slot that indexes an existing filament, +// returns (slot - 1) — 1-based → 0-based. // 2. Else falls back to first_filament_for_physical_head(pem, physical). // Returns -1 if neither source yields a valid filament. +// +// `pem` has one entry per logical filament slot, so its size is the slot count and the +// result is always a valid index into it (or -1). An override naming a slot at or past +// that size cannot be honoured — every consumer indexes a per-filament array, and the +// ConfigOption get_at() several of them use clamps rather than failing, which would turn a +// corrupt 3MF's "1:9999" into a silently wrong filament. Such an override is ignored and +// the printer's own routing applies, exactly as if the override were absent. int resolve_filament_for_head(const std::map<int,int>& plate_map, const ConfigOptionInts& pem, int physical); @@ -233,6 +307,40 @@ std::vector<int> imex_secondary_logical_slots(const std::vector<int>& active_p enum class ImexRole { Primary, Copy, Mirror, Span }; +// The one table a new role has to be added to. +// +// `letter` is the suffix the role carries in the `imex_mode_active_tools` on-disk format +// ("0:P,1:C,2:M,3:S"). That string is written into printer profiles and into 3MF projects, +// so the letters are FORMAT: never renumber, rename or reorder them, only append. The table +// order is also the order the modes editor cycles its tiles through and lists its colour +// legend in, which is why Primary comes first. +// +// Everything that used to open-code the letters or a parallel small-int encoding of the +// enum now goes through this table or through ImexRole itself, so adding a fifth role means +// editing the enum, this table, and the places that must genuinely make a new decision +// about it (the transform switch, the zone/marker classification, the editor's per-role +// colour + label) — not a scattered set of int mappings that fail silently when missed. +struct ImexRoleDesc { + ImexRole role; + char letter; +}; +inline constexpr ImexRoleDesc kImexRoleTable[] = { + { ImexRole::Primary, 'P' }, + { ImexRole::Copy, 'C' }, + { ImexRole::Mirror, 'M' }, + { ImexRole::Span, 'S' }, +}; + +// The on-disk suffix letter for `role`. Inverse of imex_role_from_suffix(). +char imex_role_letter(ImexRole role); + +// Reads a whole token suffix — everything after the ':' — back into a role. Anything that +// is not exactly one of the table's letters is Copy: that covers "C" itself, an empty +// suffix ("3:"), a multi-character suffix, and any letter a future build might write that +// this one does not know. Copy is the historical fallback for an unrecognised suffix and +// must stay so, or a project saved by a newer build changes meaning when reopened here. +ImexRole imex_role_from_suffix(const std::string& suffix); + // Parses `imex_mode_active_tools[mode]` into a list of (physical_head, role) pairs. // Accepted token forms (comma-separated, whitespace-tolerant): // "phys" — bare index, role defaults to Copy @@ -251,6 +359,61 @@ enum class ImexRole { Primary, Copy, Mirror, Span }; // in hand and need the full head/role list (e.g. ghost factory/updater). std::vector<std::pair<int, ImexRole>> parse_imex_active_tools(const std::string& active_tools_for_mode); +// ============================================================================= +// The one derivation of "what does this plate's mode do, and does its filament reach +// the primary" — shared by the hard block and the pre-slice warning +// ============================================================================= +// Print::validate() refuses a plate whose filaments do not route to the mode's declared +// primary; Plater's collect_imex_warnings() names that same primary's filament in its +// bed-temperature and filament-type warnings. Both need the identical chain: resolve the +// mode row -> parse its tool roster -> find the declared primary -> ask whether any used +// filament slot routes there. Computed twice, the two drift, and the warning ends up +// describing a plate the block describes differently. Computed here, they cannot. +// +// Everything in ImexRouting is a pure function of the four inputs. Deliberately absent: +// the `is_imex` gate (Print::validate's, and only its, outer condition) and any bound on +// the tool roster against the project's filament count (the plater's, and only its, way of +// dropping tools it has no filament preset to name). Those are genuinely per-caller and +// each stays with the caller that owns it. +struct ImexRouting +{ + // The mode is a parallel mode: non-empty and not kImexPrimaryMode. False leaves every + // other field at its default — no mode row is even looked up. + bool parallel = false; + // `imex_mode_active_tools` for this mode, or "" when the mode resolves to no row / a + // ragged table. See find_imex_mode(). + std::string active_tools; + // The parsed roster, physical head + role, in the order the string lists them. + std::vector<std::pair<int, ImexRole>> tools; + // Declared primary PHYSICAL head, from imex_primary_tool_for_mode(). -1 when the mode + // resolves to no row, an empty roster, or a roster with no Primary marker. + int primary_phys = -1; + // The 0-based LOGICAL filament slot the primary prints with: the first entry of + // `used_slots_1b` whose pem entry maps to `primary_phys`. -1 when nothing on the plate + // routes there (which is exactly what `primary_unrouted` reports as a hard error, and + // what the plater's warning path falls back out of so it still has a filament to name). + int primary_logical = -1; + // Sorted, deduplicated PHYSICAL heads that `used_slots_1b` actually reach. Slots outside + // the pem are dropped rather than clamped: ConfigOption::get_at() clamps to values front, + // which would let an error message name the very head it just said nothing routes to. + std::vector<int> routed_heads; + // The mode declares a primary, the printer has a routing map, and no used filament + // reaches that primary. The precise condition Print::validate refuses the plate on. + bool primary_unrouted = false; + + bool routes_to_primary() const { return this->primary_logical >= 0; } +}; + +// `cfg` is any config carrying the printer's mode-table keys — the Print's applied config +// in the slicer, the edited printer preset in the GUI. `used_slots_1b` is 1-based filament +// indices (Print::extruders() + 1, or PartPlate::get_extruders()). `pem` is the effective +// physical_extruder_map: already normalised on the Print's config by Print::apply(), and +// obtained from effective_physical_extruder_map(PresetBundle) in the GUI. +ImexRouting imex_resolve_routing(const ConfigBase& cfg, + const std::string& parallel_mode, + const std::vector<int>& used_slots_1b, + const ConfigOptionInts& pem); + // Per-gantry grouping derived from the active_tools string. The single source of // truth for paired-gantry visualization aggregation: when the primary's gantry // has at least one Span tool, every non-primary gantry's representative tool @@ -319,6 +482,10 @@ ImexMirrorAxis imex_mirror_axis_for(int primary_phys, int target_phys, int tools // while the other axis tracks 1:1. // Zero-length gantry_offset degenerates to identity. // Primary: identity. +// Span: identity, same as Primary. A Span tool shares the primary's gantry AND its zone, +// printing the same objects through mid-print toolchanges rather than a duplicate +// placed elsewhere, so there is nothing to translate or reflect. calc_imex_ghosts +// bakes no ghost for a Span head, so no caller reaches this today. Transform3d imex_head_transform(int primary, int target, ImexRole role, const Vec2d& gantry_offset, const Vec2d& primary_zone_center, diff --git a/tests/libslic3r/test_imex_helpers.cpp b/tests/libslic3r/test_imex_helpers.cpp index 9c66bb871b..05c98b9a5a 100644 --- a/tests/libslic3r/test_imex_helpers.cpp +++ b/tests/libslic3r/test_imex_helpers.cpp @@ -4,6 +4,9 @@ #include "libslic3r/PrintConfig.hpp" #include "libslic3r/Point.hpp" +#include <iterator> +#include <set> + using namespace Slic3r; using Catch::Matchers::WithinAbs; @@ -97,6 +100,72 @@ TEST_CASE("imex_pem_tool_for - MMU collapse routes multiple logical slots to one REQUIRE(imex_pem_tool_for(6, "copy_mode", pem) == 3); } +// --------------------------------------------------------------------------- +// imex_physical_heater_for +// +// GCodeWriter::set_temperature(temp, wait, tool) is logical-in, and M104/M109 name a +// physical heater, so this is the single translation point for every non-SEMM +// multi-extruder printer in the tree — IMEX or not. `is_imex` is what keeps non-IMEX +// profiles out of the remap, and physical_extruder_map carries a *different* meaning on +// those (indexed by extruder id, not filament id), so remapping them would retarget +// heaters. fdm_bbl_3dp_002_common ships a non-identity [1, 0], which is the case that +// makes the guard load-bearing rather than cosmetic. +// --------------------------------------------------------------------------- + +TEST_CASE("imex_physical_heater_for - non-IMEX printer passes the logical id through untouched", "[IMEX]") { + // The shipping BBL dual-nozzle map. With is_imex=0 the id must come out unchanged; + // remapping here would send filament 0's M109 to heater 1 and vice versa. + auto pem = make_pem({1, 0}); + REQUIRE(imex_physical_heater_for(false, pem, 0) == 0); + REQUIRE(imex_physical_heater_for(false, pem, 1) == 1); + + // Same guard on an AFC-shaped map, where a remap would collapse four ids onto heater 0. + auto afc = make_pem({0, 0, 0, 0, 1, 2, 3}); + REQUIRE(imex_physical_heater_for(false, afc, 3) == 3); + REQUIRE(imex_physical_heater_for(false, afc, 6) == 6); +} + +TEST_CASE("imex_physical_heater_for - IMEX identity map is a no-op", "[IMEX]") { + auto pem = make_pem({0, 1, 2, 3}); + for (int id = 0; id < 4; ++id) + REQUIRE(imex_physical_heater_for(true, pem, id) == id); +} + +TEST_CASE("imex_physical_heater_for - IMEX permutation remaps to the physical heater", "[IMEX]") { + // The same [1, 0] map read the IMEX way: filament 0 lives on heater 1. + auto pem = make_pem({1, 0}); + REQUIRE(imex_physical_heater_for(true, pem, 0) == 1); + REQUIRE(imex_physical_heater_for(true, pem, 1) == 0); +} + +TEST_CASE("imex_physical_heater_for - IMEX MMU collapse targets the shared heater", "[IMEX]") { + // User's IQEX: logical 0-3 are AFC lanes on heater 0, so all four heat the same hotend. + auto pem = make_pem({0, 0, 0, 0, 1, 2, 3}); + REQUIRE(imex_physical_heater_for(true, pem, 0) == 0); + REQUIRE(imex_physical_heater_for(true, pem, 3) == 0); + REQUIRE(imex_physical_heater_for(true, pem, 4) == 1); + REQUIRE(imex_physical_heater_for(true, pem, 6) == 3); +} + +TEST_CASE("imex_physical_heater_for - out-of-range ids pass through instead of clamping", "[IMEX]") { + // Deliberately NOT get_at(), which clamps to values.front() and would silently retarget + // an out-of-range id at whatever heater sits in slot 0 — heater 1 for this map. + auto pem = make_pem({1, 0}); + REQUIRE(imex_physical_heater_for(true, pem, -1) == -1); // the "no T parameter" sentinel + REQUIRE(imex_physical_heater_for(true, pem, 2) == 2); // one past the end + REQUIRE(imex_physical_heater_for(true, pem, 99) == 99); + + // Same for the single-entry PrintConfig default, which every non-IMEX printer carries. + auto lone = make_pem({0}); + REQUIRE(imex_physical_heater_for(true, lone, 1) == 1); +} + +TEST_CASE("imex_physical_heater_for - empty pem never remaps", "[IMEX]") { + ConfigOptionInts empty_pem; + REQUIRE(imex_physical_heater_for(true, empty_pem, 0) == 0); + REQUIRE(imex_physical_heater_for(false, empty_pem, 2) == 2); +} + TEST_CASE("imex_suppresses_bare_toolchange - non-IMEX printer never suppresses", "[IMEX]") { REQUIRE_FALSE(imex_suppresses_bare_toolchange("", 0)); REQUIRE_FALSE(imex_suppresses_bare_toolchange("", 1)); @@ -356,6 +425,40 @@ TEST_CASE("parse_imex_head_filament_map - empty string", "[IMEX]") { REQUIRE(parse_imex_head_filament_map("").empty()); } +TEST_CASE("parse_imex_head_filament_map - a high byte makes its token unparseable", "[IMEX]") { + // This string comes straight from 3MF metadata, so bytes above 0x7F are reachable without + // ever passing through the UI. 0xFF is a letter, never whitespace in any single-byte locale, + // so it survives the whitespace strip and makes the physical index unparseable — that token + // is dropped and the well-formed token beside it still parses. + // + // What this case does NOT demonstrate is the undefined behaviour of handing a negative char + // to isspace: glibc's ctype table is defined over -128..255 and isspace(-1) returns 0, so + // this passes just as well against the unguarded version. Catching that needs a sanitizer + // build (UBSan) or an MSVC debug CRT, not an assertion here. + auto m = parse_imex_head_filament_map("\xFF" "0:3,4:5"); + REQUIRE(m.size() == 1); + REQUIRE(m.count(0) == 0); + REQUIRE(m[4] == 5); + + // A high byte in the slot half is likewise rejected rather than read out of range. + REQUIRE(parse_imex_head_filament_map("0:\xFF").empty()); +} + +TEST_CASE("parse_imex_head_filament_map - absurd indices are rejected at parse", "[IMEX]") { + // Absolute sanity cap only: nothing can exceed the slicer-wide extruder ceiling. + // The bound against the project's actual filament count is resolve_filament_for_head's. + REQUIRE(parse_imex_head_filament_map("1:9999").empty()); + REQUIRE(parse_imex_head_filament_map("9999:1").empty()); + REQUIRE(parse_imex_head_filament_map("1:0").empty()); // slots are 1-based + REQUIRE(parse_imex_head_filament_map("-1:2").empty()); + REQUIRE(parse_imex_head_filament_map("1:-2").empty()); + + // A bad token does not poison the good ones beside it. + auto m = parse_imex_head_filament_map("0:9999,1:2"); + REQUIRE(m.size() == 1); + REQUIRE(m[1] == 2); +} + TEST_CASE("resolve_filament_for_head - override wins", "[IMEX]") { auto pem = make_pem({0, 0, 0, 0, 1, 2, 3}); std::map<int,int> plate_map{{0, 3}}; // 1-based slot 3 = 0-based logical 2 @@ -375,6 +478,26 @@ TEST_CASE("resolve_filament_for_head - no routing for head", "[IMEX]") { REQUIRE(resolve_filament_for_head(plate_map, pem, 2) == -1); } +TEST_CASE("resolve_filament_for_head - override past the filament count is ignored", "[IMEX]") { + // pem has one entry per logical filament slot, so a slot at or past its size names a + // filament that does not exist. A project file carrying such an override must not + // resolve to it: downstream lookups use ConfigOption::get_at, which clamps instead of + // failing, so an honoured 1:9999 would be a silently wrong filament rather than a crash. + auto pem = make_pem({0, 0, 0, 0, 1, 2, 3}); // 7 slots -> valid 0-based logicals are 0..6 + + // Highest legal slot still resolves — the bound must not be off by one. + REQUIRE(resolve_filament_for_head({{1, 7}}, pem, 1) == 6); + + // One past it, and far past it, fall back to the printer's own routing for that head + // (first_filament_for_physical_head(pem, 1) == 4), i.e. the override is treated as absent. + REQUIRE(resolve_filament_for_head({{1, 8}}, pem, 1) == 4); + REQUIRE(resolve_filament_for_head({{1, 9999}}, pem, 1) == 4); + + // With no pem routing for the head either, an out-of-range override yields -1 rather + // than a wrong slot, so callers take their "no filament" branch. + REQUIRE(resolve_filament_for_head({{5, 9999}}, pem, 5) == -1); +} + TEST_CASE("imex_primary_tool_for_mode - role marker authoritative", "[IMEX]") { // Tab.cpp enforces one Primary per mode; position is not semantically meaningful. REQUIRE(imex_primary_tool_for_mode("0:P,1:C,2:C") == 0); @@ -582,6 +705,22 @@ TEST_CASE("imex_head_transform - primary is identity", "[IMEX]") { REQUIRE(xf.isApprox(Transform3d::Identity())); } +TEST_CASE("imex_head_transform - span is identity like primary", "[IMEX]") { + // A Span tool is the primary's within-gantry multicolor partner: it prints the same + // objects in the primary's own zone through mid-print toolchanges, so it has no zone of + // its own to be translated or reflected into. It must ignore gantry_offset entirely — + // translating it by one would place a phantom copy in a neighbouring zone. + const Vec2d offset{120.0, 30.0}; + Transform3d xf = imex_head_transform(0, 1, ImexRole::Span, offset, Vec2d{50.0, 50.0}, + ImexMirrorAxis::X); + REQUIRE(xf.isApprox(Transform3d::Identity())); + + // Cross-gantry axis choice is irrelevant for Span for the same reason. + Transform3d xf_y = imex_head_transform(0, 2, ImexRole::Span, offset, Vec2d{50.0, 50.0}, + ImexMirrorAxis::Y); + REQUIRE(xf_y.isApprox(Transform3d::Identity())); +} + TEST_CASE("imex_head_transform - mirror with zero offset is identity", "[IMEX]") { const Vec2d offset{0.0, 0.0}; Transform3d xf = imex_head_transform(0, 1, ImexRole::Mirror, offset, Vec2d::Zero(), ImexMirrorAxis::X); @@ -643,6 +782,60 @@ TEST_CASE("resolve_filament_for_head - no routing returns -1 (ghost color fallba REQUIRE(resolve_filament_for_head(override_on_5, pem, 5) == 6); } +TEST_CASE("imex_role_letter - the historical letters are pinned", "[IMEX]") { + // The write half of the on-disk format for imex_mode_active_tools, spelled out rather than + // read back off kImexRoleTable: both imex_role_letter() and imex_role_from_suffix() are + // linear scans of that table, so driving them from it asserts only that the table agrees + // with itself. These are the letters already written into printer profiles and 3MF projects. + REQUIRE(imex_role_letter(ImexRole::Primary) == 'P'); + REQUIRE(imex_role_letter(ImexRole::Copy) == 'C'); + REQUIRE(imex_role_letter(ImexRole::Mirror) == 'M'); + REQUIRE(imex_role_letter(ImexRole::Span) == 'S'); +} + +TEST_CASE("the role table gives every role its own letter", "[IMEX]") { + // The one property the table can actually violate, and the one the round trip depends on: + // a duplicated letter makes the on-disk format ambiguous (imex_role_from_suffix returns the + // first row, so the second role silently reads back as the first), and a duplicated role + // makes imex_role_letter's answer depend on row order. Appending a fifth role with a letter + // already in use is exactly how that happens. + std::set<char> letters; + std::set<ImexRole> roles; + for (const ImexRoleDesc& d : kImexRoleTable) { + INFO("role table row with letter '" << d.letter << "'"); + CHECK(letters.insert(d.letter).second); + CHECK(roles.insert(d.role).second); + } + REQUIRE(letters.size() == std::size(kImexRoleTable)); +} + +TEST_CASE("imex_role_from_suffix - the historical letters are pinned", "[IMEX]") { + // Spelled out rather than derived from the table, so a change to the table that would + // reinterpret an existing preset fails here instead of silently agreeing with itself. + REQUIRE(imex_role_from_suffix("P") == ImexRole::Primary); + REQUIRE(imex_role_from_suffix("C") == ImexRole::Copy); + REQUIRE(imex_role_from_suffix("M") == ImexRole::Mirror); + REQUIRE(imex_role_from_suffix("S") == ImexRole::Span); +} + +TEST_CASE("imex_role_from_suffix - anything unrecognised stays Copy", "[IMEX]") { + // Copy is the long-standing fallback for an unknown suffix; a project written by a build + // that knows a role this one does not must degrade to Copy, not to Primary. + REQUIRE(imex_role_from_suffix("") == ImexRole::Copy); + REQUIRE(imex_role_from_suffix("X") == ImexRole::Copy); + REQUIRE(imex_role_from_suffix("p") == ImexRole::Copy); // case sensitive, as before + REQUIRE(imex_role_from_suffix("PP") == ImexRole::Copy); // suffix is the whole token tail +} + +TEST_CASE("imex_primary_tool_for_mode - only an exact P suffix names the primary", "[IMEX]") { + // Shares imex_role_from_suffix() with parse_imex_active_tools(), so this pins that the + // two agree on which token is the Primary rather than each deciding for itself. + REQUIRE(imex_primary_tool_for_mode("0:C,1:P,2:M") == 1); + REQUIRE(imex_primary_tool_for_mode("0:PP,1:M") == -1); + REQUIRE(imex_primary_tool_for_mode("0:p,1:M") == -1); + REQUIRE(imex_primary_tool_for_mode("0,1,2") == 0); // legacy bare index +} + TEST_CASE("parse_imex_active_tools - Span role parsed from S suffix", "[IMEX]") { auto out = parse_imex_active_tools("0:P,1:S,2:M,3:M"); REQUIRE(out.size() == 4); @@ -884,3 +1077,431 @@ TEST_CASE("imex_hull_violates_zones - violating any one of several zones is enou // Overlaps none of the three (sits in the gaps between them). REQUIRE_FALSE(imex_hull_violates_zones(zones, scaled_rect(12, 12, 18, 18))); } + +// --------------------------------------------------------------------------- +// find_imex_mode / imex_mode_table +// +// The three mode options are positionally coupled ConfigOptionStrings with nothing +// enforcing equal length, so these pin the resolution rule that every IMEX call site +// now shares: the names array is the roster, the first matching row wins, and a sibling +// array too short to reach that row pads to an empty string and flags `ragged` instead +// of reading out of bounds or degrading into "no such mode". +// --------------------------------------------------------------------------- + +namespace { + +// Only the keys the mode lookup reads. Any of the three may be omitted by passing an +// empty vector for it -- `imex_mode_table` and `find_imex_mode` must cope with a config +// that never registered the option at all, which is what a non-IMEX preset looks like. +DynamicPrintConfig mode_cfg(const std::vector<std::string>& names, + const std::vector<std::string>& tools, + const std::vector<std::string>& gcodes) +{ + DynamicPrintConfig cfg; + if (!names.empty()) cfg.set_key_value("imex_mode_names", new ConfigOptionStrings(names)); + if (!tools.empty()) cfg.set_key_value("imex_mode_active_tools", new ConfigOptionStrings(tools)); + if (!gcodes.empty()) cfg.set_key_value("imex_mode_gcodes", new ConfigOptionStrings(gcodes)); + return cfg; +} + +} // namespace + +TEST_CASE("find_imex_mode - an exact name yields that row's index, tools and script", "[IMEX]") { + // The defining property: all three fields come from the SAME position, so a lookup + // that resolved the index against one array and read another cannot pass. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "copy", "iq-copy" }, + { "0:P", "0:P,1:C", "0:P,1:C,2:C,3:C" }, + { "", "COPY_SCRIPT", "QUAD_SCRIPT" }); + + const ImexMode m = find_imex_mode(cfg, "copy"); + REQUIRE(m.found()); + CHECK(m.index == 1); + CHECK(m.name == "copy"); + CHECK(m.active_tools == "0:P,1:C"); + CHECK(m.gcode == "COPY_SCRIPT"); + CHECK_FALSE(m.ragged); + + const ImexMode last = find_imex_mode(cfg, "iq-copy"); + REQUIRE(last.found()); + CHECK(last.index == 2); + CHECK(last.active_tools == "0:P,1:C,2:C,3:C"); + CHECK(last.gcode == "QUAD_SCRIPT"); +} + +TEST_CASE("find_imex_mode - a name no row carries is not found", "[IMEX]") { + // What a plate's mode becomes once it is renamed or deleted in Printer Settings, or + // once the project is opened against a preset that names its modes differently. The + // not-found case has to be explicit: an index of -1, not an out-of-range index that + // happens to read empty. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "copy" }, + { "0:P", "0:P,1:C" }, + { "", "COPY_SCRIPT" }); + + const ImexMode m = find_imex_mode(cfg, "copy-renamed"); + CHECK_FALSE(m.found()); + CHECK(m.index == -1); + CHECK(m.name.empty()); + CHECK(m.active_tools.empty()); + CHECK(m.gcode.empty()); + CHECK_FALSE(m.ragged); + CHECK_FALSE(static_cast<bool>(m)); +} + +TEST_CASE("find_imex_mode - a short active-tools array pads and reports ragged", "[IMEX]") { + // The reviewer's opening case: a profile whose imex_mode_active_tools does not reach + // the last mode. The mode still exists -- it is named, and its index still has to be + // reported to {imex_mode_index} -- but it has no tools, and `ragged` is what lets a + // caller say so instead of silently printing a parallel mode with an empty roster. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "copy" }, + { "0:P" }, + { "", "COPY_SCRIPT" }); + + const ImexMode m = find_imex_mode(cfg, "copy"); + REQUIRE(m.found()); + CHECK(m.index == 1); + CHECK(m.active_tools.empty()); + CHECK(m.gcode == "COPY_SCRIPT"); + CHECK(m.ragged); + + // The row the short array does reach is not ragged. + CHECK_FALSE(find_imex_mode(cfg, kImexPrimaryMode).ragged); +} + +TEST_CASE("find_imex_mode - a short gcodes array pads and reports ragged", "[IMEX]") { + // Raggedness in the other direction. A mode with no script is a legitimate profile -- + // Primary is normally exactly that -- so this must not cost the mode its tools. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "copy" }, + { "0:P", "0:P,1:C" }, + { "" }); + + const ImexMode m = find_imex_mode(cfg, "copy"); + REQUIRE(m.found()); + CHECK(m.index == 1); + CHECK(m.active_tools == "0:P,1:C"); + CHECK(m.gcode.empty()); + CHECK(m.ragged); +} + +TEST_CASE("find_imex_mode - a missing sibling option is padding, not a failed lookup", "[IMEX]") { + // A profile old enough to predate a key, or a config assembled by hand. Absent is the + // limiting case of short, and must be answered the same way. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "copy" }, {}, {}); + + const ImexMode m = find_imex_mode(cfg, "copy"); + REQUIRE(m.found()); + CHECK(m.index == 1); + CHECK(m.active_tools.empty()); + CHECK(m.gcode.empty()); + CHECK(m.ragged); +} + +TEST_CASE("find_imex_mode - a config with no mode table finds nothing", "[IMEX]") { + // Every non-IMEX printer, and any caller that reaches the helper before the printer + // preset is loaded. Must answer not-found rather than dereference a null option. + const DynamicPrintConfig empty; + CHECK_FALSE(find_imex_mode(empty, "copy").found()); + CHECK_FALSE(find_imex_mode(empty, kImexPrimaryMode).found()); + CHECK(imex_mode_table(empty).empty()); + + // An empty names array is the same answer, even with siblings present. + const DynamicPrintConfig no_names = mode_cfg({}, { "0:P,1:C" }, { "COPY_SCRIPT" }); + CHECK_FALSE(find_imex_mode(no_names, "copy").found()); + CHECK(imex_mode_table(no_names).empty()); +} + +TEST_CASE("find_imex_mode - a duplicated mode name resolves to the first row", "[IMEX]") { + // The modes editor uniquifies names on entry, so duplicates only arrive from a + // hand-edited profile -- but the eight open-coded lookups this replaced disagreed + // about them: the ones that folded the bounds check into the match condition skipped + // a first row the tools array did not reach and silently took the second. First match + // wins, unconditionally, so the plate, the preview and the emitted G-code cannot pick + // different rows for the same name. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "copy", "copy" }, + { "0:P", "0:P,1:C", "0:P,1:M" }, + { "", "FIRST", "SECOND" }); + + const ImexMode m = find_imex_mode(cfg, "copy"); + REQUIRE(m.found()); + CHECK(m.index == 1); + CHECK(m.active_tools == "0:P,1:C"); + CHECK(m.gcode == "FIRST"); + + // Still the first row when the tools array is too short to cover it. This is the case + // where the old idioms diverged from each other. + const DynamicPrintConfig ragged = mode_cfg({ kImexPrimaryMode, "copy", "copy" }, + { "0:P" }, + { "", "FIRST", "SECOND" }); + const ImexMode rm = find_imex_mode(ragged, "copy"); + REQUIRE(rm.found()); + CHECK(rm.index == 1); + CHECK(rm.active_tools.empty()); + CHECK(rm.gcode == "FIRST"); + CHECK(rm.ragged); +} + +TEST_CASE("imex_mode_table - one row per name, in config order, padded the same way", "[IMEX]") { + // The roster view the modes editor and the plate's mode menu consume. Its size is the + // names array's size and nothing else's, or the editor would drop or invent rows when + // a profile's arrays disagree. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "copy", "mirror" }, + { "0:P", "0:P,1:C" }, + { "", "COPY_SCRIPT", "MIRROR_SCRIPT", "EXTRA" }); + + const std::vector<ImexMode> table = imex_mode_table(cfg); + REQUIRE(table.size() == 3); + + CHECK(table[0].index == 0); + CHECK(table[0].name == kImexPrimaryMode); + CHECK(table[0].active_tools == "0:P"); + CHECK_FALSE(table[0].ragged); + + CHECK(table[1].index == 1); + CHECK(table[1].name == "copy"); + CHECK(table[1].active_tools == "0:P,1:C"); + CHECK(table[1].gcode == "COPY_SCRIPT"); + CHECK_FALSE(table[1].ragged); + + // Past the end of the tools array: padded, flagged, and NOT dropped from the roster. + CHECK(table[2].index == 2); + CHECK(table[2].name == "mirror"); + CHECK(table[2].active_tools.empty()); + CHECK(table[2].gcode == "MIRROR_SCRIPT"); + CHECK(table[2].ragged); + + // A sibling array LONGER than the names array contributes no row: the names array is + // the roster, so the trailing "EXTRA" script belongs to no mode. + for (const ImexMode& m : table) + CHECK(m.gcode != "EXTRA"); +} + +TEST_CASE("imex_mode_table - every row agrees with find_imex_mode on that name", "[IMEX]") { + // The two entry points must not be able to drift: find_imex_mode is the hot path and + // does not build the table, so this pins them to the same answer. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "copy", "iq-copy" }, + { "0:P", "0:P,1:C" }, + { "", "COPY_SCRIPT" }); + + for (const ImexMode& row : imex_mode_table(cfg)) { + DYNAMIC_SECTION("row " << row.index << " (" << row.name << ")") { + const ImexMode found = find_imex_mode(cfg, row.name); + CHECK(found.index == row.index); + CHECK(found.active_tools == row.active_tools); + CHECK(found.gcode == row.gcode); + CHECK(found.ragged == row.ragged); + } + } +} + +// --------------------------------------------------------------------------- +// imex_resolve_routing — the one derivation shared by the hard block and the warning +// --------------------------------------------------------------------------- +// +// Print::validate() refuses a plate whose filaments do not route to the mode's declared +// primary; Plater's collect_imex_warnings() names that same primary's filament. Both used +// to re-derive the mode, its roster, the primary and the routing test for themselves, which +// is how they could describe the same plate differently. These pin the single derivation +// they now share, and in particular the physical/logical distinction that +// collect_imex_warnings got wrong once already. + +TEST_CASE("imex_resolve_routing - a primary mode derives nothing", "[IMEX]") { + // The reserved sentinel is "no parallel printing": no mode row is looked up, so no + // roster, no primary, and above all no block. Same for a plate that never carried a mode. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "copy" }, { "0:P", "0:P,1:C" }, { "", "S" }); + const auto pem = make_pem({0, 1}); + + for (const std::string& mode : { std::string(kImexPrimaryMode), std::string() }) { + DYNAMIC_SECTION("mode '" << mode << "'") { + const ImexRouting r = imex_resolve_routing(cfg, mode, { 1 }, pem); + CHECK_FALSE(r.parallel); + CHECK(r.active_tools.empty()); + CHECK(r.tools.empty()); + CHECK(r.primary_phys == -1); + CHECK(r.primary_logical == -1); + CHECK_FALSE(r.routes_to_primary()); + CHECK_FALSE(r.primary_unrouted); + CHECK(r.routed_heads.empty()); + } + } +} + +TEST_CASE("imex_resolve_routing - plain IDEX copy mode routes its single filament", "[IMEX]") { + // The ordinary case: two carriages, one logical filament each, the plate's object on + // filament 1. Nothing to warn about and nothing to block. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "copy" }, { "0:P", "0:P,1:C" }, { "", "S" }); + const ImexRouting r = imex_resolve_routing(cfg, "copy", { 1 }, make_pem({0, 1})); + + CHECK(r.parallel); + CHECK(r.active_tools == "0:P,1:C"); + REQUIRE(r.tools.size() == 2); + CHECK(r.tools[0].first == 0); + CHECK(r.tools[0].second == ImexRole::Primary); + CHECK(r.tools[1].first == 1); + CHECK(r.tools[1].second == ImexRole::Copy); + CHECK(r.primary_phys == 0); + CHECK(r.primary_logical == 0); + CHECK(r.routes_to_primary()); + CHECK_FALSE(r.primary_unrouted); + CHECK(r.routed_heads == std::vector<int>{0}); +} + +TEST_CASE("imex_resolve_routing - a plate whose filament misses the primary is unrouted", "[IMEX]") { + // The hard block's own case: IDEX copy mode declares T0 primary, but the object is + // assigned filament 2, which the map routes to T1. `primary_unrouted` is the whole + // condition Print::validate refuses on, and routed_heads is what names T1 in the message. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "copy" }, { "0:P", "0:P,1:C" }, { "", "S" }); + const ImexRouting r = imex_resolve_routing(cfg, "copy", { 2 }, make_pem({0, 1})); + + CHECK(r.primary_phys == 0); + CHECK(r.primary_logical == -1); + CHECK_FALSE(r.routes_to_primary()); + CHECK(r.primary_unrouted); + CHECK(r.routed_heads == std::vector<int>{1}); +} + +TEST_CASE("imex_resolve_routing - AFC manifold: primary is a PHYSICAL index, not a logical slot", "[IMEX]") { + // The index confusion collect_imex_warnings shipped with (fixed in fbc58d2a1d): the + // mode's tool numbers are PHYSICAL carriages, while filament presets and bed temps are + // indexed by LOGICAL slot, and on an AFC manifold the two diverge. Here logical slots + // 0-3 are four AFC lanes on physical T0; T1, T2, T3 are direct carriages fed by logical + // 4, 5, 6. + // + // The mode makes physical T1 the primary and the plate's object is on filament 5 + // (1-based) = logical slot 4. The routing must report slot 4. Reporting slot 1 -- the + // primary's own physical number read as a logical index -- is the bug: logical 1 is an + // AFC lane on T0, so the warning named a filament that is not on the primary at all. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "afc-copy" }, + { "0:P", "1:P,2:C,3:C" }, + { "", "S" }); + const auto pem = make_pem({0, 0, 0, 0, 1, 2, 3}); + const ImexRouting r = imex_resolve_routing(cfg, "afc-copy", { 5 }, pem); + + CHECK(r.primary_phys == 1); + CHECK(r.primary_logical == 4); + CHECK(r.primary_logical != r.primary_phys); + CHECK(r.routes_to_primary()); + CHECK_FALSE(r.primary_unrouted); + CHECK(r.routed_heads == std::vector<int>{1}); +} + +TEST_CASE("imex_resolve_routing - AFC manifold: an AFC lane does not satisfy a direct primary", "[IMEX]") { + // Same manifold, same mode, but the object is on filament 2 (logical slot 1), an AFC + // lane on physical T0. T1 is the declared primary and nothing reaches it, so the plate + // is unrouted -- which is precisely the answer a physical-as-logical read would have + // inverted, since logical slot 1 exists and would have looked like a hit. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "afc-copy" }, + { "0:P", "1:P,2:C,3:C" }, + { "", "S" }); + const ImexRouting r = imex_resolve_routing(cfg, "afc-copy", { 2 }, make_pem({0, 0, 0, 0, 1, 2, 3})); + + CHECK(r.primary_phys == 1); + CHECK(r.primary_logical == -1); + CHECK(r.primary_unrouted); + CHECK(r.routed_heads == std::vector<int>{0}); +} + +TEST_CASE("imex_resolve_routing - AFC manifold: any lane on the primary head satisfies it", "[IMEX]") { + // Four logical lanes share physical T0. With T0 primary, an object on any of them + // routes, and the first used slot wins -- the rule imex_primary_logical_from_objects + // documents, pinned here because the warning names the filament it picks. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "afc-copy" }, + { "0:P", "0:P,1:C,2:C,3:C" }, + { "", "S" }); + const auto pem = make_pem({0, 0, 0, 0, 1, 2, 3}); + + CHECK(imex_resolve_routing(cfg, "afc-copy", { 3 }, pem).primary_logical == 2); + CHECK(imex_resolve_routing(cfg, "afc-copy", { 4, 2 }, pem).primary_logical == 3); + CHECK(imex_resolve_routing(cfg, "afc-copy", { 5, 2 }, pem).primary_logical == 1); +} + +TEST_CASE("imex_resolve_routing - warning and block can never disagree about the primary", "[IMEX]") { + // The defining property of the extraction. Plater reads primary_logical to name a + // filament and Print::validate reads primary_unrouted to refuse the plate; they are two + // views of one value, so a plate is unrouted exactly when no slot was found. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "copy", "quad" }, + { "0:P", "0:P,1:C", "0:P,1:S,2:M,3:M" }, + { "", "S", "Q" }); + const std::vector<std::vector<int>> slot_sets = { {}, {1}, {2}, {3}, {1, 2}, {2, 3}, {4} }; + const std::vector<ConfigOptionInts> pems = { make_pem({0, 1}), make_pem({0, 0, 1, 2}), make_pem({1, 0}) }; + + for (const std::string& mode : { "copy", "quad" }) { + for (size_t s = 0; s < slot_sets.size(); ++s) { + for (size_t p = 0; p < pems.size(); ++p) { + DYNAMIC_SECTION(mode << " slots#" << s << " pem#" << p) { + const ImexRouting r = imex_resolve_routing(cfg, mode, slot_sets[s], pems[p]); + REQUIRE(r.primary_phys >= 0); + REQUIRE_FALSE(pems[p].values.empty()); + CHECK(r.primary_unrouted == !r.routes_to_primary()); + } + } + } + } +} + +TEST_CASE("imex_resolve_routing - an empty routing map is not an unrouted plate", "[IMEX]") { + // A printer that declares no physical_extruder_map has said nothing about where its + // filaments go, which is not the same claim as "they go somewhere other than the + // primary". Only the latter is an error, so this must not block. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "copy" }, { "0:P", "0:P,1:C" }, { "", "S" }); + const ImexRouting r = imex_resolve_routing(cfg, "copy", { 1 }, ConfigOptionInts{}); + + CHECK(r.primary_phys == 0); + CHECK(r.primary_logical == -1); + CHECK_FALSE(r.primary_unrouted); + CHECK(r.routed_heads.empty()); +} + +TEST_CASE("imex_resolve_routing - a mode with no primary marker never blocks", "[IMEX]") { + // A hand-edited roster that declares only copies. There is no primary to route to, so + // there is nothing to refuse -- the roster still parses, which is what the plater needs + // to decide it has fewer than two tools to compare. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "broken" }, { "0:P", "0:C,1:C" }, { "", "S" }); + const ImexRouting r = imex_resolve_routing(cfg, "broken", { 2 }, make_pem({0, 1})); + + CHECK(r.parallel); + CHECK(r.tools.size() == 2); + CHECK(r.primary_phys == -1); + CHECK(r.primary_logical == -1); + CHECK_FALSE(r.primary_unrouted); +} + +TEST_CASE("imex_resolve_routing - an unresolved or ragged mode yields an empty roster", "[IMEX]") { + // A plate whose mode was renamed or deleted in Printer Settings, and a profile whose + // active-tools array does not reach the named row. Both are "no tools, no primary, + // no block" -- the answer both call sites relied on the mode lookup for. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "copy", "ragged" }, + { "0:P", "0:P,1:C" }, + { "", "S", "R" }); + const auto pem = make_pem({0, 1}); + + for (const std::string& mode : { "copy-renamed", "ragged" }) { + DYNAMIC_SECTION("mode " << mode) { + const ImexRouting r = imex_resolve_routing(cfg, mode, { 2 }, pem); + CHECK(r.parallel); + CHECK(r.active_tools.empty()); + CHECK(r.tools.empty()); + CHECK(r.primary_phys == -1); + CHECK_FALSE(r.primary_unrouted); + } + } +} + +TEST_CASE("imex_resolve_routing - routed_heads is sorted, deduplicated and never clamps", "[IMEX]") { + // routed_heads is what the block's message lists as "this plate's filaments are on ...". + // Slots past the end of the map are DROPPED, not clamped: ConfigOption::get_at() clamps + // to values.front(), which would let the sentence name T0 -- the very head it just said + // nothing routes to. + const DynamicPrintConfig cfg = mode_cfg({ kImexPrimaryMode, "quad" }, + { "0:P", "0:P,1:C,2:C,3:C" }, + { "", "Q" }); + const auto pem = make_pem({0, 0, 1, 2}); + + // Slots 3 and 4 (logical 2, 3) reach T1 and T2; slot 2 (logical 1) reaches T0; slot 9 + // is past the map and contributes nothing. + const ImexRouting r = imex_resolve_routing(cfg, "quad", { 4, 2, 3, 9, 4 }, pem); + CHECK(r.routed_heads == std::vector<int>{0, 1, 2}); + + // Every used slot out of range: the message would otherwise read "on T0". + const ImexRouting all_out = imex_resolve_routing(cfg, "quad", { 9, 12 }, pem); + CHECK(all_out.routed_heads.empty()); + CHECK(all_out.primary_unrouted); +} From fcfda6c835beec3fcf30dd36e74d2242ac856865 Mon Sep 17 00:00:00 2001 From: Clifford Garwood <cliff@cigii.com> Date: Thu, 3 Sep 2026 00:55:04 -0400 Subject: [PATCH 33/51] Move the IMEX bed-zone geometry into libslic3r Closes review comment 16, and fixes three defects the move exposed. PartPlate::calc_imex_zones() was 392 lines deciding where every zone, collision strip and safety margin sits, in the GUI layer, with no test coverage. The three wxGetApp() calls that kept it there were all in its first 25 lines, fetching two configs. The geometry now lives in compute_imex_zone_layout(); the wrapper fetches the configs, calls it, and clips the returned rects to the bed outline for the GLModels, which is the only part needing GUI types. libslic3r gained no wx dependency: it takes DynamicPrintConfig directly, so the option lookups moved verbatim rather than through a hand-written value struct that could drift. The move is otherwise exact -- verified by a line-for-line diff of every arithmetic expression against the original, and by running 15 scenarios through the extracted code against hand-derived values. The only deletion is a lambda that was never called. Three fixes on top, each of which needed the code to be testable: - An off-grid or absent Primary left pri_col/pri_row at their (0,0) initialisers and built a layout from them, reporting the whole bed as the clear primary zone and the whole bed as a blocked mirror zone at once; under imex_firmware_managed_zones it shifted the slice by the bed centre. Guarding on the resolved primary head covers both routes. Reachable only from a hand-edited preset or a 3MF authored against another printer -- the editor pins Primary to tool 0 -- but that is the same class the unresolved-mode fallback handles. - imex_nozzle_clearance_x/y fell back to 0.0 where PrintConfig registers 30.0. Both strip loops are gated on the value being positive, so the fallback emitted no collision strips at all while the preview still drew 30 mm toolhead boxes. - The collision-strip loop asked each mirror head for its own grid cell, but an aggregated gantry's cell is pinned to the primary's column and expanded into a full-width row strip. Where the representative's column differed from the primary's, no boundary matched and the plate came back with no strips and no margin bands -- an object flush against the shared boundary sliced without a warning while the far carriage occupied it. Present since Span aggregation was added in 4966d0fae8 and carried out of PartPlate verbatim. The flags now come from the painted cells; an exhaustive sweep of the reachable grid, role and layout space (1,630,720 configurations) shows the only behaviour change is the missing strips appearing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/IMEXZones.cpp | 381 +++++++++++++++++++ src/libslic3r/IMEXZones.hpp | 93 +++++ tests/libslic3r/CMakeLists.txt | 1 + tests/libslic3r/test_imex_zones.cpp | 571 ++++++++++++++++++++++++++++ 5 files changed, 1048 insertions(+) create mode 100644 src/libslic3r/IMEXZones.cpp create mode 100644 src/libslic3r/IMEXZones.hpp create mode 100644 tests/libslic3r/test_imex_zones.cpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 59261a52e6..7d67d45b67 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -295,6 +295,8 @@ set(lisbslic3r_sources Geometry/VoronoiVisualUtils.hpp IMEXHelpers.cpp IMEXHelpers.hpp + IMEXZones.cpp + IMEXZones.hpp Int128.hpp KDTreeIndirect.hpp Layer.cpp diff --git a/src/libslic3r/IMEXZones.cpp b/src/libslic3r/IMEXZones.cpp new file mode 100644 index 0000000000..15c3fa140a --- /dev/null +++ b/src/libslic3r/IMEXZones.cpp @@ -0,0 +1,381 @@ +#include "libslic3r/IMEXZones.hpp" + +#include <algorithm> +#include <set> +#include <utility> + +#include "libslic3r/IMEXHelpers.hpp" + +namespace Slic3r { + +ImexZoneLayout compute_imex_zone_layout(const DynamicPrintConfig& printer_cfg, + const std::string& plate_mode, + const std::string& process_mode, + const BoundingBoxf& bed_extents) +{ + ImexZoneLayout out; + + auto* is_imex_opt = printer_cfg.option<ConfigOptionBool>("is_imex"); + if (!is_imex_opt || !is_imex_opt->value) + return out; + + // Per-plate mode takes priority over the process preset. + std::string active_mode = plate_mode; + if (active_mode == kImexPrimaryMode && !process_mode.empty()) + active_mode = process_mode; + if (active_mode == kImexPrimaryMode || active_mode.empty()) + return out; + + // Grid dimensions and tool layout from printer config + auto* gantry_opt = printer_cfg.option<ConfigOptionInt>("imex_gantry_count"); + auto* tpg_opt = printer_cfg.option<ConfigOptionInt>("imex_tools_per_gantry"); + auto* layout_opt = printer_cfg.option<ConfigOptionEnum<ImexToolLayout>>("imex_tool_layout"); + + int n_cols = tpg_opt ? std::max(1, tpg_opt->value) : 2; + int n_rows = gantry_opt ? std::max(1, gantry_opt->value) : 1; + + // Which corner is T0? flip_x: col 0 is right(max-X); flip_y: row 0 is rear(max-Y) + const ImexToolLayout layout = layout_opt ? layout_opt->value : ImexToolLayout::FrontLeft; + bool flip_x = (layout == ImexToolLayout::FrontRight || layout == ImexToolLayout::RearRight); + bool flip_y = (layout == ImexToolLayout::RearLeft || layout == ImexToolLayout::RearRight); + + // Convert tool index to physical (col=X-index, row=Y-index), col/row 0 = min-X/min-Y + auto tool_to_phys = [&](int idx) -> std::pair<int,int> { + int raw_col = idx % n_cols, raw_row = idx / n_cols; + return { flip_x ? (n_cols - 1 - raw_col) : raw_col, + flip_y ? (n_rows - 1 - raw_row) : raw_row }; + }; + + int pri_col = 0, pri_row = 0; + + if (n_cols == 1 && n_rows == 1) + return out; // nothing to dim with a single zone + + // Look up secondary tool indices (active in mode, but NOT the primary tool). + // An unresolved mode, and a mode whose row the tools array does not reach, both come + // back as an empty string; the zone_roles guard below then returns an empty layout. + const std::string active_tools_str = find_imex_mode(printer_cfg, active_mode).active_tools; + + // Which heads own a zone cell, and in what role. Roles carry through from + // parse_imex_active_tools() rather than being flattened into small ints, so the + // classification below is a comparison the compiler checks and a new role cannot slip + // through as an unhandled number. + // + // imex_primary_tool_for_mode handles the Primary slot (it owns the bare-legacy-token → + // Primary rule); parse_imex_active_tools fills in the Copy/Mirror secondaries. Mode + // strings use physical T-indices directly; filament routing is separate + // (imex_head_filament_map). + // + // Only Primary / Copy / Mirror land in this map. A Span head shares the primary's zone + // instead of owning one, so it deliberately gets no entry (and hence no zone centre -- + // see ImexZoneLayout::head_zone_centers), and an extra Primary entry beyond the first is + // ignored. Any further role must decide here whether it owns a cell. + std::map<int, ImexRole> zone_roles; + { + const int primary = imex_primary_tool_for_mode(active_tools_str); + if (primary >= 0 && primary < n_rows * n_cols) + zone_roles[primary] = ImexRole::Primary; + for (const auto& [phys_idx, role] : parse_imex_active_tools(active_tools_str)) { + if (phys_idx < 0 || phys_idx >= n_rows * n_cols) continue; + if (phys_idx == primary) continue; + // Exhaustive on purpose, with no default: a role added to the enum has to answer + // "does this own a zone cell?" here, and -Wswitch asks the question at compile + // time instead of letting the head silently vanish from the layout. + switch (role) { + case ImexRole::Copy: + case ImexRole::Mirror: + zone_roles[phys_idx] = role; + break; + case ImexRole::Primary: // an extra Primary beyond the first is ignored + case ImexRole::Span: // shares the primary's zone rather than owning one + break; + } + } + } + + // If the mode name was found but has no tools (e.g. stale process-preset mode on a new + // printer that has no modes defined yet), there is nothing to compute. + if (zone_roles.empty()) + return out; + + // Identify the Primary tool from the mode definition + for (const auto& [idx, role] : zone_roles) { + if (role == ImexRole::Primary) { auto [c, r] = tool_to_phys(idx); pri_col = c; pri_row = r; + out.primary_head = idx; break; } + } + + // No Primary landed inside the grid. Either the mode declares none at all, or its `:P` + // index is off-grid: the modes editor deliberately preserves tool assignments across + // imex_gantry_count changes, so a mode authored on a 4-tool IQEX with Primary on T3 keeps + // that assignment when the printer is reconfigured as a 2-tool IDEX, and the + // `primary < n_rows * n_cols` bound above then drops it from zone_roles. + // + // Every zone, strip, ghost centre and slice offset below is derived from pri_col/pri_row, + // which would still be sitting at their (0,0) initialisers — a position no active tool + // occupies. That yields a primary zone and a secondary zone that both claim the whole bed: + // imex_primary_zone() reports the plate clear while the blocking boxes report it full, and + // under imex_firmware_managed_zones compute_imex_slice_offset() shifts the slice by the bed + // centre. Degrade to "this plate has no IMEX zones" instead — the same answer the earlier + // early returns give, and the one every consumer already handles. + if (out.primary_head < 0) + return ImexZoneLayout{}; + + // Per-gantry grouping drives Span-based aggregation. When the mode declares a + // Span partner on primary's gantry, non-primary gantries with multiple same-role + // tools collapse to one cell each (placed at primary's column so has_col_sep + // stays false and make_boxes expands the cell into a full-X row-strip). + // Mixed-role / single-tool / no-Span configurations keep per-tool cells. + const ImexGantryGrouping grouping = + group_imex_active_tools_by_gantry(active_tools_str, n_cols); + std::map<int, const ImexGantryGroup*> group_by_gantry; + for (const auto& grp : grouping.groups) + group_by_gantry[grp.gantry_index] = &grp; + + // Separate copy and mirror secondary cells using physical coordinates + std::set<std::pair<int,int>> copy_cells, mirror_cells; + for (const auto& [idx, role] : zone_roles) { + if (role == ImexRole::Primary) continue; // primary handled separately + + const int phys_gantry = idx / n_cols; + auto git = group_by_gantry.find(phys_gantry); + const ImexGantryGroup* grp = (git == group_by_gantry.end()) ? nullptr : git->second; + + if (grp && grp->aggregate) { + // Only the representative contributes a cell; non-reps are folded into + // the same row-strip and skipped entirely. + if (idx != grp->representative_phys) continue; + auto [rep_c, r] = tool_to_phys(idx); + (void)rep_c; // intentionally discarded — aggregated cell pins to pri_col + if (role == ImexRole::Copy) copy_cells.insert({pri_col, r}); + else if (role == ImexRole::Mirror) mirror_cells.insert({pri_col, r}); + } else { + auto [c, r] = tool_to_phys(idx); + if (role == ImexRole::Copy) copy_cells.insert({c, r}); + else if (role == ImexRole::Mirror) mirror_cells.insert({c, r}); + } + } + + // All active secondary cells combined (for separation axis computation) + std::set<std::pair<int,int>> all_secondary; + for (auto& p : copy_cells) all_secondary.insert(p); + for (auto& p : mirror_cells) all_secondary.insert(p); + + double x_min = bed_extents.min(0), x_max = bed_extents.max(0); + double y_min = bed_extents.min(1), y_max = bed_extents.max(1); + + // Zone sizing is based on ACTIVE tool count per axis, not total grid dimensions. + // Inactive tools (absent from zone_roles) donate their bed share to active neighbors. + // Sorted active col/row lists map physical index k → zone index k. + std::vector<int> active_cols_v, active_rows_v; + { + std::set<int> ac_set, ar_set; + for (const auto& [idx, role] : zone_roles) { + auto [c, r] = tool_to_phys(idx); + ac_set.insert(c); ar_set.insert(r); + } + active_cols_v.assign(ac_set.begin(), ac_set.end()); // sorted ascending + active_rows_v.assign(ar_set.begin(), ar_set.end()); + } + int n_active_cols = std::max(1, (int)active_cols_v.size()); + int n_active_rows = std::max(1, (int)active_rows_v.size()); + + std::map<int,int> col_to_zone, row_to_zone; + for (int k = 0; k < n_active_cols; ++k) col_to_zone[active_cols_v[k]] = k; + for (int k = 0; k < n_active_rows; ++k) row_to_zone[active_rows_v[k]] = k; + + double zone_w = (x_max - x_min) / n_active_cols; + double zone_h = (y_max - y_min) / n_active_rows; + + // Zone index of the primary tool + int pri_col_k = col_to_zone.count(pri_col) ? col_to_zone[pri_col] : 0; + int pri_row_k = row_to_zone.count(pri_row) ? row_to_zone[pri_row] : 0; + + // Zone center per physical head — ghost placement consumes this so that + // ghosts land in their own secondary zone instead of stacking on primary. + // Every active tool (including primary) gets an entry; ghost offset math is + // simply center[head] - center[primary]. + for (const auto& [idx, role] : zone_roles) { + auto [c, r] = tool_to_phys(idx); + int ck = col_to_zone.count(c) ? col_to_zone.at(c) : 0; + int rk = row_to_zone.count(r) ? row_to_zone.at(r) : 0; + out.head_zone_centers[idx] = Vec2d( + x_min + (ck + 0.5) * zone_w, + y_min + (rk + 0.5) * zone_h); + } + + // Separation axes: row-sep = secondaries on a different gantry, col-sep = different column + bool has_row_sep = false, has_col_sep = false; + for (const auto& [sc, sr] : all_secondary) { + if (sr != pri_row) has_row_sep = true; + if (sc != pri_col) has_col_sep = true; + } + + // Build expanded zone rects for a set of cells. + // When secondaries share only a row difference (same column as primary) → expand to full X width. + // When secondaries share only a column difference → expand to full Y height. + // When both axes differ → per-quadrant. + auto make_boxes = [&](const std::set<std::pair<int,int>>& cells) -> std::vector<BoundingBoxf> { + std::vector<BoundingBoxf> boxes; + if (cells.empty()) return boxes; + auto ck = [&](int c) { return col_to_zone.count(c) ? col_to_zone.at(c) : 0; }; + auto rk = [&](int r) { return row_to_zone.count(r) ? row_to_zone.at(r) : 0; }; + if (has_row_sep && !has_col_sep) { + std::set<int> rows; for (auto& [c,r] : cells) rows.insert(r); + for (int sr : rows) { + int k = rk(sr); + boxes.emplace_back(Vec2d(x_min, y_min + k*zone_h), Vec2d(x_max, y_min + (k+1)*zone_h)); + } + } else if (has_col_sep && !has_row_sep) { + std::set<int> cols; for (auto& [c,r] : cells) cols.insert(c); + for (int sc : cols) { + int k = ck(sc); + boxes.emplace_back(Vec2d(x_min + k*zone_w, y_min), Vec2d(x_min + (k+1)*zone_w, y_max)); + } + } else { + for (auto& [sc,sr] : cells) { + int ck_ = ck(sc), rk_ = rk(sr); + boxes.emplace_back(Vec2d(x_min + ck_*zone_w, y_min + rk_*zone_h), + Vec2d(x_min + (ck_+1)*zone_w, y_min + (rk_+1)*zone_h)); + } + } + return boxes; + }; + + out.copy_zones = make_boxes(copy_cells); + out.mirror_zones = make_boxes(mirror_cells); + + // --- Secondary zone blocking --- + // The expanded bounding boxes for all secondary (copy+mirror) zones. check_outside() + // uses these to prevent objects being placed outside the primary zone. + auto push_secondary_box = [&](const std::vector<BoundingBoxf>& boxes) { + for (const auto& b : boxes) + out.secondary_zone_boxes.emplace_back(Vec3d(b.min.x(), b.min.y(), -1.0), + Vec3d(b.max.x(), b.max.y(), 1e4)); + }; + push_secondary_box(out.copy_zones); + push_secondary_box(out.mirror_zones); + + // --- Carriage collision danger strips --- + // Only add strips at boundaries of the PRIMARY zone — objects are only placed in the + // primary zone, so secondary-to-secondary boundaries have no relevance. + // + // Strip width is the literal nozzle clearance value on the primary side only: + // right X boundary: [bnd_x - nozzle_clearance_x, bnd_x] + // left X boundary: [bnd_x, bnd_x + nozzle_clearance_x] + // top Y boundary: [bnd_y - nozzle_clearance_y, bnd_y] + // bottom Y boundary:[bnd_y, bnd_y + nozzle_clearance_y] + // + // Strip length matches the primary zone extent (same expansion logic as make_boxes): + // !has_row_sep → full bed height; has_row_sep → primary row only + // !has_col_sep → full bed width; has_col_sep → primary column only + + auto* cw_opt = printer_cfg.option<ConfigOptionFloat>("imex_nozzle_clearance_x"); + auto* ch_opt = printer_cfg.option<ConfigOptionFloat>("imex_nozzle_clearance_y"); + auto* mgn_opt = printer_cfg.option<ConfigOptionFloat>("imex_carriage_margin"); + // Fallbacks mirror the values registered in PrintConfig.cpp: 30.0 for both clearances + // (6664, 6672), 0.0 for the margin (6680). The clearances must NOT fall back to 0.0 -- + // both strip loops below are gated on `carriage_w > 0.0` / `carriage_h > 0.0`, so a zero + // would silently emit no collision strips at all while the preview still draws 30 mm + // toolhead boxes. A config built from the ConfigDef always carries these; a partial or + // hand-built one is the only way to reach the fallback. + double carriage_w = cw_opt ? cw_opt->value : 30.0; + double carriage_h = ch_opt ? ch_opt->value : 30.0; + double margin = mgn_opt ? mgn_opt->value : 0.0; + + // Primary zone extent (the clear printable area): + // row-sep only → full bed width × primary row's Y band + // col-sep only → primary col's X band × full bed height + // both → primary quadrant + // Uses zone indices so inactive tools don't shrink the zone. + double pz_x0 = has_col_sep ? x_min + pri_col_k * zone_w : x_min; + double pz_x1 = has_col_sep ? x_min + (pri_col_k + 1) * zone_w : x_max; + double pz_y0 = has_row_sep ? y_min + pri_row_k * zone_h : y_min; + double pz_y1 = has_row_sep ? y_min + (pri_row_k + 1) * zone_h : y_max; + out.primary_zone_box = BoundingBoxf(Vec2d(pz_x0, pz_y0), Vec2d(pz_x1, pz_y1)); + + auto add_strip = [&](double sx0, double sx1, double sy0, double sy1) { + out.collision_zones.emplace_back(Vec3d(sx0, sy0, -1.0), Vec3d(sx1, sy1, 1e4)); + }; + auto add_margin_band = [&](double sx0, double sx1, double sy0, double sy1) { + out.margin_bands.emplace_back(Vec2d(sx0, sy0), Vec2d(sx1, sy1)); + }; + + // Determine which directions have mirror secondaries adjacent to the primary. + // Only mirror tools can cause carriage collisions — they move toward each other. + // Copy tools always move in the same direction, so no collision strip is needed. + // + // Driven by `mirror_cells`, not by zone_roles: on an AGGREGATED gantry the cell is + // pinned to the primary's column and make_boxes then expands it into a full-width row + // strip, so the painted zone — not any one head's own cell — is what the primary's + // carriage can meet. Reading each head's own cell instead lost the strip whenever the + // representative's column differed from the primary's: at tpg=3, gantry_count=2, mode + // "0:P,1:S,4:M,5:M" the rear gantry paints a full-width mirror strip against the + // primary's rear boundary, yet neither T4 (col 1) nor T5 (col 2) is in the primary's + // column, so no strip and no margin band were emitted at all. + // + // Both axes require zone-adjacent AND same row/column on the OTHER axis: a mirror + // diagonally offset from primary (different row AND different column) can't collide + // with primary's carriage on either axis since the gantries don't overlap there. + // Without these checks, paired-gantry mc-mirror (`0:P,1:S,2:M,3:M`) would draw a + // spurious right-edge strip from T3 even though T3 lives on the other gantry's row. + // + // The adjacency tests (±1) are in ZONE indices so an inactive column or row between + // two active ones cannot hide the boundary they really share (see "inactive tools + // donate their bed share"), while the co-linearity test on the other axis stays in + // physical indices. The two forms agree for any cell that owns a zone — col_to_zone + // and row_to_zone are order-preserving bijections over exactly the active indices — + // so this is one rule written two ways, not two rules. + bool has_right_sec = false, has_left_sec = false; + bool has_top_sec = false, has_bottom_sec = false; + for (const auto& [sc, sr] : mirror_cells) { + int zc = col_to_zone.count(sc) ? col_to_zone.at(sc) : -1; + int zr = row_to_zone.count(sr) ? row_to_zone.at(sr) : -1; + if (zc < 0 || zr < 0) continue; // no zone of its own, so no boundary with primary + // X-boundary strips: mirror zone-adjacent in X, same physical row as primary. + if (zr == pri_row_k && zc == pri_col_k + 1) has_right_sec = true; + if (zr == pri_row_k && zc == pri_col_k - 1) has_left_sec = true; + // Y-boundary strips: mirror zone-adjacent in Y, same physical column as primary. + if (zr == pri_row_k + 1 && sc == pri_col) has_top_sec = true; + if (zr == pri_row_k - 1 && sc == pri_col) has_bottom_sec = true; + } + + // X-axis boundaries (vertical strips, width = nozzle_clearance_x on primary side) + if (carriage_w > 0.0) { + if (has_right_sec) { + double bnd_x = x_min + (pri_col_k + 1) * zone_w; + double strip_inner = bnd_x - carriage_w; + add_strip(strip_inner, bnd_x, pz_y0, pz_y1); + if (margin > 0.0) + add_margin_band(strip_inner - margin, strip_inner, pz_y0, pz_y1); + } + if (has_left_sec) { + double bnd_x = x_min + pri_col_k * zone_w; + double strip_inner = bnd_x + carriage_w; + add_strip(bnd_x, strip_inner, pz_y0, pz_y1); + if (margin > 0.0) + add_margin_band(strip_inner, strip_inner + margin, pz_y0, pz_y1); + } + } + + // Y-axis boundaries (horizontal strips, width = nozzle_clearance_y on primary side) + if (carriage_h > 0.0) { + if (has_top_sec) { + double bnd_y = y_min + (pri_row_k + 1) * zone_h; + double strip_inner = bnd_y - carriage_h; + add_strip(pz_x0, pz_x1, strip_inner, bnd_y); + if (margin > 0.0) + add_margin_band(pz_x0, pz_x1, strip_inner - margin, strip_inner); + } + if (has_bottom_sec) { + double bnd_y = y_min + pri_row_k * zone_h; + double strip_inner = bnd_y + carriage_h; + add_strip(pz_x0, pz_x1, bnd_y, strip_inner); + if (margin > 0.0) + add_margin_band(pz_x0, pz_x1, strip_inner, strip_inner + margin); + } + } + + return out; +} + +} // namespace Slic3r diff --git a/src/libslic3r/IMEXZones.hpp b/src/libslic3r/IMEXZones.hpp new file mode 100644 index 0000000000..d0c0e29912 --- /dev/null +++ b/src/libslic3r/IMEXZones.hpp @@ -0,0 +1,93 @@ +#pragma once + +#include <map> +#include <optional> +#include <string> +#include <vector> + +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/PrintConfig.hpp" + +namespace Slic3r { + +// Where every IMEX bed zone, carriage collision strip and advisory margin band sits, in +// plate-local millimetres. Purely geometric: no rendering, no clipping against the bed +// outline, no GUI types. PartPlate turns the rectangles into GLModels (clipping each one +// to the bed polygon as it goes) and copies the boxes straight into the members that +// check_outside() consults, so this struct is the whole answer to "which boxes". +// +// Every list is empty and `primary_zone_box` unset when no parallel mode is in effect — +// IMEX off, Primary mode, a 1x1 tool grid, a mode whose tool roster is empty, or a mode +// whose Primary tool is not on the current grid (no `:P` marker, or a `:P` index left +// over from a wider grid). The whole layout hangs off the primary's cell, so without one +// there is nothing to divide and consumers must see the same "no zones" answer. +struct ImexZoneLayout +{ + // Physical T-index of the active mode's Primary tool; -1 when the layout is empty. + int primary_head = -1; + + // Physical head -> XY centre of that head's zone. One entry per tool the mode makes + // active, Primary included. A Span tool has no entry: it shares the primary's zone + // rather than owning one. Ghost placement offsets by centre[head] - centre[primary]. + // + // EXCEPTION, read before using the X component. These centres are built from the head's + // OWN grid cell, but an AGGREGATED representative's zone rectangle is pinned to the + // primary's column and then expanded to a full-width row strip. So for an aggregated head + // whose own column differs from the primary's, centre[head].x names a column its painted + // zone does not have, and `centre[head] - centre[primary]` carries a bogus X offset. + // Reachable at imex_tools_per_gantry >= 3 when the primary-column tool on the aggregated + // gantry is inactive (e.g. tpg=3, gantry_count=2, mode "0:P,1:S,4:M,5:M"). + // Both current consumers pin X to the primary's centre for aggregated heads -- + // PartPlate::calc_imex_ghosts() via bed_x_center, GCodeViewer via sec_center_of() -- and a + // new consumer must do the same until this is either pinned here or the aggregate flag is + // exposed on the layout. + std::map<int, Vec2d> head_zone_centers; + + // The clear printable area — the primary tool's zone. Objects go here and nowhere else. + std::optional<BoundingBoxf> primary_zone_box; + + // Copy / Mirror zone rectangles, already expanded along whichever axis carries no + // separation: secondaries differing from primary only by row give full-bed-width + // strips, only by column give full-bed-height strips, and differing on both axes give + // per-tool quadrants. + std::vector<BoundingBoxf> copy_zones; + std::vector<BoundingBoxf> mirror_zones; + + // `copy_zones` followed by `mirror_zones`, as full-height boxes for the placement + // check. An object overlapping one of these is outside the primary zone. + std::vector<BoundingBoxf3> secondary_zone_boxes; + + // Carriage danger strips lying just inside the primary zone's boundary, one per + // boundary that faces an adjacent Mirror ZONE -- an aggregated gantry contributes the + // one pinned zone it paints, not one per head -- in right / left / top / bottom order. + // Width is the literal nozzle clearance for that axis. Copy tools never contribute: + // they travel in the same direction as the primary and cannot close on it. + std::vector<BoundingBoxf3> collision_zones; + + // Advisory (non-blocking) bands immediately inside each collision strip, present only + // when imex_carriage_margin > 0. Same boundary order as `collision_zones`. + std::vector<BoundingBoxf> margin_bands; +}; + +// Computes the IMEX zone layout for one plate. +// +// `printer_cfg` — the edited printer preset's config. Read for is_imex, the tool grid +// (imex_gantry_count / imex_tools_per_gantry / imex_tool_layout), the +// mode roster (imex_mode_names / imex_mode_active_tools) and the strip +// widths (imex_nozzle_clearance_x / _y, imex_carriage_margin). A missing +// option falls back to the same default the caller would have seen. +// `plate_mode` — the plate's own IMEX mode. Wins over the process preset unless it is +// `kImexPrimaryMode`. +// `process_mode` — the process preset's `imex_parallel_mode`, used only as the fallback +// when `plate_mode` is `kImexPrimaryMode`. Pass "" when unavailable. +// `bed_extents` — XY extents of the plate shape, in plate-local mm. Zones subdivide it. +// +// Zone sizing keys off the count of ACTIVE tools per axis rather than the grid dimensions, +// so a tool the mode leaves out donates its share of the bed to its active neighbours. +ImexZoneLayout compute_imex_zone_layout(const DynamicPrintConfig& printer_cfg, + const std::string& plate_mode, + const std::string& process_mode, + const BoundingBoxf& bed_extents); + +} // namespace Slic3r diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index f67316980a..5763b64dd5 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -24,6 +24,7 @@ add_executable(${_TEST_NAME}_tests test_fill_plane_path.cpp test_geometry.cpp test_imex_helpers.cpp + test_imex_zones.cpp test_multimaterial_segmentation.cpp test_placeholder_parser.cpp test_polygon.cpp diff --git a/tests/libslic3r/test_imex_zones.cpp b/tests/libslic3r/test_imex_zones.cpp new file mode 100644 index 0000000000..4946afc27a --- /dev/null +++ b/tests/libslic3r/test_imex_zones.cpp @@ -0,0 +1,571 @@ +#include <catch2/catch_all.hpp> + +#include <string> +#include <vector> + +#include "libslic3r/IMEXHelpers.hpp" +#include "libslic3r/IMEXZones.hpp" +#include "libslic3r/PrintConfig.hpp" + +using namespace Slic3r; +using Catch::Matchers::WithinAbs; + +namespace { + +// A square 200x200 bed keeps every expected coordinate an exact round number, so a +// failure reports a wrong decision rather than a rounding difference. +const BoundingBoxf kBed{ Vec2d(0.0, 0.0), Vec2d(200.0, 200.0) }; + +constexpr const char* kMode = "parallel"; + +struct PrinterCfg +{ + int gantry_count = 1; + int tools_per_gantry = 2; + ImexToolLayout tool_layout = ImexToolLayout::FrontLeft; + std::string active_tools; // the imex_mode_active_tools entry for kMode + double clearance_x = 0.0; + double clearance_y = 0.0; + double margin = 0.0; + bool is_imex = true; +}; + +// Builds the subset of the printer preset compute_imex_zone_layout actually reads. Every +// key is set explicitly so no assertion below depends on a PrintConfig default. +DynamicPrintConfig make_cfg(const PrinterCfg& p) +{ + DynamicPrintConfig cfg; + cfg.set_key_value("is_imex", new ConfigOptionBool(p.is_imex)); + cfg.set_key_value("imex_gantry_count", new ConfigOptionInt(p.gantry_count)); + cfg.set_key_value("imex_tools_per_gantry", new ConfigOptionInt(p.tools_per_gantry)); + cfg.set_key_value("imex_tool_layout", new ConfigOptionEnum<ImexToolLayout>(p.tool_layout)); + // Slot 0 is the reserved Primary mode, which never carries tools; kMode is slot 1. + cfg.set_key_value("imex_mode_names", + new ConfigOptionStrings(std::vector<std::string>{ kImexPrimaryMode, kMode })); + cfg.set_key_value("imex_mode_active_tools", + new ConfigOptionStrings(std::vector<std::string>{ std::string(), p.active_tools })); + cfg.set_key_value("imex_nozzle_clearance_x", new ConfigOptionFloat(p.clearance_x)); + cfg.set_key_value("imex_nozzle_clearance_y", new ConfigOptionFloat(p.clearance_y)); + cfg.set_key_value("imex_carriage_margin", new ConfigOptionFloat(p.margin)); + return cfg; +} + +ImexZoneLayout layout_for(const PrinterCfg& p, + const std::string& plate_mode = kMode, + const std::string& process_mode = std::string()) +{ + return compute_imex_zone_layout(make_cfg(p), plate_mode, process_mode, kBed); +} + +void check_rect(const BoundingBoxf& b, double x0, double y0, double x1, double y1) +{ + CHECK_THAT(b.min.x(), WithinAbs(x0, 1e-9)); + CHECK_THAT(b.min.y(), WithinAbs(y0, 1e-9)); + CHECK_THAT(b.max.x(), WithinAbs(x1, 1e-9)); + CHECK_THAT(b.max.y(), WithinAbs(y1, 1e-9)); +} + +void check_box_xy(const BoundingBoxf3& b, double x0, double y0, double x1, double y1) +{ + CHECK_THAT(b.min.x(), WithinAbs(x0, 1e-9)); + CHECK_THAT(b.min.y(), WithinAbs(y0, 1e-9)); + CHECK_THAT(b.max.x(), WithinAbs(x1, 1e-9)); + CHECK_THAT(b.max.y(), WithinAbs(y1, 1e-9)); +} + +void check_point(const Vec2d& p, double x, double y) +{ + CHECK_THAT(p.x(), WithinAbs(x, 1e-9)); + CHECK_THAT(p.y(), WithinAbs(y, 1e-9)); +} + +bool is_empty(const ImexZoneLayout& l) +{ + return l.primary_head == -1 + && !l.primary_zone_box.has_value() + && l.head_zone_centers.empty() + && l.copy_zones.empty() + && l.mirror_zones.empty() + && l.secondary_zone_boxes.empty() + && l.collision_zones.empty() + && l.margin_bands.empty(); +} + +} // namespace + +// D1 regression: both strip loops are gated on `carriage_w > 0.0`, so a clearance fallback of +// 0.0 would emit no collision strips at all -- the geometry that keeps two carriages from +// meeting -- while the preview still drew 30 mm toolhead boxes. The fallback must match the +// value registered in PrintConfig.cpp (30.0), not zero. +// +// So the strip's WIDTH is the claim, not its existence: a fallback of 0.1 would leave the zone +// list non-empty and the carriages a nozzle's width apart. 1 gantry x 2 tools on the 200mm bed +// puts the column boundary at x = 100, and the strip lies one clearance inside the primary's +// column, so the registered 30.0 is the rectangle x [70, 100] over the primary's full depth. +TEST_CASE("a config missing the nozzle clearance keys falls back to the registered clearance", + "[IMEXZones]") +{ + // Deliberately NOT via make_cfg(): the point is a config that never carries the keys. + // imex_tool_layout is left out too, so the layout falls back to FrontLeft and T0 owns the + // left column -- the same corner every other case in this file starts from. + DynamicPrintConfig cfg; + cfg.set_key_value("is_imex", new ConfigOptionBool(true)); + cfg.set_key_value("imex_gantry_count", new ConfigOptionInt(1)); + cfg.set_key_value("imex_tools_per_gantry", new ConfigOptionInt(2)); + cfg.set_key_value("imex_mode_names", new ConfigOptionStrings({ kMode })); + cfg.set_key_value("imex_mode_active_tools", new ConfigOptionStrings({ "0:P,1:M" })); + + const ImexZoneLayout l = compute_imex_zone_layout(cfg, kMode, std::string(), kBed); + + REQUIRE(l.primary_head == 0); + REQUIRE(l.primary_zone_box.has_value()); + check_rect(*l.primary_zone_box, 0.0, 0.0, 100.0, 200.0); + + // One X boundary, one strip, 30mm wide against it. + REQUIRE(l.collision_zones.size() == 1); + check_box_xy(l.collision_zones[0], 70.0, 0.0, 100.0, 200.0); + + // The margin's own fallback is 0.0, and a zero margin raises no band. + CHECK(l.margin_bands.empty()); +} + +TEST_CASE("an IDEX mirror pair splits the bed into two columns", "[IMEXZones]") +{ + // 1 gantry x 2 tools: the classic IDEX case. T1 mirrors T0, so the split is on X and + // the boundary between the two zones carries a carriage danger strip. + PrinterCfg p; + p.gantry_count = 1; + p.tools_per_gantry = 2; + p.active_tools = "0:P,1:M"; + p.clearance_x = 5.0; + p.margin = 2.0; + + const ImexZoneLayout l = layout_for(p); + + REQUIRE(l.primary_head == 0); + REQUIRE(l.primary_zone_box.has_value()); + check_rect(*l.primary_zone_box, 0.0, 0.0, 100.0, 200.0); + + CHECK(l.copy_zones.empty()); + REQUIRE(l.mirror_zones.size() == 1); + check_rect(l.mirror_zones[0], 100.0, 0.0, 200.0, 200.0); + + // Both heads get a zone centre; the ghost offset is the difference between them. + REQUIRE(l.head_zone_centers.size() == 2); + check_point(l.head_zone_centers.at(0), 50.0, 100.0); + check_point(l.head_zone_centers.at(1), 150.0, 100.0); + + // The mirror zone is off limits to objects, over the full Z range. + REQUIRE(l.secondary_zone_boxes.size() == 1); + check_box_xy(l.secondary_zone_boxes[0], 100.0, 0.0, 200.0, 200.0); + CHECK_THAT(l.secondary_zone_boxes[0].min.z(), WithinAbs(-1.0, 1e-9)); + CHECK(l.secondary_zone_boxes[0].max.z() > 1000.0); + + // Danger strip sits inside the primary zone, against the boundary, one clearance wide. + REQUIRE(l.collision_zones.size() == 1); + check_box_xy(l.collision_zones[0], 95.0, 0.0, 100.0, 200.0); + + // The advisory margin band abuts the strip on the primary side, one margin wide. + REQUIRE(l.margin_bands.size() == 1); + check_rect(l.margin_bands[0], 93.0, 0.0, 95.0, 200.0); +} + +TEST_CASE("a copy secondary claims a zone but raises no collision strip", "[IMEXZones]") +{ + // Copy tools travel in the same direction as the primary and can never close on it, + // so the shared boundary needs no danger strip -- only mirrors do. + PrinterCfg p; + p.gantry_count = 1; + p.tools_per_gantry = 2; + p.active_tools = "0:P,1:C"; + p.clearance_x = 5.0; + p.margin = 2.0; + + const ImexZoneLayout l = layout_for(p); + + REQUIRE(l.copy_zones.size() == 1); + check_rect(l.copy_zones[0], 100.0, 0.0, 200.0, 200.0); + CHECK(l.mirror_zones.empty()); + CHECK(l.secondary_zone_boxes.size() == 1); + CHECK(l.collision_zones.empty()); + CHECK(l.margin_bands.empty()); +} + +TEST_CASE("the tool layout decides which corner the primary zone occupies", "[IMEXZones]") +{ + // imex_tool_layout names the bed corner T0 sits in. With all four tools of a 2x2 IQEX + // active the bed splits into quadrants, so the primary quadrant is a direct readout of + // how tool indices were mapped onto columns and rows. + struct Case { ImexToolLayout layout; const char* name; double x0, y0, x1, y1; }; + const Case cases[] = { + { ImexToolLayout::FrontLeft, "FrontLeft", 0.0, 0.0, 100.0, 100.0 }, + { ImexToolLayout::FrontRight, "FrontRight", 100.0, 0.0, 200.0, 100.0 }, + { ImexToolLayout::RearLeft, "RearLeft", 0.0, 100.0, 100.0, 200.0 }, + { ImexToolLayout::RearRight, "RearRight", 100.0, 100.0, 200.0, 200.0 }, + }; + + for (const Case& c : cases) { + DYNAMIC_SECTION(c.name) { + PrinterCfg p; + p.gantry_count = 2; + p.tools_per_gantry = 2; + p.tool_layout = c.layout; + p.active_tools = "0:P,1:C,2:M,3:M"; + + const ImexZoneLayout l = layout_for(p); + + REQUIRE(l.primary_zone_box.has_value()); + check_rect(*l.primary_zone_box, c.x0, c.y0, c.x1, c.y1); + // The primary's zone centre must agree with its zone. + REQUIRE(l.head_zone_centers.count(0) == 1); + check_point(l.head_zone_centers.at(0), 0.5 * (c.x0 + c.x1), 0.5 * (c.y0 + c.y1)); + // Three secondaries, each with its own quadrant. + CHECK(l.secondary_zone_boxes.size() == 3); + } + } +} + +TEST_CASE("a 2x2 IQEX with independent secondaries gives one quadrant per tool", "[IMEXZones]") +{ + // No Span is declared, so nothing aggregates: T1, T2 and T3 each keep their own cell. + // Only T2 shares the primary's column, so it alone can collide with the primary + // carriage -- the diagonal T3 cannot, and must not raise a strip of its own. + PrinterCfg p; + p.gantry_count = 2; + p.tools_per_gantry = 2; + p.active_tools = "0:P,1:C,2:M,3:M"; + p.clearance_x = 6.0; + p.clearance_y = 4.0; + + const ImexZoneLayout l = layout_for(p); + + REQUIRE(l.primary_zone_box.has_value()); + check_rect(*l.primary_zone_box, 0.0, 0.0, 100.0, 100.0); + + REQUIRE(l.copy_zones.size() == 1); + check_rect(l.copy_zones[0], 100.0, 0.0, 200.0, 100.0); + + REQUIRE(l.mirror_zones.size() == 2); + check_rect(l.mirror_zones[0], 0.0, 100.0, 100.0, 200.0); + check_rect(l.mirror_zones[1], 100.0, 100.0, 200.0, 200.0); + + // Blocking boxes are the copy rects followed by the mirror rects, so the placement + // check and the rendered overlay always describe the same three areas. + REQUIRE(l.secondary_zone_boxes.size() == 3); + check_box_xy(l.secondary_zone_boxes[0], 100.0, 0.0, 200.0, 100.0); + check_box_xy(l.secondary_zone_boxes[1], 0.0, 100.0, 100.0, 200.0); + check_box_xy(l.secondary_zone_boxes[2], 100.0, 100.0, 200.0, 200.0); + + // T2 is directly behind the primary: one strip on the primary's rear boundary, + // clearance_y deep, spanning the primary zone's width. T3 contributes nothing. + REQUIRE(l.collision_zones.size() == 1); + check_box_xy(l.collision_zones[0], 0.0, 96.0, 100.0, 100.0); + CHECK(l.margin_bands.empty()); // margin defaults to 0 +} + +TEST_CASE("a Span partner collapses the far gantry into one full-width strip", "[IMEXZones]") +{ + // Paired-gantry multicolor: T1 is the primary's within-gantry Span partner, so the + // second gantry acts as a single mirrored unit rather than two independent tools. Its + // two mirrors merge into one row strip spanning the whole bed width, and the primary + // zone widens to match. + PrinterCfg p; + p.gantry_count = 2; + p.tools_per_gantry = 2; + p.active_tools = "0:P,1:S,2:M,3:M"; + p.clearance_x = 6.0; + p.clearance_y = 4.0; + + const ImexZoneLayout l = layout_for(p); + + REQUIRE(l.primary_head == 0); + REQUIRE(l.primary_zone_box.has_value()); + check_rect(*l.primary_zone_box, 0.0, 0.0, 200.0, 100.0); + + REQUIRE(l.mirror_zones.size() == 1); + check_rect(l.mirror_zones[0], 0.0, 100.0, 200.0, 200.0); + CHECK(l.copy_zones.empty()); + CHECK(l.secondary_zone_boxes.size() == 1); + + // A Span tool prints in the primary's own zone, so it owns no zone centre of its own. + CHECK(l.head_zone_centers.count(1) == 0); + check_point(l.head_zone_centers.at(0), 50.0, 50.0); + check_point(l.head_zone_centers.at(2), 50.0, 150.0); + check_point(l.head_zone_centers.at(3), 150.0, 150.0); + + // Regression guard: T3 sits on the other gantry's row, so the gantries never overlap + // in X and no right-edge strip may be drawn. Only the rear boundary is dangerous, and + // it runs the full width of the widened primary zone. + REQUIRE(l.collision_zones.size() == 1); + check_box_xy(l.collision_zones[0], 0.0, 96.0, 200.0, 100.0); +} + +TEST_CASE("inactive tools donate their bed share to the active ones", "[IMEXZones]") +{ + // Three tools on one gantry, but the mode activates only T0 and T2. Zones are sized by + // active tool count, so each gets half the bed rather than a third with a dead middle + // band -- and T2's zone starts where the primary's ends. + PrinterCfg p; + p.gantry_count = 1; + p.tools_per_gantry = 3; + p.active_tools = "0:P,2:M"; + p.clearance_x = 5.0; + + const ImexZoneLayout l = layout_for(p); + + REQUIRE(l.primary_zone_box.has_value()); + check_rect(*l.primary_zone_box, 0.0, 0.0, 100.0, 200.0); + CHECK_THAT(l.primary_zone_box->size().x(), WithinAbs(100.0, 1e-9)); // half, not 200/3 + + REQUIRE(l.mirror_zones.size() == 1); + check_rect(l.mirror_zones[0], 100.0, 0.0, 200.0, 200.0); + + REQUIRE(l.head_zone_centers.size() == 2); + check_point(l.head_zone_centers.at(0), 50.0, 100.0); + check_point(l.head_zone_centers.at(2), 150.0, 100.0); + + // The two zones are adjacent, so the boundary between them is a real collision risk. + REQUIRE(l.collision_zones.size() == 1); + check_box_xy(l.collision_zones[0], 95.0, 0.0, 100.0, 200.0); +} + +TEST_CASE("the plate mode falls back to the process preset only when it is Primary", "[IMEXZones]") +{ + PrinterCfg p; + p.gantry_count = 1; + p.tools_per_gantry = 2; + p.active_tools = "0:P,1:M"; + + SECTION("a plate still on Primary picks up the process preset's mode") { + const ImexZoneLayout l = layout_for(p, kImexPrimaryMode, kMode); + REQUIRE(l.primary_zone_box.has_value()); + check_rect(*l.primary_zone_box, 0.0, 0.0, 100.0, 200.0); + } + + SECTION("a plate with its own mode ignores the process preset") { + // The process preset names a mode that does not exist; the plate's own mode wins, + // so the layout is still built from kMode's tools. + const ImexZoneLayout l = layout_for(p, kMode, "no-such-mode"); + REQUIRE(l.primary_zone_box.has_value()); + check_rect(*l.primary_zone_box, 0.0, 0.0, 100.0, 200.0); + } + + SECTION("Primary on both sides yields no zones at all") { + CHECK(is_empty(layout_for(p, kImexPrimaryMode, std::string()))); + CHECK(is_empty(layout_for(p, kImexPrimaryMode, kImexPrimaryMode))); + } +} + +TEST_CASE("configurations with nothing to divide yield an empty layout", "[IMEXZones]") +{ + PrinterCfg base; + base.gantry_count = 1; + base.tools_per_gantry = 2; + base.active_tools = "0:P,1:M"; + + SECTION("a non-IMEX printer") { + PrinterCfg p = base; + p.is_imex = false; + CHECK(is_empty(layout_for(p))); + } + + SECTION("an empty plate mode") { + CHECK(is_empty(layout_for(base, std::string(), std::string()))); + } + + SECTION("a single-tool grid has no second zone to dim") { + PrinterCfg p = base; + p.gantry_count = 1; + p.tools_per_gantry = 1; + p.active_tools = "0:P"; + CHECK(is_empty(layout_for(p))); + } + + SECTION("a mode name that the printer does not define") { + // A stale mode carried in from another printer's process preset: the name resolves + // to no tool roster, so there is nothing to lay out. + CHECK(is_empty(layout_for(base, "carried-over-mode"))); + } + + SECTION("a mode whose tool roster is empty") { + PrinterCfg p = base; + p.active_tools = ""; + CHECK(is_empty(layout_for(p))); + } +} + +TEST_CASE("a Primary that is not on the grid yields no zones at all", "[IMEXZones]") +{ + // The modes editor preserves tool assignments across imex_gantry_count changes, so a mode + // authored on a 4-tool IQEX with Primary on T3 keeps that assignment after the printer is + // reconfigured as a 2-tool IDEX. T3 is then off the grid and cannot anchor a layout: the + // primary's cell is what every zone, strip and offset is measured from. + PrinterCfg p; + p.gantry_count = 1; + p.tools_per_gantry = 2; + p.active_tools = "3:P,0:M"; + p.clearance_x = 5.0; + p.margin = 2.0; + + const ImexZoneLayout l = layout_for(p); + + CHECK(is_empty(l)); + + // Spelled out, because the failure this guards is a self-contradiction rather than a + // wrong rectangle: the primary zone used to report the whole bed printable while the + // secondary box reported the very same rectangle blocked. + CHECK(l.primary_head == -1); + CHECK_FALSE(l.primary_zone_box.has_value()); + CHECK(l.secondary_zone_boxes.empty()); + CHECK(l.mirror_zones.empty()); + // No zone centre either, so no ghost is placed from a cell no tool occupies. + CHECK(l.head_zone_centers.empty()); + // And with no primary zone, a firmware-managed printer shifts the slice by nothing + // rather than by the bed centre. + check_point(compute_imex_slice_offset(true, kMode, l.primary_zone_box), 0.0, 0.0); +} + +TEST_CASE("a mode with no Primary marker at all yields no zones", "[IMEXZones]") +{ + // Same defect by a different route: every tool is a secondary, so there is no `:P` to + // anchor the layout even though the roster is non-empty and entirely on the grid. + PrinterCfg p; + p.gantry_count = 1; + p.tools_per_gantry = 2; + p.active_tools = "0:M,1:M"; + p.clearance_x = 5.0; + + CHECK(is_empty(layout_for(p))); +} + +TEST_CASE("a Primary on the last tool of the grid lays out normally", "[IMEXZones]") +{ + // Boundary of the bound that drops an off-grid Primary: the highest valid index must + // still be accepted, so the guard cannot be an off-by-one that swallows real modes. + SECTION("last column of a 1x2 IDEX") { + PrinterCfg p; + p.gantry_count = 1; + p.tools_per_gantry = 2; + p.active_tools = "1:P,0:M"; + p.clearance_x = 5.0; + p.margin = 2.0; + + const ImexZoneLayout l = layout_for(p); + + REQUIRE(l.primary_head == 1); + REQUIRE(l.primary_zone_box.has_value()); + check_rect(*l.primary_zone_box, 100.0, 0.0, 200.0, 200.0); + + REQUIRE(l.mirror_zones.size() == 1); + check_rect(l.mirror_zones[0], 0.0, 0.0, 100.0, 200.0); + + REQUIRE(l.head_zone_centers.size() == 2); + check_point(l.head_zone_centers.at(0), 50.0, 100.0); + check_point(l.head_zone_centers.at(1), 150.0, 100.0); + + // The mirror sits to the primary's left, so the strip hugs the primary zone's + // left boundary and the advisory band lies further inside it. + REQUIRE(l.collision_zones.size() == 1); + check_box_xy(l.collision_zones[0], 100.0, 0.0, 105.0, 200.0); + REQUIRE(l.margin_bands.size() == 1); + check_rect(l.margin_bands[0], 105.0, 0.0, 107.0, 200.0); + } + + SECTION("last tool of a 2x2 IQEX") { + PrinterCfg p; + p.gantry_count = 2; + p.tools_per_gantry = 2; + p.active_tools = "3:P,0:M"; + p.clearance_x = 5.0; + p.clearance_y = 5.0; + + const ImexZoneLayout l = layout_for(p); + + REQUIRE(l.primary_head == 3); + REQUIRE(l.primary_zone_box.has_value()); + check_rect(*l.primary_zone_box, 100.0, 100.0, 200.0, 200.0); + + REQUIRE(l.mirror_zones.size() == 1); + check_rect(l.mirror_zones[0], 0.0, 0.0, 100.0, 100.0); + + // T0 is diagonally opposite the primary, so the gantries never overlap and no + // boundary of the primary zone is a collision risk. + CHECK(l.collision_zones.empty()); + } +} + +TEST_CASE("zero clearance and zero margin suppress the strips they size", "[IMEXZones]") +{ + // The strip width is the literal clearance value, so a printer that has not configured + // one gets no strip rather than a zero-width box the placement check would still test. + PrinterCfg p; + p.gantry_count = 1; + p.tools_per_gantry = 2; + p.active_tools = "0:P,1:M"; + + SECTION("no clearance, no strip") { + const ImexZoneLayout l = layout_for(p); + CHECK(l.collision_zones.empty()); + CHECK(l.margin_bands.empty()); + } + + SECTION("clearance without margin gives the strip but no advisory band") { + p.clearance_x = 5.0; + const ImexZoneLayout l = layout_for(p); + CHECK(l.collision_zones.size() == 1); + CHECK(l.margin_bands.empty()); + } +} + +TEST_CASE("an aggregated gantry raises its collision strip from the zone it paints", "[IMEXZones]") +{ + // A Span partner on the primary's gantry collapses the far gantry to a single cell, + // pinned to the primary's column and expanded into a full-bed-width row strip. The + // danger strip on the primary's rear boundary has to follow that painted strip, not any + // one head's own grid cell -- with three tools per gantry the surviving mirrors sit in + // columns 1 and 2, neither of which is the primary's, yet the zone they jointly paint + // still runs the full width of the bed and still closes on the primary's carriage. + // + // Both rosters describe the same machine geometry (one primary gantry, one mirrored + // gantry behind it), so both must produce the same rectangles. + struct Case { const char* name; int tools_per_gantry; const char* active_tools; }; + const Case cases[] = { + { "two tools per gantry, mirrors on T2 and T3", 2, "0:P,1:S,2:M,3:M" }, + { "three tools per gantry, mirrors on T4 and T5", 3, "0:P,1:S,4:M,5:M" }, + }; + + for (const Case& c : cases) { + DYNAMIC_SECTION(c.name) { + PrinterCfg p; + p.gantry_count = 2; + p.tools_per_gantry = c.tools_per_gantry; + p.active_tools = c.active_tools; + p.clearance_x = 6.0; + p.clearance_y = 4.0; + p.margin = 2.0; + + const ImexZoneLayout l = layout_for(p); + + REQUIRE(l.primary_head == 0); + REQUIRE(l.primary_zone_box.has_value()); + check_rect(*l.primary_zone_box, 0.0, 0.0, 200.0, 100.0); + + // One merged rear strip for the whole far gantry, however many heads it carries. + CHECK(l.copy_zones.empty()); + REQUIRE(l.mirror_zones.size() == 1); + check_rect(l.mirror_zones[0], 0.0, 100.0, 200.0, 200.0); + REQUIRE(l.secondary_zone_boxes.size() == 1); + check_box_xy(l.secondary_zone_boxes[0], 0.0, 100.0, 200.0, 200.0); + + // The rear boundary is the collision risk, one clearance_y deep and as wide as + // the widened primary zone. Exactly one strip: the two gantries share no X + // extent, so neither side boundary may raise one of its own. + REQUIRE(l.collision_zones.size() == 1); + check_box_xy(l.collision_zones[0], 0.0, 96.0, 200.0, 100.0); + + // And the advisory band immediately inside it, one margin deep. + REQUIRE(l.margin_bands.size() == 1); + check_rect(l.margin_bands[0], 0.0, 94.0, 200.0, 96.0); + } + } +} From 3629056831a1db473e4cf64fa61d90b8bcc25365 Mon Sep 17 00:00:00 2001 From: Clifford Garwood <cliff@cigii.com> Date: Thu, 3 Sep 2026 00:55:35 -0400 Subject: [PATCH 34/51] Derive the IMEX slice offset in the engine Closes review comment 11, and fixes a worse bug found while doing so. The offset was only ever pushed from PartPlate::refresh_imex_slice_offset(), reachable from update_slice_context() and the plater -- both GUI-only, and it dereferences wxGetApp(). A headless slice therefore kept Vec2d::Zero(), so orca-slicer --slice on a plate with imex_firmware_managed_zones emitted slicer-managed coordinates while the firmware applied its own offsets on top. Print::update_imex_slice_offset() now derives it from the applied config and runs from process() and export_gcode(), so a CLI slice gets the value a GUI slice does. It reads m_full_print_config rather than m_config because imex_tool_layout and imex_carriage_margin are printer-preset options with no member in the static PrintConfig, and it takes the mode from the same place GCode.cpp resolves it, so the shift cannot disagree with the mode that is emitted. The GUI push and Print::set_imex_slice_offset() are deleted rather than kept as an override, because the two did not agree. calc_imex_zones() divides get_extents(m_shape), and set_shape translates m_shape by the plate position, so the pushed offset carried the plate origin -- which translate_to_print_space() and the writer offset already subtract. Plate 1 sits at the origin and agreed by accident; every later plate had the origin subtracted twice and was shifted by a full plate stride. Not silent, either: the displaced geometry fell outside the printable area, so slicing plate 2 failed validation with "part is off the plate". Confirmed fixed on hardware profiles -- the same model on plates 1 and 2 now emits identical extents. Deleting the push also removes the post-apply ordering constraint that forced the duplicate call in Plater::priv::update_background_process: the value is computed at the point of use, and process()/export_gcode() are structurally after apply(). Also routes validate()'s primary-routing check through imex_resolve_routing() so the hard block and the plater's warning cannot describe a plate differently (review comment 20), and through find_imex_mode() for the mode lookup (18). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- src/libslic3r/Print.cpp | 156 +++++++++++++++++++++++++--------------- src/libslic3r/Print.hpp | 15 ++-- 2 files changed, 109 insertions(+), 62 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 99705f8bdb..6a0c8eefec 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1,6 +1,7 @@ #include "Config.hpp" #include "Exception.hpp" #include "IMEXHelpers.hpp" +#include "IMEXZones.hpp" #include "Print.hpp" #include "BoundingBox.hpp" #include "Brim.hpp" @@ -1332,27 +1333,31 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin // IDEX/IQEX: block multi-color in non-primary parallel modes when the active // configuration can't physically support it (no within-gantry toolchange path // or MMU lane sharing). See imex_multicolor_block_reason() for the full rule. - // Both IMEX checks below need the active mode's tools string, so the parallel table is - // walked once here. Note this block is NOT gated on extruders.size() > 1: the primary + // Both IMEX checks below need the active mode's tools string and its declared primary, + // so imex_resolve_routing() derives them once for the whole block -- and is the same call + // the plater's pre-slice warning makes, so the two cannot describe the plate differently. + // Note this block is NOT gated on extruders.size() > 1: the primary // routing check applies to a single-filament plate too, which is its most common case. if (m_config.is_imex.value && !m_objects.empty()) { const std::string& parallel_mode = m_objects.front()->config().imex_parallel_mode.value; if (!parallel_mode.empty() && parallel_mode != kImexPrimaryMode) { - // Look up the active mode's tools string in the printer config's parallel - // table. Fall back to empty (the helpers below handle it gracefully). - std::string active_tools_str; - const auto& mode_names = m_config.imex_mode_names.values; - const auto& mode_tools = m_config.imex_mode_active_tools.values; - for (size_t i = 0; i < mode_names.size(); ++i) { - if (mode_names[i] == parallel_mode && i < mode_tools.size()) { - active_tools_str = mode_tools[i]; - break; - } - } std::vector<int> used_filaments_0b; + std::vector<int> used_slots_1b; used_filaments_0b.reserve(extruders.size()); - for (unsigned int e : extruders) + used_slots_1b.reserve(extruders.size()); + for (unsigned int e : extruders) { used_filaments_0b.push_back((int)e); + used_slots_1b.push_back((int)e + 1); + } + + // The active mode's tools string, its declared primary, and whether this plate's + // filaments reach that primary are all derived ONCE, here. The plater's pre-slice + // warning (collect_imex_warnings) makes the identical call, so the sentence it + // shows before slicing and the refusal below cannot describe the plate + // differently. An unresolved mode, and a mode the tools array is too short to + // cover, both yield an empty roster and no primary. + const ImexRouting routing = imex_resolve_routing(m_config, parallel_mode, used_slots_1b, + m_config.physical_extruder_map); // A mixed filament is blended at the nozzle by its component toolheads, and a // parallel mode is already using those toolheads to print copies or mirrors, so @@ -1386,7 +1391,7 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin if (used_filaments_0b.size() > 1) { const std::string reason = imex_multicolor_block_reason( parallel_mode, - active_tools_str, + routing.active_tools, m_config.imex_tools_per_gantry.value, used_filaments_0b, m_config.physical_extruder_map); @@ -1398,8 +1403,9 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin // filament the printer's physical_extruder_map routes to it. The ghost filament // picker already enforces this for the secondary tools; the primary's filament // comes from the ordinary object filament selector, which has no IMEX awareness, - // so nothing detected the mismatch. collect_imex_warnings() computes the same - // condition and discards it into a display fallback. + // so nothing detected the mismatch. collect_imex_warnings() reads the SAME + // routing.primary_logical off the same derivation, and discards it into a display + // fallback so its warning still has a filament to name. // // Blocks rather than warns, matching the multi-color rule above -- but on intent, // not on physics, and the distinction matters to anyone tempted to relax it. The @@ -1416,48 +1422,33 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin // that head holds nozzle_temperature_initial_layer for the whole job. First-layer // temperatures are unaffected -- _print_first_layer_extruder_temperatures is not // IMEX-branched -- so this is a stuck-hot nozzle, not a cold one. - const ConfigOptionInts& pem = m_config.physical_extruder_map; - const int declared_primary = imex_primary_tool_for_mode(active_tools_str); - if (declared_primary >= 0 && !pem.values.empty()) { - std::vector<int> used_slots_1b; - used_slots_1b.reserve(used_filaments_0b.size()); - for (int slot_0b : used_filaments_0b) - used_slots_1b.push_back(slot_0b + 1); - if (imex_primary_logical_from_objects(used_slots_1b, pem, declared_primary) < 0) { - // Bounds-check exactly as imex_primary_logical_from_objects does. get_at() - // CLAMPS out-of-range slots to values.front(), which would let the message - // name the very tool it just said nothing routes to. Blended slots are - // out of range by construction, but they never reach here -- the rule - // above returns first. - std::vector<int> routed_heads; - routed_heads.reserve(used_filaments_0b.size()); - for (int slot_0b : used_filaments_0b) - if (slot_0b >= 0 && slot_0b < (int) pem.values.size()) - routed_heads.push_back(pem.values[slot_0b]); - std::sort(routed_heads.begin(), routed_heads.end()); - routed_heads.erase(std::unique(routed_heads.begin(), routed_heads.end()), routed_heads.end()); - std::string routed_list; - for (int head : routed_heads) - routed_list += (routed_list.empty() ? "T" : ", T") + std::to_string(head); - // Print::apply() normalises physical_extruder_map through - // effective_physical_extruder_map (PrintApply.cpp) before validate() runs, so - // an unauthored map arrives here as the identity and every slot is in range. - // What is left is a printer with more filaments than logical extruders, where - // the tail slots fall outside the map. Narrow, but without this the sentence - // ends in a dangling "on .". - if (routed_list.empty()) - routed_list = L("no configured tool"); + // + // `primary_unrouted` is the whole condition: a declared primary, a populated + // routing map, and nothing used reaching it. Blended slots would also read as + // unrouted -- they sit past the map by construction -- but they never get here, + // the mixed-filament rule above returns first. + if (routing.primary_unrouted) { + std::string routed_list; + for (int head : routing.routed_heads) + routed_list += (routed_list.empty() ? "T" : ", T") + std::to_string(head); + // Print::apply() normalises physical_extruder_map through + // effective_physical_extruder_map (PrintApply.cpp) before validate() runs, so + // an unauthored map arrives here as the identity and every slot is in range. + // What is left is a printer with more filaments than logical extruders, where + // the tail slots fall outside the map. Narrow, but without this the sentence + // ends in a dangling "on .". + if (routed_list.empty()) + routed_list = L("no configured tool"); - StringObjectException err; - err.string = Slic3r::format( - L("IMEX mode \"%1%\" prints with T%2%, but this plate's filaments are on %3%. " - "Assign a filament loaded on T%2%, or switch this plate to Primary mode."), - parallel_mode, declared_primary, routed_list); - // Gives the notification a "Jump to <object>" link, which selects the object - // and switches to Prepare -- directly enabling the first suggested remedy. - err.object = m_objects.front(); - return err; - } + StringObjectException err; + err.string = Slic3r::format( + L("IMEX mode \"%1%\" prints with T%2%, but this plate's filaments are on %3%. " + "Assign a filament loaded on T%2%, or switch this plate to Primary mode."), + parallel_mode, routing.primary_phys, routed_list); + // Gives the notification a "Jump to <object>" link, which selects the object + // and switches to Prepare -- directly enabling the first suggested remedy. + err.object = m_objects.front(); + return err; } } } @@ -2413,6 +2404,10 @@ void Print::process(long long *time_cost_with_cache, bool use_cache) name_tbb_thread_pool_threads_set_locale(); + // IMEX firmware-managed zones: settle the emission-frame shift from the applied config + // before anything runs. Zero for every printer that is not IMEX + firmware-managed. + this->update_imex_slice_offset(); + //compute the PrintObject with the same geometries BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": this=%1%, enter, use_cache=%2%, object size=%3%")%this%use_cache%m_objects.size(); if (m_objects.empty()) @@ -3059,6 +3054,10 @@ std::string Print::export_gcode(const std::string& path_template, GCodeProcessor // centered at bed origin; processor offset stays at plate_origin so the gcode-preview // visualizer renders the centered slice at the bed center rather than the prepare-view // zone placement. Both arms reduce to set_gcode_offset() semantics when shift is zero. + // Derived here rather than read as pushed-in state, so an exporter reached without a + // preceding process() (or after a config change that only invalidated psGCodeExport) + // still emits in the frame the current config asks for. + this->update_imex_slice_offset(); const Vec2d imex_off = this->get_imex_slice_offset(); gcode.set_gcode_offset_with_imex_shift(origin(0), origin(1), imex_off.x(), imex_off.y()); gcode.do_export(this, path.c_str(), result, thumbnail_cb); @@ -3484,6 +3483,47 @@ Points Print::first_layer_wipe_tower_corners(bool check_wipe_tower_existance) co return corners; } +// IMEX firmware-managed zones: derive the slice-time XY shift from the config that has +// already been applied to this Print, so the engine never has to be told what it can work +// out. Deriving it here rather than taking a push from PartPlate is what makes a headless +// slice correct: the CLI builds a PartPlateList but drives no plater, so nothing ever ran +// the GUI-side handoff and the shift silently stayed at zero while the mode G-code told the +// firmware to fan copies out — parts in the wrong place, no diagnostic. +// +// Inputs, all reachable without a GUI: +// * m_full_print_config — the printer preset's IMEX keys. It is the full config rather +// than m_config because `imex_tool_layout` and `imex_carriage_margin` are printer-preset +// options with no home in the static PrintConfig, so m_config does not carry them. +// * the plate's `imex_parallel_mode`, read off the object config. That is the same source +// GCode.cpp and validate() resolve the active mode from (the plate's own config is +// merged into the full config before apply() by BackgroundSlicingProcess in the GUI and +// by CLI_Main in the CLI), so the shift can never disagree with the mode actually +// emitted. compute_imex_zone_layout() yields no zones for a mode the printer does not +// define, matching GCode.cpp's fallback to Primary for an unresolved mode name. +// * printable_area — the bed in PLATE-LOCAL mm. This must not be the plate's world-frame +// outline: translate_to_print_space() and the writer offset already subtract m_origin, +// so an offset carrying the plate origin would subtract it twice and put every plate +// but the first one a full plate stride out. +// +// A non-IMEX printer, or one with firmware-managed zones off, costs two bool reads and +// keeps m_imex_slice_offset at exactly Vec2d::Zero() — which is what keeps its G-code +// byte-identical. +void Print::update_imex_slice_offset() +{ + m_imex_slice_offset = Vec2d::Zero(); + if (!m_config.is_imex.value || !m_config.imex_firmware_managed_zones.value || m_objects.empty()) + return; + + // Already the resolved plate-or-process mode: the plate config overrides the process + // preset's key on the way in, exactly as PartPlate::get_imex_mode() prefers the plate. + const std::string& active_mode = m_objects.front()->config().imex_parallel_mode.value; + const ImexZoneLayout layout = compute_imex_zone_layout(m_full_print_config, active_mode, + std::string(), + get_extents(m_config.printable_area.values)); + // Empty / Primary mode and an empty layout both come back as Vec2d::Zero() here. + m_imex_slice_offset = compute_imex_slice_offset(true, active_mode, layout.primary_zone_box); +} + //SoftFever // "Print space" is the frame the emitted gcode uses. IMEX firmware-managed mode // shifts that frame by `m_imex_slice_offset` (the primary zone center in plate-local diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index fdc6083f0d..5cfe8bfcfb 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -1137,10 +1137,16 @@ public: void set_plate_origin(Vec3d origin) { m_origin = origin; } const Vec3d get_plate_origin() const { return m_origin; } // IMEX firmware-managed zones: additional XY shift applied at gcode emission so the - // primary zone's contents land at bed origin (0,0). Set by the GUI/PartPlate slice - // handoff when `imex_firmware_managed_zones` is on AND the active mode is non-primary. - // Vec2d::Zero() in every other case → byte-identical gcode output. - void set_imex_slice_offset(const Vec2d& o) { m_imex_slice_offset = o; } + // primary zone's contents land at bed origin (0,0). Non-zero only when + // `imex_firmware_managed_zones` is on AND the active mode is non-primary; Vec2d::Zero() + // in every other case → byte-identical gcode output for everyone else. + // + // Derived, never pushed in: update_imex_slice_offset() recomputes it from the applied + // config, so a headless slice gets the same shift a GUI slice does. It is a pure + // function of the config + printable_area, so calling it twice is a no-op; process() + // and export_gcode() both call it, which is what settles it ahead of every consumer + // (the writer offset in export_gcode(), and translate_to_print_space()). + void update_imex_slice_offset(); Vec2d get_imex_slice_offset() const { return m_imex_slice_offset; } //BBS: export gcode from previous gcode file from 3mf void set_gcode_file_ready(); @@ -1371,6 +1377,7 @@ private: //BBS: plate's origin Vec3d m_origin {0, 0, 0}; // IMEX firmware-managed slice offset (plate-local primary-zone center, or zero). + // Cache of update_imex_slice_offset(); nothing outside that function writes it. Vec2d m_imex_slice_offset { Vec2d::Zero() }; //BBS: modified_count int m_modified_count {0}; From 612e0e3932e9bae52b1c7cea29765bd918f9e818 Mon Sep 17 00:00:00 2001 From: Clifford Garwood <cliff@cigii.com> Date: Thu, 3 Sep 2026 00:55:35 -0400 Subject: [PATCH 35/51] Fall back to Primary when an IMEX mode does not resolve, and keep imex keys out of the config block Closes review comment 2, part of 18, and one non-IMEX regression the review did not cover. An imex_parallel_mode naming no entry in imex_mode_names still entered the parallel branches. get_imex_active_tools() returned empty and the else was skipped, so no head received its 1st-to-2nd layer temperature transition, and imex_suppresses_bare_toolchange() still dropped the initial T<n> on the expectation that a mode script would select the tool. validate() did not catch it because its guard is declared_primary >= 0 and an unresolved mode yields -1. You reach it by renaming a mode after a plate is set to it, or by opening a 3MF whose printer preset names its modes differently. m_imex_parallel_mode is no longer assigned before the lookup; a non-Primary name that matches no row now warns and re-resolves against the Primary row, which is the fallback the PR description already claimed. A mode that resolves to an empty tool roster takes the same path, since the emitted G-code is wrong in the same way. Warned rather than blocked: opening someone else's 3MF is a legitimate way to get here and the Primary reading prints correctly, so refusing to slice would turn a recoverable situation into a dead end. Silent was not an option either, because the plate keeps showing the stale mode name while drawing no zones. Separately, the 14 imex config keys all register non-nil defaults, so append_full_config was emitting "; imex_* = <default>" into every exported G-code, including on single-nozzle printers with nothing to do with the feature. They are banned from the dump, matching the treatment already given to the fast-purge, extruder-change and timelapse keys, so the config block is byte-identical to the pre-IMEX baseline for the whole shipping fleet. Nothing reads them back: GCodeProcessor has no imex reference, and the two per-plate keys round-trip through the 3MF's model_settings.config on an independent path. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- src/libslic3r/GCode.cpp | 121 ++++++++++++++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 23 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 47ef3352d1..58d681890c 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2883,19 +2883,10 @@ static std::vector<int> get_imex_active_tools(const Print& print) if (active_mode == kImexPrimaryMode) return active_tools; - const auto* mode_names_opt = print.config().option<ConfigOptionStrings>("imex_mode_names"); - const auto* tools_opt = print.config().option<ConfigOptionStrings>("imex_mode_active_tools"); - - if (!mode_names_opt || !tools_opt || mode_names_opt->values.empty() || tools_opt->values.empty()) - return active_tools; - - for (size_t i = 0; i < mode_names_opt->values.size(); ++i) { - if (i >= tools_opt->values.size() || mode_names_opt->values[i] != active_mode) - continue; - for (const auto& [phys, role] : parse_imex_active_tools(tools_opt->values[i])) - active_tools.push_back(phys); - break; - } + // An unresolved mode, and a mode the tools array is too short to cover, both hand back + // an empty tools string, which parses to no tools. + for (const auto& [phys, role] : parse_imex_active_tools(find_imex_mode(print.config(), active_mode).active_tools)) + active_tools.push_back(phys); return active_tools; } @@ -3685,19 +3676,78 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato if (print.config().is_imex.value && !print.objects().empty()) { const std::string& raw = print.objects().front()->config().imex_parallel_mode.value; imex_active_mode = raw.empty() ? kImexPrimaryMode : raw; - m_imex_parallel_mode = imex_active_mode; m_imex_head_filament_map = parse_imex_head_filament_map( print.objects().front()->config().imex_head_filament_map.value); - const auto& mode_names = print.config().imex_mode_names.values; - const auto& mode_gcodes = print.config().imex_mode_gcodes.values; - for (size_t i = 0; i < mode_names.size(); ++i) { - if (mode_names[i] == imex_active_mode) { - imex_active_mode_index = (int)i; - if (i < mode_gcodes.size()) - imex_active_mode_gcode = mode_gcodes[i]; - break; - } + // Look `name` up in the printer's mode table, filling in its index, script and + // tool roster. False means the name matches no row, i.e. the mode is unresolved. + // find_imex_mode() owns the "which row, and what if a sibling array is short" + // rule for every IMEX consumer; see IMEXHelpers.hpp. + std::string imex_active_mode_tools; + auto resolve_mode = [&](const std::string& name) { + const ImexMode mode = find_imex_mode(print.config(), name); + if (!mode.found()) + return false; + imex_active_mode_index = mode.index; + imex_active_mode_gcode = mode.gcode; + imex_active_mode_tools = mode.active_tools; + return true; + }; + // An unresolved mode name falls back to Primary rather than being carried into the + // parallel-mode paths. `imex_parallel_mode` is a plain string stored on the plate and + // matched against the printer's `imex_mode_names` by value, so it goes stale whenever + // the two drift apart -- a mode renamed or deleted after a plate was set to it, or a + // project shared between printer presets that name their modes differently. + // + // Without the fallback the exporter took every "not Primary" branch while every lookup + // keyed on the mode name came back empty, and wrote a file that is wrong rather than + // merely unconfigured: the 1st->2nd layer temperature branch is mutually exclusive with + // the standard one, so an empty active-tool roster meant NO head got its transition and + // all of them held nozzle_temperature_initial_layer for the whole print; and + // imex_suppresses_bare_toolchange() dropped the initial T<n> on the assumption that a + // mode script would select the tool, while the mode script -- also looked up by name -- + // did not exist. Print::validate()'s IMEX rules did not catch it either: they resolve + // the same name to an empty tools string, which yields no declared primary and skips + // the guard. Primary is the one interpretation that is always well-formed: single + // carriage, ordinary temperatures, ordinary tool changes. + // + // Warned rather than silent, and warned rather than blocked. Silent is not an option: + // the plate still labels itself with the stale mode and draws no zones (PartPlate's + // zone builder returns early on the same unresolved state), so a user who asked for two + // parts in copy mode would get one with nothing anywhere saying why. Blocking is not an + // option either -- opening someone else's 3MF on a differently-named preset is a + // legitimate way to arrive here, and the Primary interpretation prints correctly, so + // refusing to slice would be a regression for a case that has a good answer. + // + // The second trigger below is the ragged-table case, and it lands here rather than + // anywhere else because the damage is identical: the mode's name resolves, but the + // printer's `imex_mode_active_tools` is too short to reach its row (or the row is + // explicitly empty), so the roster every branch above keys on comes back empty and + // the export takes the parallel path with nothing in it. Nothing used to report + // that -- half the lookup sites in the tree turned a short tools array into "mode + // not found" and the other half did not, and this one did not. One rule now, in + // find_imex_mode(), and one warning, here. + const bool imex_mode_resolved = resolve_mode(imex_active_mode); + if (imex_active_mode != kImexPrimaryMode && (!imex_mode_resolved || imex_active_mode_tools.empty())) { + print.active_step_add_warning( + PrintStateBase::WarningLevel::NON_CRITICAL, + imex_mode_resolved + ? Slic3r::format(_(L("The IMEX mode \"%1%\" has no tools assigned on the selected printer. " + "Printing in Primary mode instead. Assign the mode's tools in Printer " + "Settings, or pick another mode from the plate's IMEX button.")), + imex_active_mode) + : Slic3r::format(_(L("This plate is set to the IMEX mode \"%1%\", which the selected printer " + "does not define. Printing in Primary mode instead. Pick a mode from the " + "plate's IMEX button, or restore the mode in Printer Settings.")), + imex_active_mode)); + imex_active_mode = kImexPrimaryMode; + imex_active_mode_index = 0; + imex_active_mode_gcode.clear(); + imex_active_mode_tools.clear(); + // Primary is a real row in the table (always the first one), so it may carry its own + // setup script; resolve it the same way any other selected mode would be. + resolve_mode(imex_active_mode); } + m_imex_parallel_mode = imex_active_mode; } this->placeholder_parser().set("imex_mode", imex_active_mode); this->placeholder_parser().set("imex_mode_index", imex_active_mode_index); @@ -7216,6 +7266,31 @@ void GCode::append_full_config(const Print &print, std::string &str) // banning it from the dump has no effect on the feature; the only H2C/H2D delta is the M9711/M971 // snapshot reposition. "farthest_point_timelapse"sv, + // The IMEX (IDEX/IQEX parallel printing) keys are newly-registered printer/process keys whose + // defaults are non-nil, so leaving them in the dump would add fourteen `; imex_* = <default>` + // lines to every printer's config block — an ordinary single-nozzle machine included. Excluding + // them keeps the config-dump byte-identical for the whole shipping fleet; the IMEX printers pay + // the same price the timelapse/prime-volume keys above already pay, and the active mode is still + // visible in the body of their g-code through the injected imex_mode_gcodes macro. Every key is + // read at slice time from m_config (get_imex_active_tools / find_imex_mode / the zone layout + // helpers) and never parsed back out of the dump, so banning them costs the feature nothing: + // the g-code viewer's overlay reads the loaded presets, not the config block, and the two + // per-plate process keys round-trip through the 3MF's model_settings.config plate metadata + // (bbs_3mf.cpp IMEX_PARALLEL_MODE_ATTR / IMEX_HEAD_FILAMENT_MAP_ATTR), not through this dump. + "is_imex"sv, + "imex_firmware_managed_zones"sv, + "imex_gantry_count"sv, + "imex_tools_per_gantry"sv, + "imex_tool_layout"sv, + "imex_nozzle_clearance_x"sv, + "imex_nozzle_clearance_y"sv, + "imex_carriage_margin"sv, + "imex_viz_theme"sv, + "imex_mode_names"sv, + "imex_mode_active_tools"sv, + "imex_mode_gcodes"sv, + "imex_parallel_mode"sv, + "imex_head_filament_map"sv, "compatible_printers"sv, "compatible_prints"sv, "filament_colour_type"sv, From 5629dd29e9e4c8b78105364f96ee8d56fe23bf22 Mon Sep 17 00:00:00 2001 From: Clifford Garwood <cliff@cigii.com> Date: Thu, 3 Sep 2026 00:55:35 -0400 Subject: [PATCH 36/51] Restore the pre-IMEX pressure advance output for non-IMEX printers Closes review comment 6. The per-tool pressure advance work changed set_pressure_advance() for users who are not using the feature. RepRapFirmware lost its D qualifier when no tool index was supplied: upstream emits M572 D0 S<pa> unconditionally, and a bare M572 applies to whatever tool is currently selected and errors when there is none, so PA started depending on tool-selection state for every RRF user. The D is back, defaulting to 0, and D<tool> is reached only from the IMEX paths. The same rewrite had also changed the comment separator from "<value>; Override" to "<value> ; Override" on the Klipper, RRF, Marlin 2.x and Marlin Legacy branches, so every non-IMEX print of those flavors carried a one-byte diff. Restored. Upstream is internally inconsistent here -- BBL and Repetier do use the spaced form -- and the point is to match it exactly rather than to tidy it. Emitted output for all six flavors with no tool index is now byte-identical to upstream. Verified on a real slice: a Klipper profile emits "SET_PRESSURE_ADVANCE ADVANCE=0.02; Override pressure advance value", an exact string match, with no EXTRUDER= qualifier. The tests were pinning the regressed form and are inverted. Also records at the imex key registrations why they are kept out of the g-code config block, matching the house convention at the other banned keys. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- src/libslic3r/GCodeWriter.cpp | 18 +++++++++--------- src/libslic3r/PrintConfig.cpp | 7 ++++++- tests/fff_print/test_gcodewriter.cpp | 15 +++++++-------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 1cbc5e4c58..8250cc09d8 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -522,14 +522,14 @@ std::string GCodeWriter::set_pressure_advance(double pa, int tool) const gcode << " EXTRUDER=extruder" << tool; else if (tool == 0) gcode << " EXTRUDER=extruder"; - gcode << " ; Override pressure advance value\n"; + gcode << "; Override pressure advance value\n"; } else if (FLAVOR_IS(gcfRepRapFirmware)) { - // RRF: M572 without D applies to the current tool; with D targets a specific extruder. - // Use D only when an explicit tool index is provided (IMEX parallel modes). - gcode << "M572"; - if (tool >= 0) - gcode << " D" << tool; - gcode << " S" << std::setprecision(4) << pa << " ; Override pressure advance value\n"; + // RRF: M572 D<n> targets a specific extruder; a bare M572 applies to whatever tool is + // currently selected and errors when there isn't one. Callers with no tool index keep + // the historical D0 rather than the bare form: PA would otherwise depend on + // tool-selection state for every RRF user, none of whom are asking for IMEX. + gcode << "M572 D" << (tool >= 0 ? tool : 0) + << " S" << std::setprecision(4) << pa << "; Override pressure advance value\n"; } else if (FLAVOR_IS(gcfRepetier)) { // Repetier M233: X is quadratic (K), Y is linear (L). // Applying the value to both parameters simultaneously. @@ -539,10 +539,10 @@ std::string GCodeWriter::set_pressure_advance(double pa, int tool) const gcode << "M900 K" << std::setprecision(4) << pa; if (tool >= 0) gcode << " T" << tool; - gcode << " ; Override pressure advance value\n"; + gcode << "; Override pressure advance value\n"; } else { // Marlin Legacy and everything else: single-extruder M900, no tool parameter - gcode << "M900 K" << std::setprecision(4) << pa << " ; Override pressure advance value\n"; + gcode << "M900 K" << std::setprecision(4) << pa << "; Override pressure advance value\n"; } return gcode.str(); } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 634164a005..fc946211a5 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -6604,7 +6604,12 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(true)); - // IDEX/IQEX (independent X extruder) — parallel printing support for IDEX/IQEX printers + // IDEX/IQEX (independent X extruder) — parallel printing support for IDEX/IQEX printers. + // Every key in this group is read at slice time from m_config, and the two per-plate process + // keys (imex_parallel_mode, imex_head_filament_map) round-trip through the 3MF's + // model_settings.config plate metadata, so none of them needs to appear in the exported + // g-code. They all carry non-nil defaults, so emitting them would add a line to every + // printer's dump. Kept out of the g-code config block (banned_keys). def = this->add("is_imex", coBool); def->label = L("IMEX Printer"); def->tooltip = L("Enable IMEX parallel printing for printers with multiple independent carriages (IDEX, IQEX, and similar)."); diff --git a/tests/fff_print/test_gcodewriter.cpp b/tests/fff_print/test_gcodewriter.cpp index a1969a2f89..1761e41f4f 100644 --- a/tests/fff_print/test_gcodewriter.cpp +++ b/tests/fff_print/test_gcodewriter.cpp @@ -845,14 +845,14 @@ SCENARIO("set_pressure_advance emits Klipper form with optional EXTRUDER=extrude std::string out = writer.set_pressure_advance(0.05); THEN("Output contains SET_PRESSURE_ADVANCE ADVANCE=0.05 with no EXTRUDER qualifier") { REQUIRE_THAT(out, Catch::Matchers::ContainsSubstring("SET_PRESSURE_ADVANCE")); - REQUIRE_THAT(out, Catch::Matchers::ContainsSubstring("ADVANCE=0.05")); + REQUIRE_THAT(out, Catch::Matchers::ContainsSubstring("ADVANCE=0.05; Override")); REQUIRE_THAT(out, !Catch::Matchers::ContainsSubstring("EXTRUDER=")); } } WHEN("set_pressure_advance is called with tool=0") { std::string out = writer.set_pressure_advance(0.04, 0); THEN("Output targets EXTRUDER=extruder (no trailing index)") { - REQUIRE_THAT(out, Catch::Matchers::ContainsSubstring("EXTRUDER=extruder ")); + REQUIRE_THAT(out, Catch::Matchers::ContainsSubstring("EXTRUDER=extruder;")); REQUIRE_THAT(out, !Catch::Matchers::ContainsSubstring("EXTRUDER=extruder0")); } } @@ -865,21 +865,20 @@ SCENARIO("set_pressure_advance emits Klipper form with optional EXTRUDER=extrude } } -SCENARIO("set_pressure_advance emits RepRapFirmware form with optional D<N>", "[GCodeWriter][PressureAdvance]") { +SCENARIO("set_pressure_advance emits RepRapFirmware form with D<N>", "[GCodeWriter][PressureAdvance]") { GIVEN("An RRF-flavored GCodeWriter") { GCodeWriter writer; writer.config.gcode_flavor.value = gcfRepRapFirmware; WHEN("set_pressure_advance is called without a tool index") { std::string out = writer.set_pressure_advance(0.07); - THEN("Output is bare M572 S... with no D qualifier") { - REQUIRE_THAT(out, Catch::Matchers::ContainsSubstring("M572 S0.07")); - REQUIRE_THAT(out, !Catch::Matchers::ContainsSubstring(" D")); + THEN("Output keeps the historical D0 rather than depending on the selected tool") { + REQUIRE_THAT(out, Catch::Matchers::ContainsSubstring("M572 D0 S0.07")); } } WHEN("set_pressure_advance is called with tool=0") { std::string out = writer.set_pressure_advance(0.08, 0); - THEN("Output contains D0 (explicit tool 0, not the current-tool fallback)") { + THEN("Output contains D0, same as the tool-less form") { REQUIRE_THAT(out, Catch::Matchers::ContainsSubstring("M572 D0 S0.08")); } } @@ -900,7 +899,7 @@ SCENARIO("set_pressure_advance emits Marlin 2.x form with optional T<N>", "[GCod WHEN("set_pressure_advance is called without a tool index") { std::string out = writer.set_pressure_advance(0.10); THEN("Output is bare M900 K... with no T qualifier") { - REQUIRE_THAT(out, Catch::Matchers::ContainsSubstring("M900 K0.1 ")); + REQUIRE_THAT(out, Catch::Matchers::ContainsSubstring("M900 K0.1; Override")); REQUIRE_THAT(out, !Catch::Matchers::ContainsSubstring(" T")); } } From a5ba39393e2ddeb95a0bad190cef3ad9bbf12c88 Mon Sep 17 00:00:00 2001 From: Clifford Garwood <cliff@cigii.com> Date: Thu, 3 Sep 2026 00:55:58 -0400 Subject: [PATCH 37/51] Escape the IMEX plate attributes written into the 3MF Closes review comment 1. imex_parallel_mode and imex_head_filament_map were streamed raw into XML attribute values, while every other free-text attribute in the same writer goes through xml_escape. Mode names are free text, so "PLA & ABS", a quote or a "<" made the document malformed. The failure is not a bad value on reload: both load paths for model_settings.config return false on an expat error, and m_is_bbl_3mf is set before the second entry loop runs, so the whole project fails to open with "Archive does not contain a valid model config". Both attributes now use xml_escape_double_quotes_attribute_value(), which also emits tab, CR and LF as numeric character references. That matters and plain xml_escape would not do: XML normalises literal whitespace in attribute values on read, so a tab in a mode name would come back as a space and silently rename the mode. The read side needs no change -- it takes expat's already-decoded value with no second unescape -- so this is a lossless round trip and a file written by the new code still loads in an older build. The round-trip test used "copy_mode", which exercised none of this; it now carries &, <, a quote and a tab, and also pins that ' and > come back unmodified, since both are legal raw inside a double-quoted value. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- src/libslic3r/Format/bbs_3mf.cpp | 10 ++++++++-- tests/libslic3r/test_3mf.cpp | 29 +++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index a6467487c4..f3fe29e028 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -8105,14 +8105,20 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SPIRAL_VASE_MODE << "\" " << VALUE_ATTR << "=\"" << spiral_mode_opt->getBool() << "\"/>\n"; { + // Mode names are user supplied free text, so the value has to be escaped for an + // attribute. xml_escape_double_quotes_attribute_value() is used rather than + // xml_escape() because it also emits tab/CR/LF as numeric character references: + // XML normalizes literal whitespace in attribute values on read, which would + // silently rename the mode. The reader takes the value straight from expat, + // which resolves both entities and character references, so this round-trips. auto* imex_mode_opt = plate_data->config.option<ConfigOptionString>("imex_parallel_mode"); if (imex_mode_opt && !imex_mode_opt->value.empty() && imex_mode_opt->value != kImexPrimaryMode) - stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << IMEX_PARALLEL_MODE_ATTR << "\" " << VALUE_ATTR << "=\"" << imex_mode_opt->value << "\"/>\n"; + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << IMEX_PARALLEL_MODE_ATTR << "\" " << VALUE_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(imex_mode_opt->value) << "\"/>\n"; } { auto* imex_hfm_opt = plate_data->config.option<ConfigOptionString>("imex_head_filament_map"); if (imex_hfm_opt && !imex_hfm_opt->value.empty()) - stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << IMEX_HEAD_FILAMENT_MAP_ATTR << "\" " << VALUE_ATTR << "=\"" << imex_hfm_opt->value << "\"/>\n"; + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << IMEX_HEAD_FILAMENT_MAP_ATTR << "\" " << VALUE_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(imex_hfm_opt->value) << "\"/>\n"; } //filament map related diff --git a/tests/libslic3r/test_3mf.cpp b/tests/libslic3r/test_3mf.cpp index ea448031f0..f90df77dd7 100644 --- a/tests/libslic3r/test_3mf.cpp +++ b/tests/libslic3r/test_3mf.cpp @@ -504,10 +504,27 @@ SCENARIO("BBS 3MF round-trips per-plate IMEX state (parallel mode + head filamen // Regression guard for the class of bug where per-plate state silently drops through // save/load (the variant-truncation bug was the precipitating example; IMEX plate state // rides the same XML metadata path and is equally vulnerable). + // + // The mode name is user-typed free text, so the values below deliberately carry every + // character class that is special inside an XML attribute value: + // & and < must be escaped or the document is not well formed and the project will + // not load at all, + // " must be escaped or it terminates the attribute early, + // tab must be written as a numeric character reference, because XML normalizes + // literal whitespace in attribute values on read and the mode would be + // silently renamed, + // ' and > are legal raw inside a double-quoted value and must survive untouched. + // The head filament map value is machine generated in practice; it is given hostile + // content here only to pin the escaping of the sibling attribute, so this asserts the + // XML transport, not the map grammar (the loader stores the string verbatim). + // // BBS exporter scaffolds a backup dir under temporary_dir() for the project config file; // point it at a writable location for the test process. set_temporary_dir(boost::filesystem::temp_directory_path().string()); + const std::string hostile_mode = "PLA & ABS <hot> \"2x\"\tcopy's mode"; + const std::string hostile_hfm = "1:2,2:3 & <\"\tx>"; + GIVEN("A Model with a single object on plate 0 and IMEX plate state set") { Model src_model; std::string src_file = std::string(TEST_DATA_DIR) + "/test_3mf/Prusa.stl"; @@ -519,8 +536,8 @@ SCENARIO("BBS 3MF round-trips per-plate IMEX state (parallel mode + head filamen PlateDataPtrs src_plates; auto *plate0 = new PlateData(); plate0->plate_index = 0; - plate0->config.set_key_value("imex_parallel_mode", new ConfigOptionString("copy_mode")); - plate0->config.set_key_value("imex_head_filament_map", new ConfigOptionString("1:2,2:3")); + plate0->config.set_key_value("imex_parallel_mode", new ConfigOptionString(hostile_mode)); + plate0->config.set_key_value("imex_head_filament_map", new ConfigOptionString(hostile_hfm)); src_plates.push_back(plate0); WHEN("the model is saved to BBS 3MF and loaded back") { @@ -551,17 +568,17 @@ SCENARIO("BBS 3MF round-trips per-plate IMEX state (parallel mode + head filamen THEN("the loaded plate list has the same number of plates") { REQUIRE(dst_plates.size() == src_plates.size()); } - THEN("imex_parallel_mode round-trips with its original value") { + THEN("imex_parallel_mode round-trips byte for byte, XML metacharacters included") { REQUIRE(dst_plates.size() >= 1); auto *mode_opt = dst_plates[0]->config.option<ConfigOptionString>("imex_parallel_mode"); REQUIRE(mode_opt != nullptr); - REQUIRE(mode_opt->value == "copy_mode"); + REQUIRE(mode_opt->value == hostile_mode); } - THEN("imex_head_filament_map round-trips with its original value") { + THEN("imex_head_filament_map round-trips byte for byte, XML metacharacters included") { REQUIRE(dst_plates.size() >= 1); auto *hfm_opt = dst_plates[0]->config.option<ConfigOptionString>("imex_head_filament_map"); REQUIRE(hfm_opt != nullptr); - REQUIRE(hfm_opt->value == "1:2,2:3"); + REQUIRE(hfm_opt->value == hostile_hfm); } release_PlateData_list(dst_plates); From 5ac1d05fcbb0c5b32a1f59c82c01a40952290c7b Mon Sep 17 00:00:00 2001 From: Clifford Garwood <cliff@cigii.com> Date: Thu, 3 Sep 2026 00:55:58 -0400 Subject: [PATCH 38/51] Stop three IMEX changes from altering non-IMEX behaviour None of these came from the review; they were found auditing the branch for the same class of leak review comment 6 identified. physical_extruder_map was normalised through effective_physical_extruder_map on every Print::apply(), so any printer with more than one nozzle and no authored map got the identity [0,1,...,n-1] where the single-element {0} default belongs. The key carries two readings: the IMEX paths index it by logical extruder and need one entry per extruder, while the inherited BBL paths read it through the clamping get_at(), for which {0} means "everything is physical 0". Deriving unconditionally imposed the IMEX reading on profiles that mean the other one, changing the config block line and the {first_tools} / {first_filaments} / {curr_physical_extruder_id} placeholders for multi-nozzle non-IMEX printers. Gated on is_imex; every consumer needing the per-extruder form is already IMEX-gated, and profiles with an authored map of the right length are unaffected either way. That gating unmasked a latent out-of-bounds read: WipeTower's M104/M109 emitters index m_physical_extruder_map by tool with no bounds check, which reads past the end of the single-element default on a multi-nozzle machine. Upstream's bug, from the BambuStudio wipe tower sync, previously hidden because the map was being widened for everyone. Now bounds-checked, falling back to the tool's own index -- the form GCodeProcessor already uses for the same map. Preset::save() and get_preset_differed_for_save() carried a branch storing the full vector whenever a child and its parent had different lengths. It was written against a set_with_nil that threw on mismatched sizes; upstream #13035 replaced that with a tolerant version that keeps the child vector verbatim and nil-marks only the overlapping range, and that fix was already in the tree when this branch was rebased. Left in, it defeated the delta encoding for every user printer preset whose extruder count differs from its parent's: a 7-extruder profile inheriting a single-extruder base wrote out all of its per-variant retraction keys as literals, including ones identical to the parent, pinning them against future vendor updates while the UI still reported the preset as inheriting. Removed; the two save loops are now identical to upstream. Note this only affects new saves -- presets already written keep their frozen values until re-saved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- src/libslic3r/GCode/WipeTower.cpp | 13 +++++++++++-- src/libslic3r/Preset.cpp | 12 ------------ src/libslic3r/PrintApply.cpp | 14 +++++++++++++- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 5834937169..790c0d9d73 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -1350,7 +1350,7 @@ public: buffer += "M400\n"; buffer += "M104"; if (target_extruder != -1) - buffer += (" T" + std::to_string(m_physical_extruder_map[target_extruder])); + buffer += (" T" + std::to_string(physical_extruder_for(target_extruder))); buffer += " S" + std::to_string(target_temp) + " N0"; // N0 means the gcode is generated by slicer if (!comment.empty()) buffer += " ;" + comment; buffer += '\n'; @@ -1362,7 +1362,7 @@ public: { std::string buffer = "M109"; if (target_extruder != -1) - buffer += (" T" + std::to_string(m_physical_extruder_map[target_extruder])); + buffer += (" T" + std::to_string(physical_extruder_for(target_extruder))); buffer += " S" + std::to_string(target_temp) + " N0"; // N0 means the gcode is generated by slicer if (!comment.empty()) buffer += " ;" + comment; buffer += '\n'; @@ -1382,6 +1382,15 @@ public: void set_multi_nozzle_group_result(const MultiNozzleUtils::LayeredNozzleGroupResult *multi_nozzle_group_result) { m_multi_nozzle_group_result = multi_nozzle_group_result; } void set_physical_extruder_map(const std::vector<int> &physical_extruder_map) { m_physical_extruder_map = physical_extruder_map; } + // physical_extruder_map defaults to the single element {0} and is only widened to one entry + // per extruder on IMEX printers, so indexing it by tool is out of range on any other + // multi-extruder machine. Fall back to the tool's own index, matching the bounds-checked + // form GCodeProcessor uses for the same map. + int physical_extruder_for(int tool) const + { + return tool >= 0 && tool < (int) m_physical_extruder_map.size() ? m_physical_extruder_map[tool] : tool; + } + private: std::string set_normal_acceleration() { std::vector<unsigned int> accelerations = m_is_first_layer ? m_first_layer_normal_accelerations : m_normal_accelerations; diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index e3ac3a75df..211de76a6c 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -733,12 +733,6 @@ void Preset::save(DynamicPrintConfig* parent_config) ConfigOptionVectorBase* opt_vec_inherit = static_cast<ConfigOptionVectorBase*>(parent_config->option(option)); if (opt_vec_src->size() == 1) opt_dst->set(opt_src); - else if (opt_vec_src->size() != opt_vec_inherit->size()) { - // Size mismatch (e.g. new multi-extruder profile inheriting from a - // single-extruder base): nil-delta encoding requires matching sizes, - // so fall back to storing the full vector. - opt_dst->set(opt_src); - } else if (key_set1->find(option) != key_set1->end()) { opt_vec_dst->set_with_nil(opt_vec_src, opt_vec_inherit, 1); } @@ -1905,12 +1899,6 @@ Preset* PresetCollection::get_preset_differed_for_save(Preset& preset) ConfigOptionVectorBase* opt_vec_inherit = static_cast<ConfigOptionVectorBase*>(parent_preset->config.option(option)); if (opt_vec_src->size() == 1) opt_dst->set(opt_src); - else if (opt_vec_src->size() != opt_vec_inherit->size()) { - // Size mismatch (e.g. new multi-extruder profile inheriting from a - // single-extruder base): nil-delta encoding requires matching sizes, - // so fall back to storing the full vector. - opt_dst->set(opt_src); - } else if (key_set1->find(option) != key_set1->end()) { opt_vec_dst->set_with_nil(opt_vec_src, opt_vec_inherit, 1); } diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index 3d1fc8f16c..579c5e5747 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -1313,7 +1313,19 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ // Fill in physical_extruder_map when the printer profile has not authored one. It has one // entry per logical extruder, so it is sized from the nozzle count -- not from // printer_extruder_id, which is indexed by variant slot. - { + // + // IMEX printers only. physical_extruder_map carries two readings in this tree (see + // IMEXHelpers.hpp): the IMEX paths need one entry per logical extruder, the inherited BBL + // paths read it through the clamping get_at(), which collapses every logical extruder to + // physical 0 while the profile default is the single-element {0}. Deriving the identity + // unconditionally would impose the IMEX reading on printers that mean the other one and + // change what they emit -- {first_tools}/{first_filaments}/{first_non_support_*} and + // {most_used_physical_extruder_id}/{curr_physical_extruder_id} in custom start G-code, plus + // the `; physical_extruder_map =` line in the G-code config block -- for every multi-nozzle + // profile that never authored a map. Non-IMEX printers therefore keep the config value + // exactly as it arrives, which is what upstream slices with. + const auto* is_imex_opt = new_full_config.option<ConfigOptionBool>("is_imex"); + if (is_imex_opt && is_imex_opt->value) { auto* pem = new_full_config.option<ConfigOptionInts>("physical_extruder_map", true); if (pem) { pem->values = effective_physical_extruder_map(pem, extruder_count).values; From 5b30af463d6e173f895587fbc8ceeb68815e6a1d Mon Sep 17 00:00:00 2001 From: Clifford Garwood <cliff@cigii.com> Date: Thu, 3 Sep 2026 00:56:26 -0400 Subject: [PATCH 39/51] Reduce PartPlate's zone code to a wrapper and key its cache on the tool layout calc_imex_zones() is now 69 lines: fetch the two edited configs, call compute_imex_zone_layout(), store the result, and clip each returned rect to the bed outline to build the GLModels. That last step is the only part that needs GUI types, which is why it stayed. See the extraction commit for the behaviour- preservation evidence. refresh_imex_slice_offset() is deleted along with its call in update_slice_context(); the offset is derived in the engine now, and it was computing it in the plate-list world frame, which double-counted the plate origin for every plate after the first. Two smaller changes: - The zone/ghost cache key omitted imex_tool_layout, which decides which physical corner tool 0 occupies and therefore moves every zone rectangle, collision strip and ghost offset while every other keyed field stays put. A layout change produced an identical key. That this currently appears to work is incidental -- some other path happens to rebuild -- and not something to depend on. Found by building the preview's own cache key against this one. - The tools-per-gantry fallback for a missing key was 1 in two places where PrintConfig registers 2 and the zone code uses 2. All four sites now agree; a missing key otherwise grouped tools against a grid divided a different way. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- src/slic3r/GUI/PartPlate.cpp | 478 +++++------------------------------ src/slic3r/GUI/PartPlate.hpp | 4 - 2 files changed, 69 insertions(+), 413 deletions(-) diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 3d968012f6..a828936ed0 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -28,6 +28,7 @@ #include "libslic3r/Tesselate.hpp" #include "libslic3r/GCode/ThumbnailData.hpp" #include "libslic3r/IMEXHelpers.hpp" +#include "libslic3r/IMEXZones.hpp" #include "libslic3r/Color.hpp" #include "libslic3r/Utils.hpp" @@ -573,6 +574,11 @@ void PartPlate::calc_exclude_triangles(const ExPolygon &poly) // Forward declaration (defined later in this file) static bool init_model_from_lines(GLModel &model, const Lines &lines, float z); +// Thin GUI wrapper: fetch the configs, hand the geometry to libslic3r, turn the returned +// rectangles into render meshes. Every zone/strip/margin decision lives in +// compute_imex_zone_layout (libslic3r/IMEXZones.cpp), which is unit-tested headlessly; +// the only work left here is clipping each rectangle to the bed outline and building the +// GLModel for it, which needs the GUI's model helpers. void PartPlate::calc_imex_zones() { m_imex_copy_zones.clear(); @@ -589,194 +595,34 @@ void PartPlate::calc_imex_zones() if (!wxGetApp().preset_bundle) return; - const DynamicPrintConfig& printer_cfg = wxGetApp().preset_bundle->printers.get_edited_preset().config; - auto* is_imex_opt = printer_cfg.option<ConfigOptionBool>("is_imex"); - if (!is_imex_opt || !is_imex_opt->value) + PresetBundle& bundle = *wxGetApp().preset_bundle; + const DynamicPrintConfig& printer_cfg = bundle.printers.get_edited_preset().config; + + // Process-preset mode is the fallback the library applies when the plate is still on + // the reserved Primary mode; it ignores this string otherwise. + std::string process_mode; + if (auto* mode_opt = bundle.prints.get_edited_preset().config.option<ConfigOptionString>("imex_parallel_mode")) + process_mode = mode_opt->value; + + const ImexZoneLayout layout = compute_imex_zone_layout(printer_cfg, get_imex_mode(), + process_mode, get_extents(m_shape)); + + m_imex_primary_head = layout.primary_head; + m_imex_head_zone_centers = layout.head_zone_centers; + m_imex_primary_zone_box = layout.primary_zone_box; + m_imex_secondary_zone_boxes = layout.secondary_zone_boxes; + m_imex_collision_zones = layout.collision_zones; + + // No primary zone means the layout is empty (IMEX off, Primary mode, single-tool grid, + // or a mode with no tools) -- exactly the cases that returned before touching geometry. + if (!m_imex_primary_zone_box.has_value()) return; - // Per-plate mode takes priority over the process preset. - std::string active_mode = get_imex_mode(); - if (active_mode == kImexPrimaryMode) { - const DynamicPrintConfig& process_cfg = wxGetApp().preset_bundle->prints.get_edited_preset().config; - auto* mode_opt = process_cfg.option<ConfigOptionString>("imex_parallel_mode"); - if (mode_opt && !mode_opt->value.empty()) - active_mode = mode_opt->value; - } - if (active_mode == kImexPrimaryMode || active_mode.empty()) - return; - - // Grid dimensions and tool layout from printer config - auto* gantry_opt = printer_cfg.option<ConfigOptionInt>("imex_gantry_count"); - auto* tpg_opt = printer_cfg.option<ConfigOptionInt>("imex_tools_per_gantry"); - auto* layout_opt = printer_cfg.option<ConfigOptionEnum<ImexToolLayout>>("imex_tool_layout"); - - int n_cols = tpg_opt ? std::max(1, tpg_opt->value) : 2; - int n_rows = gantry_opt ? std::max(1, gantry_opt->value) : 1; - - // Which corner is T0? flip_x: col 0 is right(max-X); flip_y: row 0 is rear(max-Y) - const ImexToolLayout layout = layout_opt ? layout_opt->value : ImexToolLayout::FrontLeft; - bool flip_x = (layout == ImexToolLayout::FrontRight || layout == ImexToolLayout::RearRight); - bool flip_y = (layout == ImexToolLayout::RearLeft || layout == ImexToolLayout::RearRight); - - // Convert tool index to physical (col=X-index, row=Y-index), col/row 0 = min-X/min-Y - auto tool_to_phys = [&](int idx) -> std::pair<int,int> { - int raw_col = idx % n_cols, raw_row = idx / n_cols; - return { flip_x ? (n_cols - 1 - raw_col) : raw_col, - flip_y ? (n_rows - 1 - raw_row) : raw_row }; - }; - - int pri_col = 0, pri_row = 0; - - if (n_cols == 1 && n_rows == 1) - return; // nothing to dim with a single zone - - // Look up secondary tool indices (active in mode, but NOT the primary tool) - auto* names_opt = printer_cfg.option<ConfigOptionStrings>("imex_mode_names"); - auto* tools_opt = printer_cfg.option<ConfigOptionStrings>("imex_mode_active_tools"); - std::string active_tools_str; - if (names_opt && tools_opt) { - for (size_t i = 0; i < names_opt->values.size(); ++i) { - if (names_opt->values[i] == active_mode && i < tools_opt->values.size()) { - active_tools_str = tools_opt->values[i]; - break; - } - } - } - - // Parse "phys_idx:P/C/M" format → map<phys_idx, state> (1=Primary, 2=Copy, 3=Mirror). - // imex_primary_tool_for_mode handles the Primary slot (bare legacy token → Primary); - // parse_imex_active_tools fills in the Copy/Mirror secondaries. Mode strings use - // physical T-indices directly; filament routing is separate (imex_head_filament_map). - std::map<int,int> tool_states; - { - const int primary = imex_primary_tool_for_mode(active_tools_str); - if (primary >= 0 && primary < n_rows * n_cols) - tool_states[primary] = 1; - for (const auto& [phys_idx, role] : parse_imex_active_tools(active_tools_str)) { - if (phys_idx < 0 || phys_idx >= n_rows * n_cols) continue; - if (phys_idx == primary) continue; - if (role == ImexRole::Mirror) tool_states[phys_idx] = 3; - else if (role == ImexRole::Copy) tool_states[phys_idx] = 2; - // Extra ImexRole::Primary entries beyond the first are ignored. - } - } - - // If the mode name was found but has no tools (e.g. stale process-preset mode on a new - // printer that has no modes defined yet), there is nothing to compute. - if (tool_states.empty()) - return; - - // Identify the Primary tool from the mode definition - for (auto& [idx, state] : tool_states) { - if (state == 1) { auto [c, r] = tool_to_phys(idx); pri_col = c; pri_row = r; - m_imex_primary_head = idx; break; } - } - - // Per-gantry grouping drives Span-based aggregation. When the mode declares a - // Span partner on primary's gantry, non-primary gantries with multiple same-role - // tools collapse to one cell each (placed at primary's column so has_col_sep - // stays false and make_boxes expands the cell into a full-X row-strip). - // Mixed-role / single-tool / no-Span configurations keep per-tool cells. - const ImexGantryGrouping grouping = - group_imex_active_tools_by_gantry(active_tools_str, n_cols); - std::map<int, const ImexGantryGroup*> group_by_gantry; - for (const auto& grp : grouping.groups) - group_by_gantry[grp.gantry_index] = &grp; - - // Separate copy and mirror secondary cells using physical coordinates - std::set<std::pair<int,int>> copy_cells, mirror_cells; - for (auto& [idx, state] : tool_states) { - if (state == 1) continue; // primary handled separately - - const int phys_gantry = idx / n_cols; - auto git = group_by_gantry.find(phys_gantry); - const ImexGantryGroup* grp = (git == group_by_gantry.end()) ? nullptr : git->second; - - if (grp && grp->aggregate) { - // Only the representative contributes a cell; non-reps are folded into - // the same row-strip and skipped entirely. - if (idx != grp->representative_phys) continue; - auto [rep_c, r] = tool_to_phys(idx); - (void)rep_c; // intentionally discarded — aggregated cell pins to pri_col - if (state == 2) copy_cells.insert({pri_col, r}); - else if (state == 3) mirror_cells.insert({pri_col, r}); - } else { - auto [c, r] = tool_to_phys(idx); - if (state == 2) copy_cells.insert({c, r}); - else if (state == 3) mirror_cells.insert({c, r}); - } - } - - // All active secondary cells combined (for separation axis computation) - std::set<std::pair<int,int>> all_secondary; - for (auto& p : copy_cells) all_secondary.insert(p); - for (auto& p : mirror_cells) all_secondary.insert(p); - - auto bed_ext = get_extents(m_shape); - double x_min = bed_ext.min(0), x_max = bed_ext.max(0); - double y_min = bed_ext.min(1), y_max = bed_ext.max(1); - - // Zone sizing is based on ACTIVE tool count per axis, not total grid dimensions. - // Inactive tools (absent from tool_states) donate their bed share to active neighbors. - // Sorted active col/row lists map physical index k → zone index k. - std::vector<int> active_cols_v, active_rows_v; - { - std::set<int> ac_set, ar_set; - for (auto& [idx, state] : tool_states) { - auto [c, r] = tool_to_phys(idx); - ac_set.insert(c); ar_set.insert(r); - } - active_cols_v.assign(ac_set.begin(), ac_set.end()); // sorted ascending - active_rows_v.assign(ar_set.begin(), ar_set.end()); - } - int n_active_cols = std::max(1, (int)active_cols_v.size()); - int n_active_rows = std::max(1, (int)active_rows_v.size()); - - std::map<int,int> col_to_zone, row_to_zone; - for (int k = 0; k < n_active_cols; ++k) col_to_zone[active_cols_v[k]] = k; - for (int k = 0; k < n_active_rows; ++k) row_to_zone[active_rows_v[k]] = k; - - double zone_w = (x_max - x_min) / n_active_cols; - double zone_h = (y_max - y_min) / n_active_rows; - - // Zone index of the primary tool - int pri_col_k = col_to_zone.count(pri_col) ? col_to_zone[pri_col] : 0; - int pri_row_k = row_to_zone.count(pri_row) ? row_to_zone[pri_row] : 0; - - // Zone center per physical head — ghost placement consumes this so that - // ghosts land in their own secondary zone instead of stacking on primary. - // Every active tool (including primary) gets an entry; ghost offset math is - // simply center[head] - center[primary]. - for (auto& [idx, state] : tool_states) { - auto [c, r] = tool_to_phys(idx); - int ck = col_to_zone.count(c) ? col_to_zone.at(c) : 0; - int rk = row_to_zone.count(r) ? row_to_zone.at(r) : 0; - m_imex_head_zone_centers[idx] = Vec2d( - x_min + (ck + 0.5) * zone_w, - y_min + (rk + 0.5) * zone_h); - } - - // Separation axes: row-sep = secondaries on a different gantry, col-sep = different column - bool has_row_sep = false, has_col_sep = false; - for (const auto& [sc, sr] : all_secondary) { - if (sr != pri_row) has_row_sep = true; - if (sc != pri_col) has_col_sep = true; - } - - // Primary zone extent (the clear printable area): - // row-sep only → full bed width × primary row's Y band - // col-sep only → primary col's X band × full bed height - // both → primary quadrant - auto in_primary_zone = [&](int col, int row) { - bool row_ok = !has_row_sep || (row == pri_row); - bool col_ok = !has_col_sep || (col == pri_col); - return row_ok && col_ok; - }; - ExPolygon bed_poly; generate_print_polygon(bed_poly); - // Build a clipped filled GLModel for an expanded zone rect and push into a vector. + // Build a clipped filled GLModel for one zone rect and push it into a vector. + // A rect falling entirely outside the bed outline contributes no model. auto push_zone_fill = [&](std::vector<GLModel>& vec, double cx0, double cx1, double cy0, double cy1) { ExPolygon cell; cell.contour.append({ scale_(cx0), scale_(cy0) }); @@ -791,179 +637,16 @@ void PartPlate::calc_imex_zones() } }; - // Build expanded zone rects for a set of cells. - // When secondaries share only a row difference (same column as primary) → expand to full X width. - // When secondaries share only a column difference → expand to full Y height. - // When both axes differ → per-quadrant. - struct BoxRect { double x0, x1, y0, y1; }; - auto make_boxes = [&](const std::set<std::pair<int,int>>& cells) -> std::vector<BoxRect> { - std::vector<BoxRect> boxes; - if (cells.empty()) return boxes; - auto ck = [&](int c) { return col_to_zone.count(c) ? col_to_zone.at(c) : 0; }; - auto rk = [&](int r) { return row_to_zone.count(r) ? row_to_zone.at(r) : 0; }; - if (has_row_sep && !has_col_sep) { - std::set<int> rows; for (auto& [c,r] : cells) rows.insert(r); - for (int sr : rows) { - int k = rk(sr); - boxes.push_back({x_min, x_max, y_min + k*zone_h, y_min + (k+1)*zone_h}); - } - } else if (has_col_sep && !has_row_sep) { - std::set<int> cols; for (auto& [c,r] : cells) cols.insert(c); - for (int sc : cols) { - int k = ck(sc); - boxes.push_back({x_min + k*zone_w, x_min + (k+1)*zone_w, y_min, y_max}); - } - } else { - for (auto& [sc,sr] : cells) { - int ck_ = ck(sc), rk_ = rk(sr); - boxes.push_back({x_min + ck_*zone_w, x_min + (ck_+1)*zone_w, - y_min + rk_*zone_h, y_min + (rk_+1)*zone_h}); - } - } - return boxes; - }; - - // Build fills for copy and mirror zones using expanded boxes (inactive cells not rendered). - auto push_expanded_fills = [&](std::vector<GLModel>& vec, const std::set<std::pair<int,int>>& cells) { - for (const auto& b : make_boxes(cells)) - push_zone_fill(vec, b.x0, b.x1, b.y0, b.y1); - }; - push_expanded_fills(m_imex_copy_zones, copy_cells); - push_expanded_fills(m_imex_mirror_zones, mirror_cells); - - - // --- Secondary zone blocking --- - // Collect the expanded bounding boxes for all secondary (copy+mirror) zones. - // check_outside() uses these to prevent objects being placed outside the primary zone. - for (const auto& b : make_boxes(copy_cells)) - m_imex_secondary_zone_boxes.push_back( - BoundingBoxf3(Vec3d(b.x0, b.y0, -1.0), Vec3d(b.x1, b.y1, 1e4))); - for (const auto& b : make_boxes(mirror_cells)) - m_imex_secondary_zone_boxes.push_back( - BoundingBoxf3(Vec3d(b.x0, b.y0, -1.0), Vec3d(b.x1, b.y1, 1e4))); - - // --- Carriage collision danger strips --- - // Only add strips at boundaries of the PRIMARY zone — objects are only placed in the - // primary zone, so secondary-to-secondary boundaries have no relevance. - // - // Strip width is the literal nozzle clearance value on the primary side only: - // right X boundary: [bnd_x - nozzle_clearance_x, bnd_x] - // left X boundary: [bnd_x, bnd_x + nozzle_clearance_x] - // top Y boundary: [bnd_y - nozzle_clearance_y, bnd_y] - // bottom Y boundary:[bnd_y, bnd_y + nozzle_clearance_y] - // - // Strip length matches the primary zone extent (same expansion logic as make_boxes): - // !has_row_sep → full bed height; has_row_sep → primary row only - // !has_col_sep → full bed width; has_col_sep → primary column only - - auto* cw_opt = printer_cfg.option<ConfigOptionFloat>("imex_nozzle_clearance_x"); - auto* ch_opt = printer_cfg.option<ConfigOptionFloat>("imex_nozzle_clearance_y"); - auto* mgn_opt = printer_cfg.option<ConfigOptionFloat>("imex_carriage_margin"); - double carriage_w = cw_opt ? cw_opt->value : 0.0; - double carriage_h = ch_opt ? ch_opt->value : 0.0; - double margin = mgn_opt ? mgn_opt->value : 0.0; - - // Helper: build a filled GLModel polygon and push into margin overlay (advisory, non-blocking) - auto add_margin_fill = [&](double sx0, double sx1, double sy0, double sy1) { - ExPolygon cell; - cell.contour.append({ scale_(sx0), scale_(sy0) }); - cell.contour.append({ scale_(sx1), scale_(sy0) }); - cell.contour.append({ scale_(sx1), scale_(sy1) }); - cell.contour.append({ scale_(sx0), scale_(sy1) }); - ExPolygons clipped = intersection_ex({ cell }, { bed_poly }); - if (!clipped.empty()) { - GLModel m; - if (init_model_from_poly(m, clipped.front(), GROUND_Z)) - m_imex_margin_overlay.push_back(std::move(m)); - } - }; - - // Primary zone extent — uses zone indices so inactive tools don't shrink the zone - double pz_x0 = has_col_sep ? x_min + pri_col_k * zone_w : x_min; - double pz_x1 = has_col_sep ? x_min + (pri_col_k + 1) * zone_w : x_max; - double pz_y0 = has_row_sep ? y_min + pri_row_k * zone_h : y_min; - double pz_y1 = has_row_sep ? y_min + (pri_row_k + 1) * zone_h : y_max; - m_imex_primary_zone_box = BoundingBoxf(Vec2d(pz_x0, pz_y0), Vec2d(pz_x1, pz_y1)); - - // Helper: build a BoundingBoxf3 strip, clip to bed, add to members - auto add_strip = [&](double sx0, double sx1, double sy0, double sy1) { - BoundingBoxf3 box; - box.min = Vec3d(sx0, sy0, -1.0); - box.max = Vec3d(sx1, sy1, 1e4); - m_imex_collision_zones.push_back(box); - - ExPolygon cell; - cell.contour.append({ scale_(sx0), scale_(sy0) }); - cell.contour.append({ scale_(sx1), scale_(sy0) }); - cell.contour.append({ scale_(sx1), scale_(sy1) }); - cell.contour.append({ scale_(sx0), scale_(sy1) }); - ExPolygons clipped = intersection_ex({ cell }, { bed_poly }); - if (!clipped.empty()) { - GLModel m; - if (init_model_from_poly(m, clipped.front(), GROUND_Z)) - m_imex_collision_overlay.push_back(std::move(m)); - } - }; - - // Determine which directions have mirror secondaries adjacent to the primary. - // Only mirror tools can cause carriage collisions — they move toward each other. - // Copy tools always move in the same direction, so no collision strip is needed. - // - // Both axes require zone-adjacent AND same row/column on the OTHER axis: a mirror - // diagonally offset from primary (different row AND different column) can't collide - // with primary's carriage on either axis since the gantries don't overlap there. - // Without these checks, paired-gantry mc-mirror (`0:P,1:S,2:M,3:M`) would draw a - // spurious right-edge strip from T3 even though T3 lives on the other gantry's row. - bool has_right_sec = false, has_left_sec = false; - bool has_top_sec = false, has_bottom_sec = false; - for (auto& [idx, state] : tool_states) { - if (state != 3) continue; // only mirror tools (state==3) require collision strips - auto [c, r] = tool_to_phys(idx); - int zc = col_to_zone.count(c) ? col_to_zone.at(c) : -1; - int zr = row_to_zone.count(r) ? row_to_zone.at(r) : -1; - // X-boundary strips: mirror zone-adjacent in X, same physical row as primary. - if (zr == pri_row_k && zc == pri_col_k + 1) has_right_sec = true; - if (zr == pri_row_k && zc == pri_col_k - 1) has_left_sec = true; - // Y-boundary strips: mirror zone-adjacent in Y, same physical column as primary. - if (zr == pri_row_k + 1 && c == pri_col) has_top_sec = true; - if (zr == pri_row_k - 1 && c == pri_col) has_bottom_sec = true; - } - - // X-axis boundaries (vertical strips, width = nozzle_clearance_x on primary side) - if (carriage_w > 0.0) { - if (has_right_sec) { - double bnd_x = x_min + (pri_col_k + 1) * zone_w; - double strip_inner = bnd_x - carriage_w; - add_strip(strip_inner, bnd_x, pz_y0, pz_y1); - if (margin > 0.0) - add_margin_fill(strip_inner - margin, strip_inner, pz_y0, pz_y1); - } - if (has_left_sec) { - double bnd_x = x_min + pri_col_k * zone_w; - double strip_inner = bnd_x + carriage_w; - add_strip(bnd_x, strip_inner, pz_y0, pz_y1); - if (margin > 0.0) - add_margin_fill(strip_inner, strip_inner + margin, pz_y0, pz_y1); - } - } - - // Y-axis boundaries (horizontal strips, width = nozzle_clearance_y on primary side) - if (carriage_h > 0.0) { - if (has_top_sec) { - double bnd_y = y_min + (pri_row_k + 1) * zone_h; - double strip_inner = bnd_y - carriage_h; - add_strip(pz_x0, pz_x1, strip_inner, bnd_y); - if (margin > 0.0) - add_margin_fill(pz_x0, pz_x1, strip_inner - margin, strip_inner); - } - if (has_bottom_sec) { - double bnd_y = y_min + pri_row_k * zone_h; - double strip_inner = bnd_y + carriage_h; - add_strip(pz_x0, pz_x1, bnd_y, strip_inner); - if (margin > 0.0) - add_margin_fill(pz_x0, pz_x1, strip_inner, strip_inner + margin); - } - } + for (const BoundingBoxf& b : layout.copy_zones) + push_zone_fill(m_imex_copy_zones, b.min.x(), b.max.x(), b.min.y(), b.max.y()); + for (const BoundingBoxf& b : layout.mirror_zones) + push_zone_fill(m_imex_mirror_zones, b.min.x(), b.max.x(), b.min.y(), b.max.y()); + // Red-orange fill for each carriage danger strip, and the amber advisory band just + // inside it. Both are visual only -- blocking is driven by m_imex_collision_zones. + for (const BoundingBoxf3& b : layout.collision_zones) + push_zone_fill(m_imex_collision_overlay, b.min.x(), b.max.x(), b.min.y(), b.max.y()); + for (const BoundingBoxf& b : layout.margin_bands) + push_zone_fill(m_imex_margin_overlay, b.min.x(), b.max.x(), b.min.y(), b.max.y()); } // Build a cache key from the current IDEX/IQEX config options, or "" if IDEX/IQEX is off. @@ -1014,9 +697,16 @@ std::string PartPlate::build_imex_cache_key() const int primary_phys = -1; resolve_active_mode_tools(active_tools, primary_phys); // empty on failure — keyed as such auto* fw_opt = printer_cfg.option<ConfigOptionBool>("imex_firmware_managed_zones"); + // imex_tool_layout decides which physical corner tool 0 occupies (flip_x / flip_y inside + // compute_imex_zone_layout), so every zone rectangle, collision strip and ghost offset moves + // when it changes while every other keyed field stays put. Without it the key is identical + // across a layout change and the baked zones go stale; that this currently appears to work is + // incidental -- some other path happens to rebuild -- not something to rely on. + auto* layout_opt = printer_cfg.option<ConfigOptionEnum<ImexToolLayout>>("imex_tool_layout"); return active_mode + "|" + std::to_string(n_col_opt ? n_col_opt->value : 2) + "x" + std::to_string(n_row_opt ? n_row_opt->value : 1) + + "|ly" + std::to_string(layout_opt ? (int)layout_opt->value : 0) + "|cw" + std::to_string(cw_opt ? (int)(cw_opt->value * 10) : 0) + "|ch" + std::to_string(ch_opt ? (int)(ch_opt->value * 10) : 0) + "|mg" + std::to_string(mgn_opt ? (int)(mgn_opt->value * 10) : 0) @@ -1107,18 +797,16 @@ bool PartPlate::resolve_active_mode_tools(std::string& out_tools_str, int& out_p } if (active_mode.empty() || active_mode == kImexPrimaryMode) return false; - auto* names = printer_cfg.option<ConfigOptionStrings>("imex_mode_names"); - auto* tools = printer_cfg.option<ConfigOptionStrings>("imex_mode_active_tools"); - if (!names || !tools) return false; - auto it = std::find(names->values.begin(), names->values.end(), active_mode); - if (it == names->values.end()) return false; - const size_t mode_idx = it - names->values.begin(); - if (mode_idx >= tools->values.size()) return false; + const ImexMode mode = find_imex_mode(printer_cfg, active_mode); + if (!mode.found()) return false; - const int primary_phys = imex_primary_tool_for_mode(tools->values[mode_idx]); + // Also the ragged case: a tools array too short to reach this row hands back an empty + // string, which has no declared primary, which is the same "no zones here" answer the + // explicit bounds check used to give. + const int primary_phys = imex_primary_tool_for_mode(mode.active_tools); if (primary_phys < 0) return false; - out_tools_str = tools->values[mode_idx]; + out_tools_str = mode.active_tools; out_primary_phys = primary_phys; return true; } @@ -1159,7 +847,11 @@ void PartPlate::calc_imex_ghosts() // non-primary gantry is represented by a single ghost — its column-paired rep — // so non-rep tools on aggregated gantries are skipped. This single source of // pairing truth keeps ghost emission and zone aggregation in lockstep. - int tpg = 1; + // 2 matches the value registered in PrintConfig.cpp:6643 and the fallback in + // compute_imex_zone_layout(). All three must agree: the zone rectangles come from the + // library, so a different grouping default here would pair tools against a grid that + // was divided differently. + int tpg = 2; if (auto* tpg_opt = wxGetApp().preset_bundle->printers.get_edited_preset() .config.option<ConfigOptionInt>("imex_tools_per_gantry")) tpg = std::max(1, tpg_opt->value); @@ -1306,7 +998,11 @@ void PartPlate::update_imex_ghost_transforms( // moves the ghost exactly as a rebuild would place it. See the note there: for an // aggregated gantry both X frames sit on the bed centerline, which zeroes gantry_offset.x // so the cross-gantry mirror tracks primary's X and reflects in Y. - int tpg = 1; + // 2 matches the value registered in PrintConfig.cpp:6643 and the fallback in + // compute_imex_zone_layout(). All three must agree: the zone rectangles come from the + // library, so a different grouping default here would pair tools against a grid that + // was divided differently. + int tpg = 2; if (auto* tpg_opt = wxGetApp().preset_bundle->printers.get_edited_preset() .config.option<ConfigOptionInt>("imex_tools_per_gantry")) tpg = std::max(1, tpg_opt->value); @@ -1533,20 +1229,15 @@ bool PartPlate::has_imex_multimaterial_conflict() const const std::string mode = get_imex_mode(); if (mode == kImexPrimaryMode) return false; - // Resolve the active mode's tools string from the printer config. - auto* names_opt = printer_cfg.option<ConfigOptionStrings>("imex_mode_names"); - auto* tools_opt = printer_cfg.option<ConfigOptionStrings>("imex_mode_active_tools"); auto* tpg_opt = printer_cfg.option<ConfigOptionInt>("imex_tools_per_gantry"); auto* pem_opt = printer_cfg.option<ConfigOptionInts>("physical_extruder_map"); - if (!names_opt || !tools_opt || !tpg_opt || !pem_opt) return false; + if (!tpg_opt || !pem_opt) return false; - std::string active_tools_str; - for (size_t i = 0; i < names_opt->values.size(); ++i) { - if (names_opt->values[i] == mode && i < tools_opt->values.size()) { - active_tools_str = tools_opt->values[i]; - break; - } - } + // Resolve the active mode's tools string from the printer config. Print::validate() + // resolves the same name the same way and keeps going on an empty result -- the mixed + // filament rule below does not depend on the roster -- so this must too, or the badge + // goes quiet on exactly the plates the slicer refuses. + const std::string active_tools_str = find_imex_mode(printer_cfg, mode).active_tools; // Convert PartPlate's 1-based extruder list to the 0-based form the helper expects. // @@ -4884,35 +4575,6 @@ void PartPlate::update_slice_result_valid_state(bool valid) m_plater->mark_plate_toolbar_image_dirty(); } -// IMEX firmware-managed zones: compute the plate-local primary-zone center and push it -// to m_print as the slice-time XY shift. Vec2d::Zero() in every non-firmware-managed -// path (flag off, primary/empty mode, empty zone box) → byte-identical gcode output for -// unaffected printers. Defensive accessors tolerate option() returning nullptr in case -// the preset bundle is reached during early Plater construction. -// Called both from update_slice_context (plate switch path) and from -// Plater::priv::update_background_process (every-slice path) so reslice with mode toggled -// without plate change picks up the right shift. -void PartPlate::refresh_imex_slice_offset() -{ - Vec2d imex_off = Vec2d::Zero(); - if (auto* app = &wxGetApp(); app && app->preset_bundle && m_print) { - const DynamicPrintConfig& printer_cfg = app->preset_bundle->printers.get_edited_preset().config; - auto* fw_opt = printer_cfg.option<ConfigOptionBool>("imex_firmware_managed_zones"); - if (fw_opt && fw_opt->value) { - std::string active_mode = get_imex_mode(); - if (active_mode == kImexPrimaryMode) { - const DynamicPrintConfig& process_cfg = app->preset_bundle->prints.get_edited_preset().config; - if (auto* mo = process_cfg.option<ConfigOptionString>("imex_parallel_mode")) - if (!mo->value.empty()) active_mode = mo->value; - } - ensure_imex_zones(); - imex_off = compute_imex_slice_offset(true, active_mode, m_imex_primary_zone_box); - } - } - if (m_print) - m_print->set_imex_slice_offset(imex_off); -} - //update current slice context into backgroud slicing process void PartPlate::update_slice_context(BackgroundSlicingProcess & process) { @@ -4926,8 +4588,6 @@ void PartPlate::update_slice_context(BackgroundSlicingProcess & process) wxQueueEvent(m_plater, event); }; - refresh_imex_slice_offset(); - process.set_fff_print(m_print); process.set_gcode_result(m_gcode_result); process.select_technology(this->printer_technology); diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index a5de5bbbd2..1477d59068 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -563,10 +563,6 @@ public: // Returns the primary-zone bounding box in mm when an IDEX/IQEX parallel mode is active. // Empty (nullopt) when IDEX/IQEX is off or the mode is "primary" (full-bed). std::optional<BoundingBoxf> imex_primary_zone() { ensure_imex_zones(); return m_imex_primary_zone_box; } - // Compute the IMEX firmware-managed slice offset and push it to m_print. Safe to call - // every slice. Sets Vec2d::Zero() when the printer flag is off, the mode is primary, or - // the preset bundle isn't ready yet. Must be called from the GUI thread. - void refresh_imex_slice_offset(); // Returns carriage collision strips (mm) for the current IDEX/IQEX mode. // Always call imex_primary_zone() first to ensure the cache is warm. const std::vector<BoundingBoxf3>& imex_collision_zones() const { return m_imex_collision_zones; } From f75bdd601344fdc1feeab90aca1e873730b79f8b Mon Sep 17 00:00:00 2001 From: Clifford Garwood <cliff@cigii.com> Date: Thu, 3 Sep 2026 00:56:26 -0400 Subject: [PATCH 40/51] Move the IMEX modes editor into its own file and fix four defects in it Closes review comments 21, 4 and 12, and the widget half of 19. - 21: IMEXModesCtrl was 572 lines inside Tab.cpp. It now lives in IMEXModesCtrl.{hpp,cpp} next to IMEXFilamentPickerPopover, which was the precedent named in the comment. The move itself is exact -- member order, comments and every string literal unchanged -- and the class had no file-local dependencies in Tab.cpp, only its include list, so the new source states those explicitly. - 4: a mode row with an empty Name was silently dropped on save, tools and G-code with it, and matches_config() compared against that same filtered output so the preset never went dirty and the row stayed on screen. Rows are now given a generated unique name instead of being discarded, and add_row() pre-fills one so the common path never produces a blank. Names are deliberately not translated: objects store a mode name in imex_parallel_mode and GCode.cpp matches it by string, so a localized name would break a project reopened in another language. - 12: the editor had a third parser that read a bare token and an unknown role suffix as Primary, while parse_imex_active_tools reads both as Copy -- so the editor and the slicer could read one imex_mode_active_tools string two different ways. Deleted; the editor now uses the same two helpers the slicer does. - 19: tile state was an int shadowing ImexRole, with the role letters duplicated in a second switch that wrote the on-disk format. The tile now holds optional<ImexRole>, with Inactive spelled as the absence of a role rather than a fifth integer, and the letters come from kImexRoleTable. Four further changes, from testing rather than the review: - Deleting a mode reported only the row's current name, so renaming a mode and then deleting it left every plate using it stranded on a name that no longer exists. Both the build-time and current names are now reported, minus any a surviving row still carries. - The instruction text and colour legend were built once in the constructor and never rebuilt, so raising gantry count to 2 gave the tiles a Span role the legend never explained until the preset was saved and the page reopened. Both are rebuilt with the grid, and the per-role detail moved into legend tooltips so the panel no longer opens with a paragraph. - The tile holding Primary is now read-only. Primary is tool 0 and moves only via Tool 0 Position; a click could previously demote the only Primary, leaving a mode that parses to no primary at all, which degrades the plate to an ordinary single-tool print with nothing in the editor showing what is wrong. A mode arriving without a Primary keeps every tile live so it can still be repaired. - Names and G-code were read with ToStdString() (the ANSI codepage on Windows) and written with from_u8() (UTF-8). On a non-UTF-8 codepage a name like "Modus A" with a diaeresis was stored as invalid UTF-8, came back blank, and was then silently renamed by the auto-naming above. Every read is now into_u8() and every write from_u8(); EditGCodeDialog was affected in both directions. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/IMEXModesCtrl.cpp | 697 +++++++++++++++++++++++++++++++ src/slic3r/GUI/IMEXModesCtrl.hpp | 242 +++++++++++ 3 files changed, 941 insertions(+) create mode 100644 src/slic3r/GUI/IMEXModesCtrl.cpp create mode 100644 src/slic3r/GUI/IMEXModesCtrl.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 5f31db9a54..835043ace4 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -274,6 +274,8 @@ set(SLIC3R_GUI_SOURCES GUI/IconManager.hpp GUI/IMEXFilamentPickerPopover.cpp GUI/IMEXFilamentPickerPopover.hpp + GUI/IMEXModesCtrl.cpp + GUI/IMEXModesCtrl.hpp GUI/ImageGrid.cpp GUI/ImageGrid.h GUI/ImGuiWrapper.cpp diff --git a/src/slic3r/GUI/IMEXModesCtrl.cpp b/src/slic3r/GUI/IMEXModesCtrl.cpp new file mode 100644 index 0000000000..f1a3570e97 --- /dev/null +++ b/src/slic3r/GUI/IMEXModesCtrl.cpp @@ -0,0 +1,697 @@ +#include "slic3r/GUI/IMEXModesCtrl.hpp" + +#include <wx/app.h> +#include <wx/font.h> +#include <wx/stattext.h> + +#include <algorithm> +#include <utility> + +#include "slic3r/GUI/EditGCodeDialog.hpp" +#include "slic3r/GUI/GUI.hpp" +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/I18N.hpp" +#include "slic3r/GUI/wxExtensions.hpp" + +namespace Slic3r { +namespace GUI { + +IMEXModesCtrl::IMEXModesCtrl(wxWindow* parent, int n_cols, int n_rows, int layout) + : wxPanel(parent, wxID_ANY), m_n_cols(std::max(1, n_cols)), m_n_rows(std::max(1, n_rows)), m_layout(layout) +{ + // Pull the app's window-default colour explicitly. Without this, GTK gives + // child wxPanels a slightly lighter "widget bg" instead of the app's dark + // theme — making chromeless ScalableButtons inside the panel render with a + // visible light box around the icon. Sub-panels inherit this colour. + SetBackgroundColour(wxGetApp().get_window_default_clr()); + + m_outer = new wxBoxSizer(wxVERTICAL); + m_rows_sizer = new wxBoxSizer(wxVERTICAL); + + // Info panel (instructions + legend) and the column-header row. Both depend on the grid + // shape, so their CONTENTS are (re)built by rebuild_info_and_header(), which set_grid_size() + // calls again whenever the grid changes. The panels themselves are stable so m_outer's + // ordering never has to be rearranged. + m_info_panel = new wxPanel(this, wxID_ANY); + m_info_panel->SetBackgroundColour(GetBackgroundColour()); + m_hdr_panel = new wxPanel(this, wxID_ANY); + m_hdr_panel->SetBackgroundColour(GetBackgroundColour()); + rebuild_info_and_header(); + + auto* add_btn = new wxButton(this, wxID_ANY, _L("+ Add Mode"), + wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + add_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { add_row(); notify(); }); + + m_outer->Add(m_info_panel, 0, wxEXPAND | wxBOTTOM, FromDIP(4)); + m_outer->Add(m_hdr_panel, 0, wxEXPAND | wxBOTTOM, FromDIP(2)); + m_outer->Add(m_rows_sizer, 0, wxEXPAND); + m_outer->AddSpacer(FromDIP(4)); + m_outer->Add(add_btn, 0); + // SetSizer(), not SetSizerAndFit(): no row exists yet, so there is nothing to fit to -- + // rows arrive from add_row() / load_from_config() / set_grid_size(). Deliberately NOT + // followed by m_outer->SetSizeHints(this) once they do: this panel owns a sizer, so + // wxWindow::GetBestSize() bypasses the best-size cache and re-runs m_outer->CalcMin() + // on every parent layout, and that is what the enclosing sizer already reserves space + // for via GetEffectiveMinSize(). An explicitly set min size takes PRIORITY over the best + // size in that call, so a size hint would pin the reserved height to the row count that + // happened to be on screen when it ran -- adding a mode after that would clip the bottom + // row and the "+ Add Mode" button, which is the very failure the hint is meant to avoid. + SetSizer(m_outer); +} + +void IMEXModesCtrl::rebuild_info_and_header() { + // --- Info panel: instruction text + colour legend --- + m_info_panel->DestroyChildren(); + auto* info_sizer = new wxBoxSizer(wxVERTICAL); + + // Keep this to one line. Per-role detail lives in the legend tooltips below, so the + // panel does not open with a paragraph the user has to read before touching anything. + const wxString instructions = + _L("Each mode names the tool heads that take part and the role each one plays. " + "Click a tool button to cycle its role — hover a colour below for what each role does."); + auto* inst = new wxStaticText(m_info_panel, wxID_ANY, instructions); + inst->Wrap(FromDIP(620)); + info_sizer->Add(inst, 0, wxBOTTOM, FromDIP(6)); + + // Color legend — swatches sized to the body text height so they read as + // matched pairs with their labels regardless of system DPI / font scale, + // matching the on-hover ghost tooltip swatch's visual weight. + // One entry per role this printer offers, in kImexRoleTable order — the same order the + // tiles cycle in. A role added to that table appears here with no edit of its own. + auto* leg_sizer = new wxBoxSizer(wxHORIZONTAL); + const int swatch_side = m_info_panel->GetCharHeight(); + for (const ImexRoleDesc& d : kImexRoleTable) { + if (!role_offered(d.role)) continue; + const RoleStyle style = role_style(d.role); + auto* swatch = new wxPanel(m_info_panel, wxID_ANY, wxDefaultPosition, wxSize(swatch_side, swatch_side)); + swatch->SetBackgroundColour(style.bg); + auto* leg_label = new wxStaticText(m_info_panel, wxID_ANY, style.label); + const wxString hint = role_hint(d.role); + swatch->SetToolTip(hint); + leg_label->SetToolTip(hint); + leg_sizer->Add(swatch, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(4)); + leg_sizer->Add(leg_label, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(16)); + } + info_sizer->Add(leg_sizer, 0, wxBOTTOM, FromDIP(6)); + m_info_panel->SetSizerAndFit(info_sizer); + + // --- Column header row --- + // Spacers sized to align with the mode-row fields below. Name field: FromDIP(130) + FromDIP(6) + // gap; tool grid: n_cols*(FromDIP(36)+FromDIP(2))-FromDIP(2) + FromDIP(6) gap. grid_px tracks + // the live column count, so the G-code header stays aligned after a grid change. + m_hdr_panel->DestroyChildren(); + auto* hdr_sizer = new wxBoxSizer(wxHORIZONTAL); + auto* hdr_name = new wxStaticText(m_hdr_panel, wxID_ANY, _L("Name")); + auto* hdr_tools = new wxStaticText(m_hdr_panel, wxID_ANY, _L("Tools")); + auto* hdr_gcode = new wxStaticText(m_hdr_panel, wxID_ANY, _L("G-code")); + hdr_name->SetToolTip(_L("How the mode is labelled in the plate's IMEX mode selector. " + "Required — a mode with no name cannot be selected.")); + hdr_tools->SetToolTip(_L("Which tool heads take part in the mode and what role each one plays. " + "Click a tile to cycle its role.")); + hdr_gcode->SetToolTip(_L("G-code run at print start to put the printer into this mode " + "(for example a Klipper SET_PRINT_MODE call). The slicer only emits " + "the Primary tool's paths; the firmware drives the others.")); + const int grid_px = m_n_cols * FromDIP(38) - FromDIP(2); // approx grid panel width + const int name_col_px = FromDIP(136); + hdr_sizer->Add(hdr_name, 0, wxALIGN_CENTER_VERTICAL); + hdr_sizer->AddSpacer(std::max(0, name_col_px - hdr_name->GetBestSize().x)); + hdr_sizer->Add(hdr_tools, 0, wxALIGN_CENTER_VERTICAL); + hdr_sizer->AddSpacer(std::max(0, grid_px + FromDIP(6) - hdr_tools->GetBestSize().x)); + hdr_sizer->Add(hdr_gcode, 1, wxALIGN_CENTER_VERTICAL); + m_hdr_panel->SetSizerAndFit(hdr_sizer); +} + +void IMEXModesCtrl::set_grid_size(int n_cols, int n_rows, int layout) { + n_cols = std::max(1, n_cols); + n_rows = std::max(1, n_rows); + if (layout < 0) layout = m_layout; + if (n_cols == m_n_cols && n_rows == m_n_rows && layout == m_layout) return; + auto [names, tools, gcodes] = get_mode_data(); + clear_rows(); + m_n_cols = n_cols; + m_n_rows = n_rows; + m_layout = layout; + // Span becomes available the moment a second gantry exists, and the header spacing tracks the + // column count -- so the legend and headers are rebuilt here rather than only at construction. + // Without this, adding a gantry gives the tiles a Span role the legend never explains until + // the preset is saved and the page reopened. + rebuild_info_and_header(); + for (size_t i = 0; i < names.size(); ++i) + add_row(names[i], tools[i], gcodes[i], /*is_primary=*/(names[i] == kImexPrimaryMode)); + Layout(); +} + +void IMEXModesCtrl::load_from_config(const DynamicPrintConfig& cfg) { + clear_rows(); + // One ImexMode per row of imex_mode_names, with any sibling array too short for a row + // padded to an empty string -- exactly what the three per-index bounds checks this + // replaced were doing, now in one place shared with every other IMEX consumer. + const std::vector<ImexMode> table = imex_mode_table(cfg); + + // Primary row is always first and non-deletable. Look for an existing + // "primary" entry in the config (present in configs saved after #8 was + // implemented); fall back to empty tool/gcode for older configs. + const ImexMode primary = find_imex_mode(cfg, kImexPrimaryMode); + add_row(kImexPrimaryMode, primary.active_tools, primary.gcode, /*is_primary=*/true); + + for (const ImexMode& m : table) { + if (m.index == primary.index) continue; // already added above + add_row(m.name, m.active_tools, m.gcode); + } + refresh_reset_buttons(); + Layout(); +} + +std::tuple<std::vector<std::string>, std::vector<std::string>, std::vector<std::string>> +IMEXModesCtrl::get_mode_data() const { + std::vector<std::string> names, tools, gcodes; + for (auto& r : m_rows) { + // into_u8(), not ToStdString(): everything downstream of here -- the preset, the 3MF + // metadata, the plate's stored mode name -- is UTF-8, while ToStdString() encodes + // through wxConvLibc, which on Windows is the ANSI codepage. The two agree only on a + // UTF-8 locale, so mixing them turns a non-ASCII mode name into mojibake (or an empty + // field, once from_u8() rejects it) on the round trip through the preset. + std::string nm = r.is_primary ? std::string(kImexPrimaryMode) : into_u8(r.name->GetValue()); + if (nm.empty()) nm = unique_mode_name(names); + names.push_back(nm); + tools.push_back(active_tools_string(r)); + gcodes.push_back(into_u8(r.gcode->GetValue())); + } + return {names, tools, gcodes}; +} + +bool IMEXModesCtrl::matches_config(const DynamicPrintConfig& cfg) const { + auto [names, tools, gcodes] = get_mode_data(); + auto cfg_strings = [&cfg](const char* key) { + std::vector<std::string> v; + if (auto* o = cfg.option<ConfigOptionStrings>(key)) v = o->values; + return v; + }; + return names == cfg_strings("imex_mode_names") + && tools == cfg_strings("imex_mode_active_tools") + && gcodes == cfg_strings("imex_mode_gcodes"); +} + +std::map<int, ImexRole> IMEXModesCtrl::roles_for_mode(const std::string& active_tools) { + std::map<int, ImexRole> roles; + for (const auto& [phys, role] : parse_imex_active_tools(active_tools)) + roles[phys] = role; + // Promote the mode's primary, but never invent a tool that isn't in the + // slicer's own active-tool list: parse_imex_active_tools() drops negative and + // out-of-range indices, imex_primary_tool_for_mode() does not range-check the + // upper bound, and a junk index round-tripped back out on save would be a + // token the slicer ignores. + const int primary = imex_primary_tool_for_mode(active_tools); + if (primary >= 0) { + auto it = roles.find(primary); + if (it != roles.end()) + it->second = ImexRole::Primary; + } + return roles; +} + +std::string IMEXModesCtrl::unique_mode_name(const std::vector<std::string>& also_taken) const { + auto is_taken = [&](const std::string& cand) { + if (std::find(also_taken.begin(), also_taken.end(), cand) != also_taken.end()) + return true; + for (const auto& r : m_rows) + if (!r.is_primary && r.name && into_u8(r.name->GetValue()) == cand) + return true; + return false; + }; + for (int n = 2; ; ++n) { + std::string cand = "Mode " + std::to_string(n); + if (!is_taken(cand)) + return cand; + } +} + +IMEXModesCtrl::RoleStyle IMEXModesCtrl::role_style(std::optional<ImexRole> role) { + // Grey / "Inactive" is the no-role answer; every role gets an explicit case so a new + // one is a compile-time -Wswitch prompt rather than a tile that silently renders grey. + if (!role) + return { wxColour(90, 90, 90), *wxWHITE, "Inactive" }; + switch (*role) { + case ImexRole::Primary: return { wxColour(50, 160, 50), *wxWHITE, "Primary" }; // green + case ImexRole::Copy: return { wxColour(60, 120, 210), *wxWHITE, "Copy" }; // blue + case ImexRole::Mirror: return { wxColour(210, 130, 20), *wxWHITE, "Mirror" }; // amber + case ImexRole::Span: return { wxColour(180, 180, 40), *wxWHITE, "Span" }; // yellow + } + return { wxColour(90, 90, 90), *wxWHITE, "Inactive" }; // keeps every compiler quiet +} + +wxString IMEXModesCtrl::role_hint(ImexRole role) { + switch (role) { + case ImexRole::Primary: + return _L("Drives every sliced path. Always tool 0 — use Tool 0 Position above to choose " + "which corner of the bed it occupies. It cannot be moved from the grid."); + case ImexRole::Copy: + return _L("Follows the Primary at the firmware level, printing the same paths offset into " + "its own zone."); + case ImexRole::Mirror: + return _L("Follows the Primary at the firmware level, printing the same paths reflected " + "across the boundary between the two zones."); + case ImexRole::Span: + return _L("Marks a tool on the Primary's gantry as its multicolor partner. Required to " + "allow multi-color printing in paired-gantry modes."); + } + return wxEmptyString; +} + +bool IMEXModesCtrl::role_offered(ImexRole role) const { + // Span declares a within-gantry multicolor partner of the Primary, which only means + // something when there is a second gantry running in parallel with it. + if (role == ImexRole::Span) + return m_n_rows >= 2; + return true; +} + +bool IMEXModesCtrl::role_allowed_on_tile(ImexRole role, int tool_idx, + bool other_primary, int primary_gantry) const { + if (!role_offered(role)) + return false; + // Exactly one tile drives the sliced paths. + if (role == ImexRole::Primary) + return !other_primary; + // Span only on a tile sharing the Primary's gantry — that is what the marker declares. + if (role == ImexRole::Span) + return primary_gantry >= 0 && (tool_idx / m_n_cols) == primary_gantry; + return true; +} + +std::optional<ImexRole> IMEXModesCtrl::next_tile_role(std::optional<ImexRole> current, + const std::function<bool(ImexRole)>& allowed) { + const int n = (int)(sizeof(kImexRoleTable) / sizeof(kImexRoleTable[0])); + int start = 0; // no current role (Inactive) → start at the first role + if (current) { + for (int i = 0; i < n; ++i) + if (kImexRoleTable[i].role == *current) { start = i + 1; break; } + } + for (int i = start; i < n; ++i) + if (allowed(kImexRoleTable[i].role)) + return kImexRoleTable[i].role; + return std::nullopt; // walked off the end → back to Inactive +} + +void IMEXModesCtrl::apply_btn(wxButton* btn, int tool_idx, std::optional<ImexRole> role) { + // Always label as T{n} — the button color already encodes the role. + const RoleStyle style = role_style(role); + btn->SetLabel(wxString::Format("T%d", tool_idx)); + btn->SetBackgroundColour(style.bg); + btn->SetForegroundColour(style.fg); + btn->Refresh(); +} + +IMEXModesCtrl::RowSnapshot IMEXModesCtrl::snapshot_row(const Row& r) const { + RowSnapshot s; + // UTF-8 throughout -- this snapshot is compared against the preset's own values. + s.name = r.is_primary ? std::string(kImexPrimaryMode) : into_u8(r.name->GetValue()); + s.tools = active_tools_string(r); + s.gcode = into_u8(r.gcode->GetValue()); + return s; +} + +bool IMEXModesCtrl::row_differs_from_parent(int row_idx) const { + if (!m_parent_lookup) return false; + const DynamicPrintConfig* parent = m_parent_lookup(); + if (!parent) return false; + auto* p_names = parent->option<ConfigOptionStrings>("imex_mode_names"); + auto* p_tools = parent->option<ConfigOptionStrings>("imex_mode_active_tools"); + auto* p_gcodes = parent->option<ConfigOptionStrings>("imex_mode_gcodes"); + if (!p_names || row_idx < 0 || row_idx >= (int)p_names->values.size()) return false; + const Row& r = m_rows[row_idx]; + const RowSnapshot s = snapshot_row(r); + if (!r.is_primary && s.name != p_names->values[row_idx]) return true; + if (p_tools && row_idx < (int)p_tools->values.size() && s.tools != p_tools->values[row_idx]) return true; + if (p_gcodes && row_idx < (int)p_gcodes->values.size() && s.gcode != p_gcodes->values[row_idx]) return true; + return false; +} + +bool IMEXModesCtrl::row_has_parent_counterpart(int row_idx) const { + if (!m_parent_lookup) return false; + const DynamicPrintConfig* parent = m_parent_lookup(); + if (!parent) return false; + auto* p_names = parent->option<ConfigOptionStrings>("imex_mode_names"); + return p_names && row_idx >= 0 && row_idx < (int)p_names->values.size(); +} + +void IMEXModesCtrl::add_row(const std::string& name, + const std::string& active_tools, + const std::string& gcode, + bool is_primary) +{ + Row r; + r.is_primary = is_primary; + r.panel = new wxPanel(this, wxID_ANY); + r.panel->SetBackgroundColour(GetBackgroundColour()); + auto* sizer = new wxBoxSizer(wxHORIZONTAL); + + if (is_primary) { + r.orig_name = kImexPrimaryMode; + r.name = nullptr; + auto* lbl = new wxStaticText(r.panel, wxID_ANY, _L("Primary"), + wxDefaultPosition, FromDIP(wxSize(130, -1))); + wxFont f = lbl->GetFont(); + f.SetWeight(wxFONTWEIGHT_BOLD); + lbl->SetFont(f); + sizer->Add(lbl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(6)); + } else { + // A nameless mode cannot be selected on a plate and used to be dropped on + // save together with its tool roles and G-code, so a name is pre-filled + // here and restored below if the field is left empty. That keeps the + // "+ Add Mode → assign tools → never typed a name" path from losing work + // without ever showing an error. + const std::string nm = name.empty() ? unique_mode_name({}) : name; + // The name as first shown, i.e. the one the plate's mode selector offered while this + // row looked like this. remove_row() reports it alongside the current name, because + // renaming is not routed through on_mode_removed and the two then diverge. + r.orig_name = nm; + r.name = new wxTextCtrl(r.panel, wxID_ANY, from_u8(nm), wxDefaultPosition, FromDIP(wxSize(130, -1))); + r.name->SetHint(_L("Mode name (required)")); + r.name->SetToolTip(_L("Name of this parallel mode, as it appears in the plate's IMEX mode " + "selector. Stored in the project by name, so renaming a mode that " + "plates already use makes them fall back to Primary. Cannot be empty " + "— a blank name is replaced with a generated one.")); + r.name->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { notify(); }); + // Restore a name rather than let the row reach get_mode_data() unnamed. + // Row is located by panel pointer (stable across add/remove) so a + // kill-focus delivered while the rows are being torn down is a no-op. + r.name->Bind(wxEVT_KILL_FOCUS, [this, panel = r.panel](wxFocusEvent& e) { + e.Skip(); + if (m_clearing_rows) return; // focus-out emitted while the rows are being deleted + for (auto& row_ref : m_rows) { + if (row_ref.panel != panel) continue; + if (!row_ref.name || !row_ref.name->GetValue().empty()) return; + // ChangeValue(), not SetValue(): no nested wxEVT_TEXT. + row_ref.name->ChangeValue(from_u8(unique_mode_name({}))); + notify(); + return; + } + }); + } + + auto* grid_panel = new wxPanel(r.panel, wxID_ANY); + grid_panel->SetBackgroundColour(GetBackgroundColour()); + auto* grid_sizer = new wxGridSizer(m_n_rows, m_n_cols, FromDIP(2), FromDIP(2)); + + auto tool_roles = roles_for_mode(active_tools); + if (tool_roles.empty()) + tool_roles[0] = ImexRole::Primary; // default T0 → Primary when no assignment is stored + r.all_tool_roles = tool_roles; // preserve all assignments, including off-screen tools + wxPanel* this_panel = r.panel; + + // Buttons rendered top=rear (high Y), bottom=front (low Y). + // Layout remapping: m_layout encodes which corner T0 is at physically. + // flip_x (layout 1,3): col 0 is on the right (max-X) instead of left + // flip_y (layout 2,3): row 0 is at the rear (max-Y) instead of front + // Display iterates: row from n_rows-1 down to 0 (rear→front = top→bottom). + // raw_row = flip_y ? (n_rows-1-row) : row + // raw_col = flip_x ? (n_cols-1-col) : col + // + // row_start: anchor displayed rows to the gantry row containing the Primary + // assignment, so reducing gantry count keeps the meaningful row visible. + int primary_gantry_row = 0; + for (const auto& [idx, role] : tool_roles) { + if (role == ImexRole::Primary) { primary_gantry_row = idx / m_n_cols; break; } + } + int row_start = primary_gantry_row; // display rows [row_start .. row_start+m_n_rows-1] + + bool flip_x = (m_layout == 1 || m_layout == 3); + bool flip_y = (m_layout == 2 || m_layout == 3); + for (int row = m_n_rows - 1; row >= 0; --row) { + for (int col = 0; col < m_n_cols; ++col) { + int raw_row = flip_y ? (m_n_rows - 1 - row) : row; + raw_row += row_start; // anchor to Primary's gantry row + int raw_col = flip_x ? (m_n_cols - 1 - col) : col; + int tool_idx = raw_row * m_n_cols + raw_col; + std::optional<ImexRole> role; // nullopt == Inactive + auto it = tool_roles.find(tool_idx); + if (it != tool_roles.end()) role = it->second; + + auto* btn = new wxButton(grid_panel, wxID_ANY, wxEmptyString, + wxDefaultPosition, FromDIP(wxSize(36, 26)), wxBU_EXACTFIT); + apply_btn(btn, tool_idx, role); + + int btn_pos = (int)r.btns.size(); + r.btns.push_back(btn); + r.btn_roles.push_back(role); + r.btn_tool_idx.push_back(tool_idx); + + // Two tiles are read-only. + // + // The whole reserved `primary` row: it is the IMEX-off mode, so cycling roles there + // would be a no-op and confusing. + // + // And, on any row, the tile that currently HOLDS Primary. Primary is tool 0 and moves + // only via Tool 0 Position; letting a click demote it would leave the mode with no + // Primary at all, which parses to -1 and degrades the plate to an ordinary single-tool + // print with no zones — authored silently, in one click, with nothing in the editor + // showing what is wrong. The other tiles already never OFFER Primary while one is held + // (role_allowed_on_tile), so this closes the only remaining route to that state. + // A mode that reaches us WITHOUT a Primary (hand-edited preset, foreign 3MF) still has + // every tile live, so it can be repaired by promoting one. + if (is_primary || role == ImexRole::Primary) { + btn->Disable(); + } else { + btn->Bind(wxEVT_BUTTON, [this, this_panel, btn_pos](wxCommandEvent&) { + // Find the row by panel pointer (stable across add/remove) + for (auto& row_ref : m_rows) { + if (row_ref.panel != this_panel) continue; + std::optional<ImexRole>& tile = row_ref.btn_roles[btn_pos]; + const int tidx = row_ref.btn_tool_idx[btn_pos]; + + // Check if another button already holds the Primary role, + // and locate the primary's gantry row for Span eligibility. + bool other_primary = false; + int primary_gantry = -1; + for (int j = 0; j < (int)row_ref.btn_roles.size(); ++j) { + if (row_ref.btn_roles[j] == ImexRole::Primary) { + if (j != btn_pos) other_primary = true; + primary_gantry = row_ref.btn_tool_idx[j] / m_n_cols; + } + } + + // Cycle Inactive → Primary → Copy → Mirror → Span → Inactive, + // skipping whatever this tile may not take right now. + tile = next_tile_role(tile, [&](ImexRole cand) { + return role_allowed_on_tile(cand, tidx, other_primary, primary_gantry); + }); + + // Keep all_tool_roles in sync so off-screen tools are preserved + if (tile) + row_ref.all_tool_roles[tidx] = *tile; + else + row_ref.all_tool_roles.erase(tidx); + + apply_btn(row_ref.btns[btn_pos], row_ref.btn_tool_idx[btn_pos], tile); + notify(); + break; + } + }); + } + + grid_sizer->Add(btn, 0); + } + } + grid_panel->SetSizerAndFit(grid_sizer); + + // from_u8(): `gcode` arrives from the preset as UTF-8. Handing the raw std::string to + // wxString would decode it through the current locale's encoding instead. + r.gcode = new wxTextCtrl(r.panel, wxID_ANY, from_u8(gcode), + wxDefaultPosition, FromDIP(wxSize(220, 54)), wxTE_MULTILINE); + // Tooltip only, no SetHint(): wxTextEntry has no native placeholder for a + // multiline control, so wxWidgets emulates one by writing the hint into the + // control as grey text — indistinguishable from real G-code in this box. + r.gcode->SetToolTip(_L("G-code emitted once at the start of a print that uses this mode, before " + "the machine start G-code. This is where the printer is put into the " + "matching firmware mode — for example a Klipper SET_PRINT_MODE call or a " + "RepRapFirmware M567 — since the slicer only emits the Primary tool's " + "paths and the firmware drives the Copy / Mirror tools. Placeholders are " + "supported; use the edit button to browse them. Leave empty if the mode " + "needs no firmware setup.")); + r.gcode->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { notify(); }); + + if (!is_primary) { + sizer->Add(r.name, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(6)); + } + sizer->Add(grid_panel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(6)); + sizer->Add(r.gcode, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(4)); + + // Edit + remove (for non-primary) — stacked vertically. + auto* btn_col = new wxBoxSizer(wxVERTICAL); + wxTextCtrl* gcode_ctrl = r.gcode; + auto* ph_btn = new ScalableButton(r.panel, wxID_ANY, "edit", wxEmptyString, + wxDefaultSize, wxDefaultPosition, + wxBU_EXACTFIT | wxNO_BORDER, 16); + ph_btn->SetToolTip(_L("Edit G-code / browse placeholders")); + ph_btn->Bind(wxEVT_BUTTON, [this, gcode_ctrl](wxCommandEvent&) { + // EditGCodeDialog takes and returns UTF-8 (get_edited_gcode() is a ToUTF8()). + EditGCodeDialog dlg(this, "imex_mode_gcode", into_u8(gcode_ctrl->GetValue())); + if (dlg.ShowModal() == wxID_OK) + gcode_ctrl->SetValue(from_u8(dlg.get_edited_gcode())); + }); + btn_col->Add(ph_btn, 0, wxBOTTOM, FromDIP(2)); + + if (!is_primary) { + auto* rm = new ScalableButton(r.panel, wxID_ANY, "imex_remove", wxEmptyString, + wxDefaultSize, wxDefaultPosition, + wxBU_EXACTFIT | wxNO_BORDER, 16); + rm->SetToolTip(_L("Remove mode")); + rm->Bind(wxEVT_BUTTON, [this, this_panel](wxCommandEvent&) { + const std::vector<std::string> removed = remove_row(this_panel); + // Copied before notify(): on_change ends in on_value_change, which can send + // the tab through update() and hence load_from_config(), and that rebuilds + // every row. Reading the member afterwards would be reading through a + // handler whose owner has just been rebuilt underneath it. + auto removed_cb = on_mode_removed; + notify(); + if (removed_cb && !removed.empty()) + removed_cb(removed); + }); + btn_col->Add(rm, 0); + } + sizer->Add(btn_col, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(4)); + + // Per-row reset gets its own column on the right so the icon reads as + // distinct from the edit/remove column. Reset only renders when this row + // has a counterpart in the saved preset (user-added rows beyond the saved + // mode count get no reset — the X button covers "remove user-added row"). + auto* reset_col = new wxBoxSizer(wxVERTICAL); + wxPanel* this_panel_for_reset = r.panel; + if (row_has_parent_counterpart(static_cast<int>(m_rows.size()))) { + r.reset_btn = new ScalableButton(r.panel, wxID_ANY, "dot", wxEmptyString, + wxDefaultSize, wxDefaultPosition, + wxBU_EXACTFIT | wxNO_BORDER, 16); + r.reset_btn->SetToolTip(_L("Discard in-session edits to this mode (snap back to saved value)")); + r.reset_btn->Bind(wxEVT_BUTTON, [this, this_panel_for_reset](wxCommandEvent&) { + reset_row_to_parent(this_panel_for_reset); + }); + reset_col->Add(r.reset_btn, 0, wxALIGN_CENTER_VERTICAL); + } + sizer->Add(reset_col, 0, wxALIGN_CENTER_VERTICAL); + r.panel->SetSizerAndFit(sizer); + + m_rows_sizer->Add(r.panel, 0, wxEXPAND | wxBOTTOM, FromDIP(4)); + m_rows.push_back(std::move(r)); + Layout(); +} + +std::vector<std::string> IMEXModesCtrl::remove_row(wxPanel* panel) { + for (size_t i = 0; i < m_rows.size(); ++i) { + if (m_rows[i].panel != panel) continue; + if (m_rows[i].is_primary) return {}; // primary row is non-deletable + + // Both names a plate can be holding for this row: the one the row was built with and + // the one in the field now. They diverge as soon as the row is renamed, because a + // rename does not rebuild the row and is deliberately not reported as a removal (the + // name field notifies on every keystroke). Reporting only the current name is what + // let "rename, then delete" leave the plate on a mode that no longer exists. + std::vector<std::string> removed_names; + const std::string current = m_rows[i].name ? into_u8(m_rows[i].name->GetValue()) + : std::string(); + for (const std::string& n : {m_rows[i].orig_name, current}) + if (!n.empty() && std::find(removed_names.begin(), removed_names.end(), n) == removed_names.end()) + removed_names.push_back(n); + + m_rows_sizer->Detach(panel); + m_rows.erase(m_rows.begin() + i); + + // A name a surviving row still carries is not stale: the user can rename row A to + // row B's old name and then delete B. Plates holding it now resolve to A, so drop it + // rather than reset them. + auto still_in_use = [this](const std::string& n) { + return std::any_of(m_rows.begin(), m_rows.end(), [&n](const Row& r) { + return r.is_primary ? n == kImexPrimaryMode + : r.name && into_u8(r.name->GetValue()) == n; + }); + }; + removed_names.erase(std::remove_if(removed_names.begin(), removed_names.end(), still_in_use), + removed_names.end()); + + Layout(); + // Defer widget destruction so any in-flight GTK events for + // panel's children (including the × button we're inside) finish + // processing before the wxEvtHandlers are freed. + wxTheApp->CallAfter([panel]() { panel->Destroy(); }); + return removed_names; + } + return {}; +} + +void IMEXModesCtrl::clear_rows() { + // Destroying a focused wxTextCtrl emits wxEVT_KILL_FOCUS, and the Name field's + // handler would then read m_rows while it is half-destroyed. Flag the teardown + // so that handler stays out of the way. + m_clearing_rows = true; + for (auto& r : m_rows) { m_rows_sizer->Detach(r.panel); r.panel->Destroy(); } + m_rows.clear(); + m_clearing_rows = false; +} + +std::string IMEXModesCtrl::active_tools_string(const Row& r) const { + // Serialize from all_tool_roles (not just visible buttons) so assignments + // for off-screen tools are preserved across grid size changes. Inactive tools are + // simply absent from the map, so there is nothing to filter out here. + // + // The letters come from imex_role_letter(), the same table parse_imex_active_tools() + // reads back — this used to be a second, independent int → letter switch, which is + // exactly where the editor and the slicer could come to disagree about a mode string. + std::string s; + for (const auto& [idx, role] : r.all_tool_roles) { + if (!s.empty()) s += ','; + s += std::to_string(idx) + ':' + imex_role_letter(role); + } + return s; +} + +void IMEXModesCtrl::notify() { + refresh_reset_buttons(); + if (on_change) on_change(); +} + +void IMEXModesCtrl::refresh_reset_buttons() { + for (size_t i = 0; i < m_rows.size(); ++i) { + Row& r = m_rows[i]; + if (!r.reset_btn || !r.reset_btn->IsEnabled()) continue; + const bool dirty = row_differs_from_parent(static_cast<int>(i)); + if (dirty == r.reset_dirty_cached) continue; + r.reset_dirty_cached = dirty; + r.reset_btn->SetBitmap_(dirty ? "undo" : "dot"); + } +} + +void IMEXModesCtrl::reset_row_to_parent(wxPanel* panel) { + if (!m_parent_lookup) return; + const DynamicPrintConfig* parent = m_parent_lookup(); + if (!parent) return; + auto* p_names = parent->option<ConfigOptionStrings>("imex_mode_names"); + auto* p_tools = parent->option<ConfigOptionStrings>("imex_mode_active_tools"); + auto* p_gcodes = parent->option<ConfigOptionStrings>("imex_mode_gcodes"); + for (size_t i = 0; i < m_rows.size(); ++i) { + Row& r = m_rows[i]; + if (r.panel != panel) continue; + if (!p_names || i >= p_names->values.size()) return; + if (!r.is_primary && r.name) + r.name->ChangeValue(from_u8(p_names->values[i])); + if (p_gcodes && i < p_gcodes->values.size()) + r.gcode->ChangeValue(from_u8(p_gcodes->values[i])); + if (p_tools && i < p_tools->values.size()) { + // Reapply tool roles from the parent's serialized form. all_tool_roles + // is the source of truth for round-tripping; rebuild it then re-paint + // the visible buttons. + r.all_tool_roles = roles_for_mode(p_tools->values[i]); + for (size_t j = 0; j < r.btns.size(); ++j) { + int tidx = r.btn_tool_idx[j]; + auto it = r.all_tool_roles.find(tidx); + std::optional<ImexRole> role; + if (it != r.all_tool_roles.end()) role = it->second; + r.btn_roles[j] = role; + apply_btn(r.btns[j], tidx, role); + } + } + notify(); + return; + } +} + +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/IMEXModesCtrl.hpp b/src/slic3r/GUI/IMEXModesCtrl.hpp new file mode 100644 index 0000000000..f449843ebd --- /dev/null +++ b/src/slic3r/GUI/IMEXModesCtrl.hpp @@ -0,0 +1,242 @@ +#ifndef slic3r_IMEXModesCtrl_hpp_ +#define slic3r_IMEXModesCtrl_hpp_ + +#include <wx/panel.h> +#include <wx/string.h> +#include <wx/sizer.h> +#include <wx/button.h> +#include <wx/textctrl.h> + +#include <functional> +#include <map> +#include <optional> +#include <string> +#include <tuple> +#include <vector> + +#include "libslic3r/IMEXHelpers.hpp" + +class ScalableButton; + +namespace Slic3r { +namespace GUI { + +// --------------------------------------------------------------------------- +// IMEXModesCtrl — visual parallel-mode editor for the IDEX/IQEX printer tab +// +// A tool tile holds an `std::optional<ImexRole>`: the role the mode gives that tool, or +// nullopt for Inactive (grey — the tool does not take part in this mode). Inactive is the +// editor's own state and the only reason the tile is not a bare ImexRole; it is the absence +// of a role, so it is spelled as one rather than as an extra enumerator that libslic3r would +// then have to keep rejecting. Roles themselves are never re-encoded here — no int state +// table, no second copy of the on-disk letters. +// +// nullopt (grey) — not participating in this mode +// ImexRole::Primary (green) — the tool the slicer generates paths for +// ImexRole::Copy (blue) — firmware duplicates Primary at an offset +// ImexRole::Mirror (amber) — firmware mirrors Primary about an axis +// ImexRole::Span (yellow)— multicolor partner of Primary on the same gantry; +// declares paired-gantry multicolor topology and +// unlocks the multicolor block at slice time. Only +// offered on tools sharing primary's gantry, and +// only on multi-gantry printers (n_rows >= 2). +// +// Colour and legend text are the editor's business and live in role_style(); the tile cycle +// order and the serialized letters come from kImexRoleTable in IMEXHelpers.hpp, so the +// editor cannot drift from the slicer's reading of a mode string. +// +// Active-tools string format: "idx:P,idx:C,idx:M,idx:S" (backwards-compat: plain "idx" = Primary) +// --------------------------------------------------------------------------- +class IMEXModesCtrl : public wxPanel { +public: + std::function<void()> on_change; + + // Fired after on_change has written the shortened table back to the preset, with EVERY + // name the deleted row could be known by: the name the row was built with (what a plate + // set from the saved preset holds) and the name in the field at delete time (what a plate + // set after an in-session rename holds). Renaming is deliberately not routed through here + // -- the name field notifies on every keystroke -- so by the time the row is deleted the + // two can differ, and reporting only the current name leaves the plate pointing at a mode + // that no longer exists. Names a surviving row still carries are filtered out, so renaming + // one row to another's old name and then deleting cannot reset a plate that legitimately + // resolves elsewhere. Plates still set to any reported name are stale from this point on + // -- see the handler in TabPrinter::build_fff. + std::function<void(const std::vector<std::string>&)> on_mode_removed; + + // Lazy lookup so the widget always sees the current parent (preset switches + // change the parent under us). Returns nullptr when the active preset has no + // parent (system preset itself), which disables per-row reset arrows. + using ParentConfigLookup = std::function<const DynamicPrintConfig*()>; + void set_parent_config_lookup(ParentConfigLookup f) { m_parent_lookup = std::move(f); } + + // layout: 0=front-left, 1=front-right, 2=rear-left, 3=rear-right (T0 corner). + // The enum values intentionally line up 1:1 so this is a no-op cast — the helper + // is kept to make the conversion explicit at call sites. + static int parse_layout(ImexToolLayout layout) { return static_cast<int>(layout); } + + IMEXModesCtrl(wxWindow* parent, int n_cols, int n_rows, int layout = 0); + + void set_grid_size(int n_cols, int n_rows, int layout = -1); + + void load_from_config(const DynamicPrintConfig& cfg); + + // Every row on screen produces exactly one entry — a row is never skipped. + // Skipping empty-named rows used to drop the row's tool roles and G-code + // silently, and because matches_config() compares against this same filtered + // output the preset did not even go dirty to hint that something had gone + // missing; the row stayed on screen until the next load_from_config() quietly + // removed it. add_row() pre-fills a name and the Name field restores one when + // it is left empty, so the substitution below is the last-resort guard for a + // name that arrives empty from a hand-edited preset or 3MF. + std::tuple<std::vector<std::string>, std::vector<std::string>, std::vector<std::string>> + get_mode_data() const; + + // True when the widget's current rows already mirror the three IMEX-mode option + // vectors in cfg. Used by TabPrinter::update_fff() to skip a destroy-and-rebuild + // pass when the only thing that just changed was the widget itself writing back + // to config — without this guard, every keystroke in the gcode textbox triggers + // a load_from_config() that detaches the textbox the user is typing in. + bool matches_config(const DynamicPrintConfig& cfg) const; + +private: + // map<physical tool idx, role> for one `imex_mode_active_tools` entry. A tool absent + // from the map is Inactive — the same convention the serialized string uses, so the + // round trip needs no separate "off" value. + // + // Deliberately NOT a parser of its own: the slicer decides what actually prints, + // so the editor has to read the string exactly the way the slicer does or the + // same mode means two different things in the two places. Roles come from + // parse_imex_active_tools(); the primary index comes from + // imex_primary_tool_for_mode(), which is where the "a bare index is Primary" + // backwards-compat rule lives. Both are needed: parse_imex_active_tools() + // defaults a bare token to Copy (deliberately — see the note above + // parse_imex_active_tools() in IMEXHelpers.hpp), so only the combination + // reproduces the slicer's reading of a legacy "0,1,2" string, which is + // "T0 primary, the rest copies". + // + // Indices are PHYSICAL tool indices (T0..TN-1). all_tool_roles preserves + // off-grid entries so the tile widget can round-trip indices that fall + // outside the currently visible rows × cols without losing data on save. + static std::map<int, ImexRole> roles_for_mode(const std::string& active_tools); + + // "Mode N" for the lowest N >= 2 not already used by a row or by `also_taken` + // (N == 1 is conceptually the fixed Primary row). Deterministic for a given set + // of rows, so get_mode_data() is stable across calls and matches_config() stays + // honest. Intentionally NOT translated: mode names are identifiers — objects + // store one in `imex_parallel_mode` and GCode.cpp matches it against + // `imex_mode_names` by string — so a locale-dependent name would break a project + // opened under a different language. + std::string unique_mode_name(const std::vector<std::string>& also_taken) const; + + // Everything the editor draws for one role, in ONE place: a new role needs a colour and + // a legend name here and nowhere else in this file. nullopt is Inactive (grey). + // `label` is deliberately untranslated — it names a role, and the legend sits next to + // the same letters the preset stores. + struct RoleStyle { wxColour bg; wxColour fg; const char* label; }; + static RoleStyle role_style(std::optional<ImexRole> role); + + // True when this printer offers `role` at all, regardless of which tile is clicked. + // Span needs a second gantry to be a partner across, so a single-gantry printer neither + // cycles to it nor lists it in the legend. + bool role_offered(ImexRole role) const; + + // True when the tile for `tool_idx` may take `role` right now. Adds the positional rules + // on top of role_offered(): only one tile may hold Primary, and Span only on a tile + // sharing the Primary's gantry. + bool role_allowed_on_tile(ImexRole role, int tool_idx, + bool other_primary, int primary_gantry) const; + + // Next state in the tile cycle: Inactive → kImexRoleTable order → Inactive, stepping + // over any role `allowed` rejects. Inactive is always reachable, so it terminates. + static std::optional<ImexRole> next_tile_role(std::optional<ImexRole> current, + const std::function<bool(ImexRole)>& allowed); + + void apply_btn(wxButton* btn, int tool_idx, std::optional<ImexRole> role); + + struct Row { + wxPanel* panel; + wxTextCtrl* name; // nullptr for primary row (name is fixed) + wxTextCtrl* gcode; + std::vector<wxButton*> btns; + std::vector<std::optional<ImexRole>> btn_roles; // nullopt == Inactive + std::vector<int> btn_tool_idx; + std::map<int, ImexRole> all_tool_roles; // absent == Inactive + // Name the row was built with (UTF-8), i.e. the name that was in the preset — and so + // in the plate's mode selector — when the row appeared. Kept because the name field is + // free to drift from it without the row being rebuilt; remove_row() needs both to find + // the plates a delete strands. Rebuilding the rows (load_from_config / set_grid_size) + // re-seeds it, which is correct: config and rows agree again at that point. + std::string orig_name; + bool is_primary {false}; + ScalableButton* reset_btn {nullptr}; // nullptr when row has no parent counterpart + bool reset_dirty_cached {false}; + }; + + // Snapshot of row content as it would be saved (matches get_mode_data() per-row). + struct RowSnapshot { std::string name, tools, gcode; }; + RowSnapshot snapshot_row(const Row& r) const; + + // True when row at `row_idx` differs from the parent preset's value at the same + // index. Returns false when there is no parent (system preset), when the row is + // beyond the parent's mode count (user added it — no defined "default"), or when + // the lookup callback isn't wired. The Primary row's name is sentinel-fixed so + // a name diff doesn't count for it; only tools/gcode do. + bool row_differs_from_parent(int row_idx) const; + + // True when row index has a parent counterpart at all (i.e., the reset arrow + // should be present on the row at all, regardless of dirty state). + bool row_has_parent_counterpart(int row_idx) const; + + void add_row(const std::string& name = "", + const std::string& active_tools = "", + const std::string& gcode = "", + bool is_primary = false); + + // Returns every name the removed row was known by (UTF-8, deduplicated: its build-time + // name and its current name, which differ after an in-session rename), minus any name a + // surviving row still carries. The caller uses them to find the plates the delete + // stranded. Empty when nothing was removed, when the row is the non-deletable Primary, + // or when both names are blank -- a blank name is only reachable on a row that was never + // named, which no plate can be holding. + std::vector<std::string> remove_row(wxPanel* panel); + + void clear_rows(); + + std::string active_tools_string(const Row& r) const; + + void notify(); + + // Update each row's reset bitmap to reflect current dirty state. Cached so we + // only swap the bitmap when state actually transitions — avoids flicker on + // every keystroke. Disabled buttons (no saved counterpart) keep their dot. + void refresh_reset_buttons(); + + // Reset row identified by `panel` (stable across add/remove) to the parent + // preset's value at the same index. Primary row's name stays sentinel-fixed — + // only tools and gcode are restored. + void reset_row_to_parent(wxPanel* panel); + + // Rebuild the instruction text, colour legend and column headers for the CURRENT grid. + // These depend on the grid shape -- the Span role is only offered on a multi-gantry printer, + // and the header spacing is derived from the column count -- so they cannot be built once in + // the constructor: adding a second gantry has to reveal Span without a save-and-reopen cycle. + void rebuild_info_and_header(); + + // One-line explanation per role, shown as a tooltip on that role's legend swatch and label. + // Keeps the per-role detail out of the instruction paragraph. + static wxString role_hint(ImexRole role); + + wxBoxSizer* m_outer; + wxBoxSizer* m_rows_sizer; + wxPanel* m_info_panel = nullptr; + wxPanel* m_hdr_panel = nullptr; + std::vector<Row> m_rows; + int m_n_cols, m_n_rows; + int m_layout {0}; // 0=front-left, 1=front-right, 2=rear-left, 3=rear-right + bool m_clearing_rows {false}; // guards handlers against teardown-time events + ParentConfigLookup m_parent_lookup; +}; + +}} // namespace Slic3r::GUI + +#endif // slic3r_IMEXModesCtrl_hpp_ From 838c2f2df802f8a219fb335cb03b54db7bc39ba1 Mon Sep 17 00:00:00 2001 From: Clifford Garwood <cliff@cigii.com> Date: Thu, 3 Sep 2026 00:56:55 -0400 Subject: [PATCH 41/51] Reset plates to Primary when their mode is deleted Closes review comment 9. PartPlate::reset_imex_mode() had no callers, while the PR description said deleting a mode resets affected plates to Primary. IMEXModesCtrl now exposes an on_mode_removed callback that TabPrinter::build_fff handles by resetting every plate whose mode matches the deleted row, under a single undo snapshot, followed by the same dirty/update sequence the plate's own mode button runs. Wired to deletion only, on purpose: the name field notifies on every keystroke, so routing renames through the same path would orphan and reset the plate on the first character typed. Renames stay covered by the slice-time fallback and its warning. The callback is copied to a local before notify(), because notify() reaches load_from_config() -> clear_rows(), which tears down the row the handler is running inside. The rest of this file is the modes editor moving out to its own translation unit, leaving the include and the construction site. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- src/slic3r/GUI/Tab.cpp | 638 ++++------------------------------------- 1 file changed, 48 insertions(+), 590 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index b4e62ec5b4..62e133a53f 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -44,6 +44,7 @@ #include "UnsavedChangesDialog.hpp" #include "SavePresetDialog.hpp" #include "EditGCodeDialog.hpp" +#include "IMEXModesCtrl.hpp" #include "MultiChoiceDialog.hpp" #include "MsgDialog.hpp" #include "Notebook.hpp" @@ -4978,596 +4979,6 @@ void TabPrinter::build() m_printer_technology == ptSLA ? build_sla() : build_fff(); } -// --------------------------------------------------------------------------- -// IMEXModesCtrl — visual parallel-mode editor for the IDEX/IQEX printer tab -// -// Tool button states: -// 0 = Inactive (grey) — not participating in this mode -// 1 = Primary (green) — the tool the slicer generates paths for -// 2 = Copy (blue) — firmware duplicates Primary at an offset -// 3 = Mirror (amber) — firmware mirrors Primary about an axis -// 4 = Span (yellow) — multicolor partner of Primary on the same gantry; -// declares paired-gantry multicolor topology and -// unlocks the multicolor block at slice time. Only -// offered on tools sharing primary's gantry, and -// only on multi-gantry printers (n_rows >= 2). -// -// Active-tools string format: "idx:P,idx:C,idx:M,idx:S" (backwards-compat: plain "idx" = Primary) -// --------------------------------------------------------------------------- -class IMEXModesCtrl : public wxPanel { -public: - std::function<void()> on_change; - - // Lazy lookup so the widget always sees the current parent (preset switches - // change the parent under us). Returns nullptr when the active preset has no - // parent (system preset itself), which disables per-row reset arrows. - using ParentConfigLookup = std::function<const DynamicPrintConfig*()>; - void set_parent_config_lookup(ParentConfigLookup f) { m_parent_lookup = std::move(f); } - - // layout: 0=front-left, 1=front-right, 2=rear-left, 3=rear-right (T0 corner). - // The enum values intentionally line up 1:1 so this is a no-op cast — the helper - // is kept to make the conversion explicit at call sites. - static int parse_layout(ImexToolLayout layout) { return static_cast<int>(layout); } - - IMEXModesCtrl(wxWindow* parent, int n_cols, int n_rows, int layout = 0) - : wxPanel(parent, wxID_ANY), m_n_cols(std::max(1, n_cols)), m_n_rows(std::max(1, n_rows)), m_layout(layout) - { - // Pull the app's window-default colour explicitly. Without this, GTK gives - // child wxPanels a slightly lighter "widget bg" instead of the app's dark - // theme — making chromeless ScalableButtons inside the panel render with a - // visible light box around the icon. Sub-panels inherit this colour. - SetBackgroundColour(wxGetApp().get_window_default_clr()); - - m_outer = new wxBoxSizer(wxVERTICAL); - m_rows_sizer = new wxBoxSizer(wxVERTICAL); - - // --- Info panel: instruction text + color legend --- - auto* info_panel = new wxPanel(this, wxID_ANY); - info_panel->SetBackgroundColour(GetBackgroundColour()); - auto* info_sizer = new wxBoxSizer(wxVERTICAL); - - wxString instructions = - _L("Each mode defines which tool heads participate and their roles. " - "The Primary tool (green) drives all sliced paths. " - "Copy (blue) and Mirror (amber) tools follow the Primary at the firmware level. " - "Click a tool button to cycle its role — clear the Primary before reassigning it."); - if (m_n_rows >= 2) - instructions += " " + _L("Span (yellow) marks a tool on the Primary's gantry as the " - "multicolor partner — required to enable multi-color printing in " - "paired-gantry IMEX modes."); - auto* inst = new wxStaticText(info_panel, wxID_ANY, instructions); - inst->Wrap(FromDIP(620)); - info_sizer->Add(inst, 0, wxBOTTOM, FromDIP(6)); - - // Color legend — swatches sized to the body text height so they read as - // matched pairs with their labels regardless of system DPI / font scale, - // matching the on-hover ghost tooltip swatch's visual weight. - auto* leg_sizer = new wxBoxSizer(wxHORIZONTAL); - struct LegendEntry { int state; const char* label; }; - std::vector<LegendEntry> legend = { - {1,"Primary"},{2,"Copy"},{3,"Mirror"} - }; - if (m_n_rows >= 2) - legend.push_back({4, "Span"}); // only meaningful on multi-gantry printers - const int swatch_side = info_panel->GetCharHeight(); - for (auto& l : legend) { - auto* swatch = new wxPanel(info_panel, wxID_ANY, wxDefaultPosition, wxSize(swatch_side, swatch_side)); - swatch->SetBackgroundColour(btn_color(l.state)); - leg_sizer->Add(swatch, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(4)); - leg_sizer->Add(new wxStaticText(info_panel, wxID_ANY, l.label), - 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(16)); - } - info_sizer->Add(leg_sizer, 0, wxBOTTOM, FromDIP(6)); - info_panel->SetSizer(info_sizer); - - // Column header row — spacers sized to align with the mode-row fields below. - // Name field: FromDIP(130) + FromDIP(6) gap; tool grid: n_cols*(FromDIP(36)+FromDIP(2))-FromDIP(2) + FromDIP(6) gap. - auto* hdr_panel = new wxPanel(this, wxID_ANY); - hdr_panel->SetBackgroundColour(GetBackgroundColour()); - auto* hdr_sizer = new wxBoxSizer(wxHORIZONTAL); - auto* hdr_name = new wxStaticText(hdr_panel, wxID_ANY, _L("Name")); - auto* hdr_tools = new wxStaticText(hdr_panel, wxID_ANY, _L("Tools")); - auto* hdr_gcode = new wxStaticText(hdr_panel, wxID_ANY, _L("G-code")); - const int grid_px = m_n_cols * FromDIP(38) - FromDIP(2); // approx grid panel width - const int name_col_px = FromDIP(136); - hdr_sizer->Add(hdr_name, 0, wxALIGN_CENTER_VERTICAL); - hdr_sizer->AddSpacer(std::max(0, name_col_px - hdr_name->GetBestSize().x)); - hdr_sizer->Add(hdr_tools, 0, wxALIGN_CENTER_VERTICAL); - hdr_sizer->AddSpacer(std::max(0, grid_px + FromDIP(6) - hdr_tools->GetBestSize().x)); - hdr_sizer->Add(hdr_gcode, 1, wxALIGN_CENTER_VERTICAL); - hdr_panel->SetSizer(hdr_sizer); - - auto* add_btn = new wxButton(this, wxID_ANY, _L("+ Add Mode"), - wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - add_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { add_row(); notify(); }); - - m_outer->Add(info_panel, 0, wxEXPAND | wxBOTTOM, FromDIP(4)); - m_outer->Add(hdr_panel, 0, wxEXPAND | wxBOTTOM, FromDIP(2)); - m_outer->Add(m_rows_sizer, 0, wxEXPAND); - m_outer->AddSpacer(FromDIP(4)); - m_outer->Add(add_btn, 0); - SetSizer(m_outer); - } - - void set_grid_size(int n_cols, int n_rows, int layout = -1) { - n_cols = std::max(1, n_cols); - n_rows = std::max(1, n_rows); - if (layout < 0) layout = m_layout; - if (n_cols == m_n_cols && n_rows == m_n_rows && layout == m_layout) return; - auto [names, tools, gcodes] = get_mode_data(); - clear_rows(); - m_n_cols = n_cols; - m_n_rows = n_rows; - m_layout = layout; - for (size_t i = 0; i < names.size(); ++i) - add_row(names[i], tools[i], gcodes[i], /*is_primary=*/(names[i] == kImexPrimaryMode)); - Layout(); - } - - void load_from_config(const DynamicPrintConfig& cfg) { - clear_rows(); - auto* names = cfg.option<ConfigOptionStrings>("imex_mode_names"); - auto* tools = cfg.option<ConfigOptionStrings>("imex_mode_active_tools"); - auto* gcodes = cfg.option<ConfigOptionStrings>("imex_mode_gcodes"); - - // Primary row is always first and non-deletable. Look for an existing - // "primary" entry in the config (present in configs saved after #8 was - // implemented); fall back to empty tool/gcode for older configs. - std::string primary_tools, primary_gcode; - size_t primary_cfg_idx = std::string::npos; - if (names) { - for (size_t i = 0; i < names->values.size(); ++i) { - if (names->values[i] == kImexPrimaryMode) { - primary_cfg_idx = i; - if (tools && i < tools->values.size()) primary_tools = tools->values[i]; - if (gcodes && i < gcodes->values.size()) primary_gcode = gcodes->values[i]; - break; - } - } - } - add_row(kImexPrimaryMode, primary_tools, primary_gcode, /*is_primary=*/true); - - size_t n = names ? names->values.size() : 0; - for (size_t i = 0; i < n; ++i) { - if (i == primary_cfg_idx) continue; // already added above - add_row(names->values[i], - (tools && i < tools->values.size()) ? tools->values[i] : "", - (gcodes && i < gcodes->values.size()) ? gcodes->values[i] : ""); - } - refresh_reset_buttons(); - Layout(); - } - - std::tuple<std::vector<std::string>, std::vector<std::string>, std::vector<std::string>> - get_mode_data() const { - std::vector<std::string> names, tools, gcodes; - for (auto& r : m_rows) { - std::string nm = r.is_primary ? std::string(kImexPrimaryMode) : r.name->GetValue().ToStdString(); - if (nm.empty()) continue; - names.push_back(nm); - tools.push_back(active_tools_string(r)); - gcodes.push_back(r.gcode->GetValue().ToStdString()); - } - return {names, tools, gcodes}; - } - - // True when the widget's current rows already mirror the three IMEX-mode option - // vectors in cfg. Used by TabPrinter::update_fff() to skip a destroy-and-rebuild - // pass when the only thing that just changed was the widget itself writing back - // to config — without this guard, every keystroke in the gcode textbox triggers - // a load_from_config() that detaches the textbox the user is typing in. - bool matches_config(const DynamicPrintConfig& cfg) const { - auto [names, tools, gcodes] = get_mode_data(); - auto cfg_strings = [&cfg](const char* key) { - std::vector<std::string> v; - if (auto* o = cfg.option<ConfigOptionStrings>(key)) v = o->values; - return v; - }; - return names == cfg_strings("imex_mode_names") - && tools == cfg_strings("imex_mode_active_tools") - && gcodes == cfg_strings("imex_mode_gcodes"); - } - - // Parse "idx:P,idx:C,idx:M" → map<tool_idx, state> - // Backwards compat: plain "idx" (no role) → state 1 (Primary) - // Indices are PHYSICAL tool indices (T0..TN-1). all_tool_states preserves - // off-grid entries so the tile widget can round-trip indices that fall - // outside the currently visible rows × cols without losing data on save. - static std::map<int,int> parse_tool_states(const std::string& s) { - std::map<int,int> result; - if (s.empty()) return result; - std::istringstream ss(s); - std::string tok; - while (std::getline(ss, tok, ',')) { - tok.erase(std::remove_if(tok.begin(), tok.end(), ::isspace), tok.end()); - if (tok.empty()) continue; - try { - auto colon = tok.find(':'); - int idx, state = 1; - if (colon != std::string::npos) { - idx = std::stoi(tok.substr(0, colon)); - char role = std::toupper((unsigned char)tok[colon + 1]); - if (role == 'C') state = 2; - else if (role == 'M') state = 3; - else if (role == 'S') state = 4; - } else { - idx = std::stoi(tok); - } - result[idx] = state; - } catch (...) {} - } - return result; - } - -private: - // State 0=inactive, 1=primary, 2=copy, 3=mirror, 4=span - static wxColour btn_color(int state) { - switch (state) { - case 1: return wxColour(50, 160, 50); // green — Primary - case 2: return wxColour(60, 120, 210); // blue — Copy - case 3: return wxColour(210, 130, 20); // amber — Mirror - case 4: return wxColour(180, 180, 40); // yellow — Span - default: return wxColour(90, 90, 90); // grey — Inactive - } - } - static wxColour btn_fg(int /*state*/) { return *wxWHITE; } - static const char* state_role(int state) { - switch (state) { - case 1: return "P"; - case 2: return "C"; - case 3: return "M"; - case 4: return "S"; - default: return ""; - } - } - - void apply_btn(wxButton* btn, int tool_idx, int state) { - // Always label as T{n} — the button color already encodes the role. - btn->SetLabel(wxString::Format("T%d", tool_idx)); - btn->SetBackgroundColour(btn_color(state)); - btn->SetForegroundColour(btn_fg(state)); - btn->Refresh(); - } - - struct Row { - wxPanel* panel; - wxTextCtrl* name; // nullptr for primary row (name is fixed) - wxTextCtrl* gcode; - std::vector<wxButton*> btns; - std::vector<int> btn_states; - std::vector<int> btn_tool_idx; - std::map<int,int> all_tool_states; - bool is_primary {false}; - ScalableButton* reset_btn {nullptr}; // nullptr when row has no parent counterpart - bool reset_dirty_cached {false}; - }; - - // Snapshot of row content as it would be saved (matches get_mode_data() per-row). - struct RowSnapshot { std::string name, tools, gcode; }; - RowSnapshot snapshot_row(const Row& r) const { - RowSnapshot s; - s.name = r.is_primary ? std::string(kImexPrimaryMode) : r.name->GetValue().ToStdString(); - s.tools = active_tools_string(r); - s.gcode = r.gcode->GetValue().ToStdString(); - return s; - } - - // True when row at `row_idx` differs from the parent preset's value at the same - // index. Returns false when there is no parent (system preset), when the row is - // beyond the parent's mode count (user added it — no defined "default"), or when - // the lookup callback isn't wired. The Primary row's name is sentinel-fixed so - // a name diff doesn't count for it; only tools/gcode do. - bool row_differs_from_parent(int row_idx) const { - if (!m_parent_lookup) return false; - const DynamicPrintConfig* parent = m_parent_lookup(); - if (!parent) return false; - auto* p_names = parent->option<ConfigOptionStrings>("imex_mode_names"); - auto* p_tools = parent->option<ConfigOptionStrings>("imex_mode_active_tools"); - auto* p_gcodes = parent->option<ConfigOptionStrings>("imex_mode_gcodes"); - if (!p_names || row_idx < 0 || row_idx >= (int)p_names->values.size()) return false; - const Row& r = m_rows[row_idx]; - const RowSnapshot s = snapshot_row(r); - if (!r.is_primary && s.name != p_names->values[row_idx]) return true; - if (p_tools && row_idx < (int)p_tools->values.size() && s.tools != p_tools->values[row_idx]) return true; - if (p_gcodes && row_idx < (int)p_gcodes->values.size() && s.gcode != p_gcodes->values[row_idx]) return true; - return false; - } - - // True when row index has a parent counterpart at all (i.e., the reset arrow - // should be present on the row at all, regardless of dirty state). - bool row_has_parent_counterpart(int row_idx) const { - if (!m_parent_lookup) return false; - const DynamicPrintConfig* parent = m_parent_lookup(); - if (!parent) return false; - auto* p_names = parent->option<ConfigOptionStrings>("imex_mode_names"); - return p_names && row_idx >= 0 && row_idx < (int)p_names->values.size(); - } - - void add_row(const std::string& name = "", - const std::string& active_tools = "", - const std::string& gcode = "", - bool is_primary = false) - { - Row r; - r.is_primary = is_primary; - r.panel = new wxPanel(this, wxID_ANY); - r.panel->SetBackgroundColour(GetBackgroundColour()); - auto* sizer = new wxBoxSizer(wxHORIZONTAL); - - if (is_primary) { - r.name = nullptr; - auto* lbl = new wxStaticText(r.panel, wxID_ANY, _L("Primary"), - wxDefaultPosition, FromDIP(wxSize(130, -1))); - wxFont f = lbl->GetFont(); - f.SetWeight(wxFONTWEIGHT_BOLD); - lbl->SetFont(f); - sizer->Add(lbl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(6)); - } else { - r.name = new wxTextCtrl(r.panel, wxID_ANY, name, wxDefaultPosition, FromDIP(wxSize(130, -1))); - r.name->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { notify(); }); - } - - auto* grid_panel = new wxPanel(r.panel, wxID_ANY); - grid_panel->SetBackgroundColour(GetBackgroundColour()); - auto* grid_sizer = new wxGridSizer(m_n_rows, m_n_cols, FromDIP(2), FromDIP(2)); - - auto tool_states = parse_tool_states(active_tools); - if (tool_states.empty()) - tool_states[0] = 1; // default T0 → Primary when no assignment is stored - r.all_tool_states = tool_states; // preserve all assignments, including off-screen tools - wxPanel* this_panel = r.panel; - - // Buttons rendered top=rear (high Y), bottom=front (low Y). - // Layout remapping: m_layout encodes which corner T0 is at physically. - // flip_x (layout 1,3): col 0 is on the right (max-X) instead of left - // flip_y (layout 2,3): row 0 is at the rear (max-Y) instead of front - // Display iterates: row from n_rows-1 down to 0 (rear→front = top→bottom). - // raw_row = flip_y ? (n_rows-1-row) : row - // raw_col = flip_x ? (n_cols-1-col) : col - // - // row_start: anchor displayed rows to the gantry row containing the Primary - // assignment, so reducing gantry count keeps the meaningful row visible. - int primary_gantry_row = 0; - for (const auto& [idx, state] : tool_states) { - if (state == 1) { primary_gantry_row = idx / m_n_cols; break; } - } - int row_start = primary_gantry_row; // display rows [row_start .. row_start+m_n_rows-1] - - bool flip_x = (m_layout == 1 || m_layout == 3); - bool flip_y = (m_layout == 2 || m_layout == 3); - for (int row = m_n_rows - 1; row >= 0; --row) { - for (int col = 0; col < m_n_cols; ++col) { - int raw_row = flip_y ? (m_n_rows - 1 - row) : row; - raw_row += row_start; // anchor to Primary's gantry row - int raw_col = flip_x ? (m_n_cols - 1 - col) : col; - int tool_idx = raw_row * m_n_cols + raw_col; - int state = 0; - auto it = tool_states.find(tool_idx); - if (it != tool_states.end()) state = it->second; - - auto* btn = new wxButton(grid_panel, wxID_ANY, wxEmptyString, - wxDefaultPosition, FromDIP(wxSize(36, 26)), wxBU_EXACTFIT); - apply_btn(btn, tool_idx, state); - - int btn_pos = (int)r.btns.size(); - r.btns.push_back(btn); - r.btn_states.push_back(state); - r.btn_tool_idx.push_back(tool_idx); - - // The Primary mode is the IMEX-off mode — its tool assignment is - // fixed (no parallel printing happening), so cycling tool roles - // would be a no-op and confusing. Render the buttons read-only; - // the row still shows up in the editor as visual context. - if (is_primary) { - btn->Disable(); - } else { - btn->Bind(wxEVT_BUTTON, [this, this_panel, btn_pos](wxCommandEvent&) { - // Find the row by panel pointer (stable across add/remove) - for (auto& row_ref : m_rows) { - if (row_ref.panel != this_panel) continue; - int& st = row_ref.btn_states[btn_pos]; - const int tidx = row_ref.btn_tool_idx[btn_pos]; - - // Check if another button already holds the Primary state, - // and locate the primary's gantry row for Span eligibility. - bool other_primary = false; - int primary_gantry = -1; - for (int j = 0; j < (int)row_ref.btn_states.size(); ++j) { - if (row_ref.btn_states[j] == 1) { - if (j != btn_pos) other_primary = true; - primary_gantry = row_ref.btn_tool_idx[j] / m_n_cols; - } - } - // Span makes sense only on multi-gantry printers, and only - // on a tile sharing primary's gantry (it declares "this tool - // is the within-gantry multicolor partner of Primary"). - const bool span_eligible = (m_n_rows >= 2) - && (primary_gantry >= 0) - && (tidx / m_n_cols == primary_gantry); - - // Cycle: 0 → 1 → 2 → 3 → 4 → 0 with skips. - st = (st + 1) % 5; - if (st == 1 && other_primary) - st = 2; // skip Primary → go straight to Copy - if (st == 4 && !span_eligible) - st = 0; // skip Span → wrap to Inactive - - // Keep all_tool_states in sync so off-screen tools are preserved - if (st == 0) - row_ref.all_tool_states.erase(tidx); - else - row_ref.all_tool_states[tidx] = st; - - apply_btn(row_ref.btns[btn_pos], row_ref.btn_tool_idx[btn_pos], st); - notify(); - break; - } - }); - } - - grid_sizer->Add(btn, 0); - } - } - grid_panel->SetSizer(grid_sizer); - - r.gcode = new wxTextCtrl(r.panel, wxID_ANY, gcode, - wxDefaultPosition, FromDIP(wxSize(220, 54)), wxTE_MULTILINE); - r.gcode->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { notify(); }); - - if (!is_primary) { - sizer->Add(r.name, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(6)); - } - sizer->Add(grid_panel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(6)); - sizer->Add(r.gcode, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(4)); - - // Edit + remove (for non-primary) — stacked vertically. - auto* btn_col = new wxBoxSizer(wxVERTICAL); - wxTextCtrl* gcode_ctrl = r.gcode; - auto* ph_btn = new ScalableButton(r.panel, wxID_ANY, "edit", wxEmptyString, - wxDefaultSize, wxDefaultPosition, - wxBU_EXACTFIT | wxNO_BORDER, 16); - ph_btn->SetToolTip(_L("Edit G-code / browse placeholders")); - ph_btn->Bind(wxEVT_BUTTON, [this, gcode_ctrl](wxCommandEvent&) { - EditGCodeDialog dlg(this, "imex_mode_gcode", gcode_ctrl->GetValue().ToStdString()); - if (dlg.ShowModal() == wxID_OK) - gcode_ctrl->SetValue(dlg.get_edited_gcode()); - }); - btn_col->Add(ph_btn, 0, wxBOTTOM, FromDIP(2)); - - if (!is_primary) { - auto* rm = new ScalableButton(r.panel, wxID_ANY, "imex_remove", wxEmptyString, - wxDefaultSize, wxDefaultPosition, - wxBU_EXACTFIT | wxNO_BORDER, 16); - rm->SetToolTip(_L("Remove mode")); - rm->Bind(wxEVT_BUTTON, [this, this_panel](wxCommandEvent&) { - remove_row(this_panel); - notify(); - }); - btn_col->Add(rm, 0); - } - sizer->Add(btn_col, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(4)); - - // Per-row reset gets its own column on the right so the icon reads as - // distinct from the edit/remove column. Reset only renders when this row - // has a counterpart in the saved preset (user-added rows beyond the saved - // mode count get no reset — the X button covers "remove user-added row"). - auto* reset_col = new wxBoxSizer(wxVERTICAL); - wxPanel* this_panel_for_reset = r.panel; - if (row_has_parent_counterpart(static_cast<int>(m_rows.size()))) { - r.reset_btn = new ScalableButton(r.panel, wxID_ANY, "dot", wxEmptyString, - wxDefaultSize, wxDefaultPosition, - wxBU_EXACTFIT | wxNO_BORDER, 16); - r.reset_btn->SetToolTip(_L("Discard in-session edits to this mode (snap back to saved value)")); - r.reset_btn->Bind(wxEVT_BUTTON, [this, this_panel_for_reset](wxCommandEvent&) { - reset_row_to_parent(this_panel_for_reset); - }); - reset_col->Add(r.reset_btn, 0, wxALIGN_CENTER_VERTICAL); - } - sizer->Add(reset_col, 0, wxALIGN_CENTER_VERTICAL); - r.panel->SetSizer(sizer); - - m_rows_sizer->Add(r.panel, 0, wxEXPAND | wxBOTTOM, FromDIP(4)); - m_rows.push_back(std::move(r)); - Layout(); - } - - void remove_row(wxPanel* panel) { - for (size_t i = 0; i < m_rows.size(); ++i) { - if (m_rows[i].panel == panel) { - if (m_rows[i].is_primary) return; // primary row is non-deletable - m_rows_sizer->Detach(panel); - m_rows.erase(m_rows.begin() + i); - Layout(); - // Defer widget destruction so any in-flight GTK events for - // panel's children (including the × button we're inside) finish - // processing before the wxEvtHandlers are freed. - wxTheApp->CallAfter([panel]() { panel->Destroy(); }); - return; - } - } - } - - void clear_rows() { - for (auto& r : m_rows) { m_rows_sizer->Detach(r.panel); r.panel->Destroy(); } - m_rows.clear(); - } - - std::string active_tools_string(const Row& r) const { - // Serialize from all_tool_states (not just visible buttons) so assignments - // for off-screen tools are preserved across grid size changes. - std::string s; - for (const auto& [idx, state] : r.all_tool_states) { - if (state == 0) continue; - if (!s.empty()) s += ','; - s += std::to_string(idx) + ':' + state_role(state); - } - return s; - } - - void notify() { - refresh_reset_buttons(); - if (on_change) on_change(); - } - - // Update each row's reset bitmap to reflect current dirty state. Cached so we - // only swap the bitmap when state actually transitions — avoids flicker on - // every keystroke. Disabled buttons (no saved counterpart) keep their dot. - void refresh_reset_buttons() { - for (size_t i = 0; i < m_rows.size(); ++i) { - Row& r = m_rows[i]; - if (!r.reset_btn || !r.reset_btn->IsEnabled()) continue; - const bool dirty = row_differs_from_parent(static_cast<int>(i)); - if (dirty == r.reset_dirty_cached) continue; - r.reset_dirty_cached = dirty; - r.reset_btn->SetBitmap_(dirty ? "undo" : "dot"); - } - } - - // Reset row identified by `panel` (stable across add/remove) to the parent - // preset's value at the same index. Primary row's name stays sentinel-fixed — - // only tools and gcode are restored. - void reset_row_to_parent(wxPanel* panel) { - if (!m_parent_lookup) return; - const DynamicPrintConfig* parent = m_parent_lookup(); - if (!parent) return; - auto* p_names = parent->option<ConfigOptionStrings>("imex_mode_names"); - auto* p_tools = parent->option<ConfigOptionStrings>("imex_mode_active_tools"); - auto* p_gcodes = parent->option<ConfigOptionStrings>("imex_mode_gcodes"); - for (size_t i = 0; i < m_rows.size(); ++i) { - Row& r = m_rows[i]; - if (r.panel != panel) continue; - if (!p_names || i >= p_names->values.size()) return; - if (!r.is_primary && r.name) - r.name->ChangeValue(from_u8(p_names->values[i])); - if (p_gcodes && i < p_gcodes->values.size()) - r.gcode->ChangeValue(from_u8(p_gcodes->values[i])); - if (p_tools && i < p_tools->values.size()) { - // Reapply tool states from the parent's serialized form. all_tool_states - // is the source of truth for round-tripping; rebuild it then re-paint - // the visible buttons. - r.all_tool_states = parse_tool_states(p_tools->values[i]); - for (size_t j = 0; j < r.btns.size(); ++j) { - int tidx = r.btn_tool_idx[j]; - auto it = r.all_tool_states.find(tidx); - int st = (it == r.all_tool_states.end()) ? 0 : it->second; - r.btn_states[j] = st; - apply_btn(r.btns[j], tidx, st); - } - } - notify(); - return; - } - } - - wxBoxSizer* m_outer; - wxBoxSizer* m_rows_sizer; - std::vector<Row> m_rows; - int m_n_cols, m_n_rows; - int m_layout {0}; // 0=front-left, 1=front-right, 2=rear-left, 3=rear-right - ParentConfigLookup m_parent_lookup; -}; -// --------------------------------------------------------------------------- - void TabPrinter::build_fff() { if (!m_pages.empty()) @@ -6292,6 +5703,53 @@ if (is_marlin_flavor) update_dirty(); on_value_change("imex_mode_names", std::string("")); }; + // A plate stores its IMEX mode as the mode's *name*, resolved against this + // table at slice time, so deleting a row strands every plate that was using + // it. Those plates print as Primary either way -- GCode.cpp falls back when + // the name resolves to no row -- but until they are reset they keep claiming + // a mode that no longer exists: the plate button still shows the old label, + // the mode is written back out to the 3MF, and re-adding a different mode at + // the same position would not revive it. Resetting them here is what makes + // "deleting a mode resets the plates using it to Primary" true. + // + // Deletion only. Renaming is deliberately not funnelled through here: the + // name field notifies on every keystroke, so an in-progress rename would + // orphan and reset the plate on the first character typed. + // + // Because of that, a row can be renamed and only then deleted, and the plate + // is still holding the name it was set from. The control therefore reports + // every name the deleted row was known by -- its build-time name and its name + // at delete time -- already filtered of anything a surviving row still + // carries, so matching any of them is safe. + m_imex_modes_ctrl->on_mode_removed = [](const std::vector<std::string>& removed_modes) { + Plater* plater = wxGetApp().plater(); + if (!plater || removed_modes.empty()) + return; + PartPlateList& plates = plater->get_partplate_list(); + std::vector<PartPlate*> affected; + for (int i = 0; i < plates.get_plate_count(); ++i) { + PartPlate* plate = plates.get_plate(i); + if (!plate) + continue; + const std::string mode = plate->get_imex_mode(); + if (mode.empty() || mode == kImexPrimaryMode) + continue; + if (std::find(removed_modes.begin(), removed_modes.end(), mode) != removed_modes.end()) + affected.push_back(plate); + } + if (affected.empty()) + return; + // One snapshot for the whole batch, so a single undo restores every plate. + // Same sequence the plate's own mode button runs (Plater::select_plate_by_hover_id, + // PLATE_IMEX_MODE_ID) -- reset_imex_mode() already invalidates each plate's + // slice result and its zone / ghost caches. + plater->take_snapshot("reset imex mode"); + for (PartPlate* plate : affected) + plate->reset_imex_mode(); + plater->update_project_dirty_from_presets(); + plater->set_plater_dirty(true); + plater->update(); + }; auto* sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(m_imex_modes_ctrl, 1, wxEXPAND); return sizer; From 1e608fe24c20087a16d9eeff2693d0072e7968f5 Mon Sep 17 00:00:00 2001 From: Clifford Garwood <cliff@cigii.com> Date: Thu, 3 Sep 2026 00:56:55 -0400 Subject: [PATCH 42/51] Have the preview consume the shared zone layout instead of rebuilding it Closes review comment 17. GCodeViewer had its own copy of the flip_x/flip_y corner mapping, the active column/row sets, the physical-to-zone index mapping and the zone pitch -- the same derivation as the plate's, with nothing keeping the two in step. It now calls compute_imex_zone_layout() and consumes head_zone_centers. The mirror is expressed as a reflection about the midpoint of the two zone centres rather than about a zone-relative strip width, which is algebraically identical for equal-sized zones and needs no pitch, and the toolhead-box face is chosen by comparing zone centres instead of physical columns. The July report of a math error in the visualizer for non-primary heads was this drift: the sec_box_offset_y else-branch hardcoded -imex_box_wy, which happened to equal the primary's offset on the rear-* layouts and pointed the wrong way on the front-* ones. Structurally unreachable now. Verifying the two sides matched turned up two config defaults that disagreed, both fixed in their own commits: imex_nozzle_clearance_x/y (the viewer's 30.0f matched PrintConfig, the zone code's 0.0 did not, and the strip loops are gated on it) and imex_tools_per_gantry (the library's 2 matched, both GUI paths used 1). Consuming the shared function meant resolving it per frame, and the sequential-view marker flag is sticky, so one drag of the slider made every subsequent frame parse five strings and allocate a dozen containers from inputs that never change. The resolve now sits behind a cache key mirroring PartPlate::build_imex_cache_key(), plus the two inputs only the preview reads -- the bed extents and the tool layout. An idle frame compares scalars and allocates nothing. The toolhead-box mesh, which was being re-uploaded to the GPU every frame for the same reason, is rebuilt only when the clearances change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- src/slic3r/GUI/GCodeViewer.cpp | 595 ++++++++++++++++++--------------- src/slic3r/GUI/GCodeViewer.hpp | 79 ++++- 2 files changed, 398 insertions(+), 276 deletions(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index fc0a62301d..7ba8060e9e 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -11,6 +11,7 @@ #include "libslic3r/LocalesUtils.hpp" #include "libslic3r/PresetBundle.hpp" #include "libslic3r/IMEXHelpers.hpp" +#include "libslic3r/IMEXZones.hpp" //BBS: add convex hull logic for toolpath check #include "libslic3r/Geometry/ConvexHull.hpp" @@ -1606,6 +1607,228 @@ void GCodeViewer::reset() m_contained_in_bed = true; } +// IDEX/IQEX: resolve where every secondary carriage marker sits, relative to the primary, +// for one (printer preset, active mode, plate bed) triple. This parses the mode string +// several times over and rebuilds the zone grid, and every one of its inputs is preset or +// plate state, so render() runs it only when GCodeViewer::ImexMarkerKey changes and replays +// the returned plan on all the frames in between. +// +// `mode` is already resolved (the plate's mode beats the process preset). An empty +// `carriages` list means "no secondary markers for this configuration" — IMEX off in this +// mode, firmware-managed zones, or a mode whose roster has no zone-owning secondary. +GCodeViewer::ImexMarkerPlan GCodeViewer::resolve_imex_marker_plan(const DynamicPrintConfig& printer_cfg, + const std::string& mode, + const BoundingBoxf& bed_extents) +{ + ImexMarkerPlan plan; + + // Firmware-managed-zones centers the slice at bed origin, so prim_pos + // and the preview toolpaths sit in a shifted frame relative to the + // plate-local bed bounds the zone math uses. Computing secondaries here + // would place them off-bed. The firmware physically fans the centered + // toolpath out into the zones, so the centered preview with no + // secondaries is the honest representation. + auto* fw_opt = printer_cfg.opt<ConfigOptionBool>("imex_firmware_managed_zones"); + if (fw_opt && fw_opt->value) + return plan; + if (mode.empty() || mode == kImexPrimaryMode) + return plan; + + auto* tpg_opt = printer_cfg.opt<ConfigOptionInt>("imex_tools_per_gantry"); + auto* wx_opt = printer_cfg.opt<ConfigOptionFloat>("imex_nozzle_clearance_x"); + auto* wy_opt = printer_cfg.opt<ConfigOptionFloat>("imex_nozzle_clearance_y"); + // Only the gantry grouping and the mirror axis are decided here; the zone + // grid itself comes from compute_imex_zone_layout() below. The fallback is 2, + // matching PrintConfig.cpp:6643, compute_imex_zone_layout() and + // PartPlate::calc_imex_ghosts() -- all four must agree, or a missing key + // groups tools against a grid divided a different way. + const int tools_per_gantry = tpg_opt ? std::max(1, tpg_opt->value) : 2; + plan.box_wx = wx_opt ? (float)wx_opt->value : 30.0f; + plan.box_wy = wy_opt ? (float)wy_opt->value : 30.0f; + + // Parse "idx:P/C/M" via shared helpers — matches PartPlate::calc_imex_zones. + // The role travels as an ImexRole all the way to the marker placement + // below; there is no int encoding in between, so a role added to the enum + // cannot silently fall into the "not Mirror, therefore Copy" branch. + int pri_tool = -1; + std::vector<int> sec_tool_ids; + std::map<int, ImexRole> sec_tool_roles; // tool_id -> Copy or Mirror + std::set<int> sec_aggregated; // representatives standing in for a whole gantry + { + // Same lookup rule as PartPlate's zones and ghosts, and as the slicer: + // an unresolved mode, and a mode the tools array is too short to cover, + // both come back empty and leave the marker roster empty. + const std::string entry = find_imex_mode(printer_cfg, mode).active_tools; + pri_tool = imex_primary_tool_for_mode(entry); + // Aggregate per gantry via the same source of truth as PartPlate's + // zone/ghost aggregation: in Span modes only one tool prints per + // zone at a time, so a non-primary gantry collapses to one + // representative marker. Non-Span gantries keep per-tool markers. + const ImexGantryGrouping grouping = + group_imex_active_tools_by_gantry(entry, tools_per_gantry); + auto add_tool = [&](int phys_idx, ImexRole role, bool aggregated) { + if (phys_idx < 0 || phys_idx == pri_tool) return; + // Only Copy and Mirror print in a zone of their own, so only they + // get a marker. Exhaustive with no default so -Wswitch makes a new + // role answer "does this carriage get its own marker?" rather than + // defaulting into a Copy-shaped one. + switch (role) { + case ImexRole::Copy: + case ImexRole::Mirror: + break; + case ImexRole::Primary: // not a secondary carriage + case ImexRole::Span: // rides in the primary's zone + return; + } + sec_tool_roles[phys_idx] = role; + sec_tool_ids.push_back(phys_idx); + if (aggregated) sec_aggregated.insert(phys_idx); + }; + // Out-of-grid tool indices (a stale mode string carried over from a + // printer with more tools) are handled inconsistently by the code we + // must agree with: compute_imex_zone_layout drops them, so they own no + // zone, while calc_imex_ghosts still bakes a ghost for them. No single + // policy matches both, so the marker roster is left exactly as it was + // and such a tool simply falls back to the first zone below. Clamping + // pri_tool instead is a trap: the -1 sentinel truncates to gantry 0 in + // imex_mirror_axis_for and flips the marker to the opposite mirror + // axis from the ghost. It is also why the layout's own `primary_head` + // cannot stand in for `pri_tool` here — the layout reports -1 for an + // off-grid primary, this roster has to keep the authored index. + for (const auto& grp : grouping.groups) { + // Markers: an aggregated non-primary gantry shows only its rep. + if (grp.aggregate && grp.gantry_index != grouping.primary_gantry) + add_tool(grp.representative_phys, grp.representative_role, true); + else + for (const auto& [phys_idx, role] : grp.tools) + add_tool(phys_idx, role, false); + } + } + const int sec_count = (int)sec_tool_ids.size(); + if (sec_count == 0) + return plan; + + // The zone grid is not re-derived here: this is the same call + // PartPlate::calc_imex_zones() makes, with the same printer config and the + // same bed extents, so the preview and the plate cannot place a tool + // differently for the same mode. The T0-corner flips, the active + // column/row sets and the zone pitch all live inside the library; the + // markers need nothing from it but `head_zone_centers`. + // `mode` is already resolved (per-plate mode beats the process preset), + // so it goes in as the plate mode with no process fallback. + const ImexZoneLayout zone_layout = + compute_imex_zone_layout(printer_cfg, mode, std::string(), bed_extents); + + // Centre of zone (0,0), the fallback for any head the layout gave no zone — + // a mode string naming a tool outside this printer's grid. Zone indices are + // dense, so the lowest centre on each axis IS zone 0's. An empty layout + // means one undivided zone, whose centre is the bed's. + Vec2d zone0_center = bed_extents.center(); + if (!zone_layout.head_zone_centers.empty()) { + zone0_center = zone_layout.head_zone_centers.begin()->second; + for (const auto& head_center : zone_layout.head_zone_centers) { + zone0_center.x() = std::min(zone0_center.x(), head_center.second.x()); + zone0_center.y() = std::min(zone0_center.y(), head_center.second.y()); + } + } + auto zone_center_of = [&](int tid) -> Vec2d { + auto it = zone_layout.head_zone_centers.find(tid); + return (it == zone_layout.head_zone_centers.end()) ? zone0_center : it->second; + }; + const Vec2d pri_center = zone_center_of(pri_tool); + + // An aggregated gantry's zone is a full-X row strip with no column of its + // own, so its marker tracks primary's X. calc_imex_ghosts() reaches the same + // zero X offset by putting both frames on the bed centreline; for a single + // marker, pinning the centre says it directly. + auto sec_center_of = [&](int tid) -> Vec2d { + Vec2d c = zone_center_of(tid); + if (sec_aggregated.count(tid)) + c.x() = pri_center.x(); + return c; + }; + + // Primary carriage box: seeded from whether primary holds the leftmost zone + // column, then turned by any secondary sitting to one side of it. + plan.pri_box_offset_x = (pri_center.x() <= zone0_center.x()) ? 0.0f : -plan.box_wx; + plan.pri_box_offset_y = -plan.box_wy; + for (int i = 0; i < sec_count; ++i) { + const Vec2d sc = sec_center_of(sec_tool_ids[i]); + if (sc.x() > pri_center.x()) { plan.pri_box_offset_x = 0.0f; } + else if (sc.x() < pri_center.x()) { plan.pri_box_offset_x = -plan.box_wx; } + if (sc.y() > pri_center.y()) { plan.pri_box_offset_y = 0.0f; } + else if (sc.y() < pri_center.y()) { plan.pri_box_offset_y = -plan.box_wy; } + } + + plan.carriages.reserve(sec_count); + for (int i = 0; i < sec_count; ++i) { + const int sec_tool = sec_tool_ids[i]; + const Vec2d sec_center = sec_center_of(sec_tool); + const ImexRole sec_role = sec_tool_roles[sec_tool]; + + // A carriage stays inside its own zone; a Mirror reflects its + // zone-relative offset about that zone's centerline, on the axis of the + // boundary it shares with primary — the same rule the ghosts use: + // Copy → tracks primary on both axes. + // Mirror, same gantry → reflect X (zones sit side by side). + // Mirror, other gantry → reflect Y (zones sit front-to-back); X + // tracks primary, since the part off that + // gantry is a Y-reflection of the tool + // directly behind it. + // The axis comes from the shared helper, so the markers can never drift + // out of step with the plate ghosts. + const bool is_mirror = (sec_role == ImexRole::Mirror); + const bool cross_gantry = imex_mirror_axis_for(pri_tool, sec_tool, + tools_per_gantry) == ImexMirrorAxis::Y; + + // Tracking an axis translates by the gap between the two zone centres. + // Mirroring it reflects primary about the midpoint of those centres — + // the zones being equal-sized, that midpoint is the boundary between + // them, so the carriage still lands inside its own zone. Both are a + // single term applied to the live primary position each frame: + // `term - pos` when mirrored, `pos + term` when tracked. + ImexMarkerPlan::Carriage carriage; + carriage.mirror_x = is_mirror && !cross_gantry; + carriage.mirror_y = is_mirror && cross_gantry; + carriage.x_term = carriage.mirror_x ? (float)(sec_center.x() + pri_center.x()) + : (float)(sec_center.x() - pri_center.x()); + carriage.y_term = carriage.mirror_y ? (float)(sec_center.y() + pri_center.y()) + : (float)(sec_center.y() - pri_center.y()); + + // The box shows the side a toolhead could COLLIDE from, not merely which + // way its body hangs. Tools sharing a gantry share an X rail and can + // actually run into each other, and only in a same-gantry (X-axis) mirror + // do they converge — so that is the one case where the secondary's box + // flips to face the primary. Tools on different gantries cannot collide + // in X at all, so a cross-gantry mirror keeps the primary's facing, the + // same as a Copy. Do not "fix" this to follow carriage geometry: a box on + // the far side would point away from the only tool it can hit. + if (is_mirror && !cross_gantry) { + if (sec_center.x() > pri_center.x()) carriage.box_offset_x = -plan.box_wx; + else if (sec_center.x() < pri_center.x()) carriage.box_offset_x = 0.0f; + else carriage.box_offset_x = plan.pri_box_offset_x; + } else { + carriage.box_offset_x = plan.pri_box_offset_x; + } + // Y follows the same collision rule: face the gantry you could hit. A tool + // on ANOTHER row faces the primary's row; a tool on the primary's OWN row + // shares its gantry and can only hit the same other gantry, so it faces + // wherever the primary faces. The old `else` hardcoded -imex_box_wy, which + // happens to equal pri_box_offset_y on the rear-* layouts (primary's row + // sits above the others, so the loop above settles on -box_wy anyway) + // — hence a no-op there. On the front-* layouts the primary flips to 0.0f + // and the hardcoded value pointed the same-gantry secondary away from the + // only tools it could run into. + if (sec_center.y() > pri_center.y()) carriage.box_offset_y = -plan.box_wy; + else if (sec_center.y() < pri_center.y()) carriage.box_offset_y = 0.0f; + else carriage.box_offset_y = plan.pri_box_offset_y; + + plan.carriages.push_back(carriage); + } + + return plan; +} + //BBS: GUI refactor: add canvas width and height void GCodeViewer::render(int canvas_width, int canvas_height, int right_margin) { @@ -1658,291 +1881,109 @@ void GCodeViewer::render(int canvas_width, int canvas_height, int right_margin) auto* mode_opt = process_cfg.opt<ConfigOptionString>("imex_parallel_mode"); std::string mode = mode_opt ? mode_opt->value : kImexPrimaryMode; // Per-plate mode overrides the process preset. - if (auto* plate = wxGetApp().plater()->get_partplate_list().get_curr_plate()) { - std::string plate_mode = plate->get_imex_mode(); + PartPlateList& plate_list = wxGetApp().plater()->get_partplate_list(); + PartPlate* curr_plate = plate_list.get_curr_plate(); + if (curr_plate) { + std::string plate_mode = curr_plate->get_imex_mode(); if (plate_mode != kImexPrimaryMode) mode = plate_mode; } - if (mode != m_imex_last_mode) { - m_sequential_view.m_imex_secondary_markers.clear(); - m_imex_last_mode = mode; + // Bed X and Y bounds — read from the current plate's shape, which is + // in world/GL coordinates (same space as curr_vertex.position), and is + // the exact same source PartPlate::calc_imex_zones() hands to the library. + BoundingBoxf bed_extents; + { + const Pointfs& plate_shape = curr_plate ? curr_plate->get_shape() : Pointfs{}; + if (!plate_shape.empty()) { + bed_extents = get_extents(plate_shape); + } else { + // Fallback: use toolpath bounding box extent + bed_extents = BoundingBoxf(Vec2d(m_paths_bounding_box.min.x(), m_paths_bounding_box.min.y()), + Vec2d(m_paths_bounding_box.max.x(), m_paths_bounding_box.max.y())); + } } - // Firmware-managed-zones centers the slice at bed origin, so prim_pos - // and the preview toolpaths sit in a shifted frame relative to the - // plate-local bed bounds the zone math uses. Computing secondaries here - // would place them off-bed. The firmware physically fans the centered - // toolpath out into the zones, so the centered preview with no - // secondaries is the honest representation. - auto* fw_opt = printer_cfg.opt<ConfigOptionBool>("imex_firmware_managed_zones"); - const bool firmware_managed = fw_opt && fw_opt->value; + // Cache guard. The marker plan below is resolved from preset/plate state only, + // so it is rebuilt when that state moves and reused otherwise — the sequential + // slider is sticky, and re-resolving the zone layout on every frame of the rest + // of the session showed up as a measurable per-frame cost. The comparison is + // deliberately made against the live config rather than against a freshly built + // key, so an unchanged frame allocates nothing at all. + static const std::vector<std::string> s_no_strings; + auto* gantry_opt = printer_cfg.opt<ConfigOptionInt>("imex_gantry_count"); + auto* tpg_opt = printer_cfg.opt<ConfigOptionInt>("imex_tools_per_gantry"); + auto* layout_opt = printer_cfg.opt<ConfigOptionEnum<ImexToolLayout>>("imex_tool_layout"); + auto* wx_opt = printer_cfg.opt<ConfigOptionFloat>("imex_nozzle_clearance_x"); + auto* wy_opt = printer_cfg.opt<ConfigOptionFloat>("imex_nozzle_clearance_y"); + auto* fw_opt = printer_cfg.opt<ConfigOptionBool>("imex_firmware_managed_zones"); + auto* names_opt = printer_cfg.opt<ConfigOptionStrings>("imex_mode_names"); + auto* tools_opt = printer_cfg.opt<ConfigOptionStrings>("imex_mode_active_tools"); + const std::vector<std::string>& mode_names = names_opt ? names_opt->values : s_no_strings; + const std::vector<std::string>& active_tools = tools_opt ? tools_opt->values : s_no_strings; - if (!firmware_managed && !mode.empty() && mode != kImexPrimaryMode) { - auto* mode_names_opt = printer_cfg.opt<ConfigOptionStrings>("imex_mode_names"); - auto* active_tools_opt = printer_cfg.opt<ConfigOptionStrings>("imex_mode_active_tools"); + ImexMarkerKey::Scalars key; + key.plate_index = plate_list.get_curr_plate_index(); + key.gantry_count = gantry_opt ? gantry_opt->value : 0; + key.tools_per_gantry = tpg_opt ? tpg_opt->value : 0; + key.tool_layout = layout_opt ? (int)layout_opt->value : -1; + key.clearance_x = wx_opt ? wx_opt->value : 0.0; + key.clearance_y = wy_opt ? wy_opt->value : 0.0; + key.firmware_managed = fw_opt && fw_opt->value; + key.bed_min_x = bed_extents.min.x(); + key.bed_min_y = bed_extents.min.y(); + key.bed_max_x = bed_extents.max.x(); + key.bed_max_y = bed_extents.max.y(); - auto* tpg_opt = printer_cfg.opt<ConfigOptionInt>("imex_tools_per_gantry"); - auto* gc_opt = printer_cfg.opt<ConfigOptionInt>("imex_gantry_count"); - auto* wx_opt = printer_cfg.opt<ConfigOptionFloat>("imex_nozzle_clearance_x"); - auto* wy_opt = printer_cfg.opt<ConfigOptionFloat>("imex_nozzle_clearance_y"); - int tools_per_gantry = tpg_opt ? std::max(1, tpg_opt->value) : 1; - int gantry_count = gc_opt ? std::max(1, gc_opt->value) : 1; - imex_box_wx = wx_opt ? (float)wx_opt->value : 30.0f; - imex_box_wy = wy_opt ? (float)wy_opt->value : 30.0f; + if (!(m_imex_marker_key.s == key) || m_imex_marker_key.mode != mode || + m_imex_marker_key.mode_names != mode_names || + m_imex_marker_key.mode_active_tools != active_tools) { + m_imex_marker_key = ImexMarkerKey{ key, mode, mode_names, active_tools }; + m_imex_marker_plan = resolve_imex_marker_plan(printer_cfg, mode, bed_extents); + // The carriage roster — and with it the marker count and colour order — + // can change with any of those inputs, so drop the markers and let the + // lazy init below rebuild them. + m_sequential_view.m_imex_secondary_markers.clear(); + } - // Parse "idx:P/C/M" via shared helpers — matches PartPlate::calc_imex_zones. - // Secondary state is 2=Copy / 3=Mirror to match the legacy encoding used - // downstream for marker color selection. - int pri_tool = -1; - std::vector<int> sec_tool_ids; - std::map<int,int> sec_tool_states; // tool_id -> 2=Copy, 3=Mirror - std::set<int> sec_aggregated; // representatives standing in for a whole gantry - // Which tools SIZE the grid is a different question from which tools get a - // MARKER. calc_imex_zones sizes its grid from every Copy/Mirror tool — an - // aggregated gantry's non-representatives still donate their column — while only - // the representative contributes a cell. Track both sets, or the strips here come - // out a different width than the ones painted on the plate and every marker - // drifts from its ghost. - std::vector<int> grid_tool_ids; - if (mode_names_opt && active_tools_opt) { - for (size_t i = 0; i < mode_names_opt->values.size(); ++i) { - if (i < active_tools_opt->values.size() && mode_names_opt->values[i] == mode) { - const std::string& entry = active_tools_opt->values[i]; - pri_tool = imex_primary_tool_for_mode(entry); - // Aggregate per gantry via the same source of truth as PartPlate's - // zone/ghost aggregation: in Span modes only one tool prints per - // zone at a time, so a non-primary gantry collapses to one - // representative marker. Non-Span gantries keep per-tool markers. - const ImexGantryGrouping grouping = - group_imex_active_tools_by_gantry(entry, tools_per_gantry); - auto add_tool = [&](int phys_idx, ImexRole role, bool aggregated) { - if (phys_idx < 0 || phys_idx == pri_tool) return; - if (role == ImexRole::Mirror) sec_tool_states[phys_idx] = 3; - else if (role == ImexRole::Copy) sec_tool_states[phys_idx] = 2; - else return; // Primary / Span carry no secondary marker - sec_tool_ids.push_back(phys_idx); - if (aggregated) sec_aggregated.insert(phys_idx); - }; - // Out-of-grid tool indices (a stale mode string carried over from a - // printer with more tools) are handled inconsistently by the code we - // must agree with: calc_imex_zones drops them, calc_imex_ghosts keeps - // them. No single policy matches both, so bound only what has to - // match the ZONE grid — the sizing set — and leave pri_tool and the - // markers exactly as they were. Clamping pri_tool instead is a trap: - // the -1 sentinel truncates to gantry 0 in imex_mirror_axis_for and - // flips the marker to the opposite mirror axis from the ghost. - const int grid_slots = tools_per_gantry * gantry_count; - for (const auto& grp : grouping.groups) { - // Grid sizing: every in-grid Copy/Mirror tool, aggregated or not — - // matches calc_imex_zones' ac_set/ar_set exactly. - for (const auto& [phys_idx, role] : grp.tools) { - if (phys_idx < 0 || phys_idx >= grid_slots) continue; - if (phys_idx == pri_tool) continue; - if (role == ImexRole::Copy || role == ImexRole::Mirror) - grid_tool_ids.push_back(phys_idx); - } - // Markers: an aggregated non-primary gantry shows only its rep. - if (grp.aggregate && grp.gantry_index != grouping.primary_gantry) - add_tool(grp.representative_phys, grp.representative_role, true); - else - for (const auto& [phys_idx, role] : grp.tools) - add_tool(phys_idx, role, false); - } - break; - } + const ImexMarkerPlan& plan = m_imex_marker_plan; + const int sec_count = (int)plan.carriages.size(); + if (sec_count > 0) { + imex_active = true; + imex_box_wx = plan.box_wx; + imex_box_wy = plan.box_wy; + + // Lazy init secondary nozzle markers + if ((int)m_sequential_view.m_imex_secondary_markers.size() != sec_count) { + m_sequential_view.m_imex_secondary_markers.resize(sec_count); + for (int i = 0; i < sec_count; ++i) { + m_sequential_view.m_imex_secondary_markers[i].init(m_marker_filename); + m_sequential_view.m_imex_secondary_markers[i].set_color( + s_carriage_colors[(i + 1) % s_carriage_colors.size()]); } } - int sec_count = (int)sec_tool_ids.size(); - if (sec_count > 0) { - imex_active = true; + const Vec3f prim_pos = libvgcode::convert(curr_vertex.position); + carriage_box_draws.push_back({ prim_pos, s_carriage_colors[0], + plan.pri_box_offset_x, plan.pri_box_offset_y }); - // Lazy init secondary nozzle markers - if ((int)m_sequential_view.m_imex_secondary_markers.size() != sec_count) { - m_sequential_view.m_imex_secondary_markers.resize(sec_count); - for (int i = 0; i < sec_count; ++i) { - m_sequential_view.m_imex_secondary_markers[i].init(m_marker_filename); - m_sequential_view.m_imex_secondary_markers[i].set_color( - s_carriage_colors[(i + 1) % s_carriage_colors.size()]); - } - } - - // Bed X and Y bounds — read from the current plate's shape, which is - // in world/GL coordinates (same space as curr_vertex.position), and is - // the exact same source used by PartPlate::calc_imex_zones(). - float bed_x_min, bed_x_max, bed_y_min, bed_y_max; - { - PartPlate* curr_plate = wxGetApp().plater()->get_partplate_list().get_curr_plate(); - const Pointfs& plate_shape = curr_plate ? curr_plate->get_shape() : Pointfs{}; - if (!plate_shape.empty()) { - bed_x_min = (float)plate_shape[0].x(); - bed_x_max = bed_x_min; - bed_y_min = (float)plate_shape[0].y(); - bed_y_max = bed_y_min; - for (const auto& pt : plate_shape) { - bed_x_min = std::min(bed_x_min, (float)pt.x()); - bed_x_max = std::max(bed_x_max, (float)pt.x()); - bed_y_min = std::min(bed_y_min, (float)pt.y()); - bed_y_max = std::max(bed_y_max, (float)pt.y()); - } - } else { - // Fallback: use toolpath bounding box extent - bed_x_min = (float)m_paths_bounding_box.min.x(); - bed_x_max = (float)m_paths_bounding_box.max.x(); - bed_y_min = (float)m_paths_bounding_box.min.y(); - bed_y_max = (float)m_paths_bounding_box.max.y(); - } - } - - // Apply the same flip logic as PartPlate::calc_imex_zones() so physical - // grid positions match the bed zone visualization. Use option<>() not - // opt<>(): enum options load from presets as ConfigOptionEnumGeneric, so - // opt<>()'s dynamic_cast to ConfigOptionEnum<ImexToolLayout> returns null - // and silently falls back to the FrontLeft default (flip_y wrong). - auto* layout_opt = printer_cfg.option<ConfigOptionEnum<ImexToolLayout>>("imex_tool_layout"); - const ImexToolLayout layout = layout_opt ? layout_opt->value : ImexToolLayout::FrontLeft; - const bool flip_x = (layout == ImexToolLayout::FrontRight || layout == ImexToolLayout::RearRight); - const bool flip_y = (layout == ImexToolLayout::RearLeft || layout == ImexToolLayout::RearRight); - - auto phys_col_of = [&](int tid) -> int { - int raw = tid % tools_per_gantry; - return flip_x ? (tools_per_gantry - 1 - raw) : raw; - }; - auto phys_row_of = [&](int tid) -> int { - int raw = tid / tools_per_gantry; - return flip_y ? (gantry_count - 1 - raw) : raw; - }; - - // Build active col/row sets — mirrors PartPlate::calc_imex_zones() so - // zone sizes and positions stay in sync with the bed visualization. - const int pri_phys_col = (pri_tool >= 0) ? phys_col_of(pri_tool) : 0; - const int pri_phys_row = (pri_tool >= 0) ? phys_row_of(pri_tool) : 0; - - // Grid sizing and cell placement answer different questions, and - // calc_imex_zones answers them differently — match it on both counts or the - // markers drift from the ghosts: - // sizing: every Copy/Mirror tool donates its OWN column/row (ac_set is - // built from tool_to_phys, unpinned), so an aggregated gantry's - // non-representatives still widen the grid. - // placement: an aggregated cell is PINNED to the primary's column - // (copy_cells/mirror_cells insert {pri_col, r}), because the - // row-strip spans full X and has no column of its own. - auto eff_col_of = [&](int tid) { - return sec_aggregated.count(tid) ? pri_phys_col : phys_col_of(tid); - }; - - std::map<int,int> phys_col_to_zone_gv, phys_row_to_zone_gv; - int n_active_cols_gv = 1, n_active_rows_gv = 1; - { - std::set<int> ac, ar; - ac.insert(pri_phys_col); ar.insert(pri_phys_row); - for (int tid : grid_tool_ids) { - ac.insert(phys_col_of(tid)); - ar.insert(phys_row_of(tid)); - } - // col_to_zone / row_to_zone: physical index → zone index (sorted) - int k = 0; - for (int c : ac) phys_col_to_zone_gv[c] = k++; - k = 0; - for (int r : ar) phys_row_to_zone_gv[r] = k++; - n_active_cols_gv = (int)ac.size(); - n_active_rows_gv = (int)ar.size(); - } - auto zone_col = [&](int pc) { auto it = phys_col_to_zone_gv.find(pc); return it != phys_col_to_zone_gv.end() ? it->second : 0; }; - auto zone_row = [&](int pr) { auto it = phys_row_to_zone_gv.find(pr); return it != phys_row_to_zone_gv.end() ? it->second : 0; }; - - const Vec3f prim_pos = libvgcode::convert(curr_vertex.position); - const float strip_width = (bed_x_max - bed_x_min) / (float)n_active_cols_gv; - const float row_strip_height = (bed_y_max - bed_y_min) / (float)n_active_rows_gv; - const int pri_zone_col = zone_col(pri_phys_col); - const int pri_zone_row = zone_row(pri_phys_row); - - // Primary carriage box - float pri_box_offset_x = (pri_zone_col == 0) ? 0.0f : -imex_box_wx; - float pri_box_offset_y = -imex_box_wy; - for (int i = 0; i < sec_count; ++i) { - int sc = eff_col_of(sec_tool_ids[i]); - int sr = phys_row_of(sec_tool_ids[i]); - if (sc > pri_phys_col) { pri_box_offset_x = 0.0f; } - else if (sc < pri_phys_col) { pri_box_offset_x = -imex_box_wx; } - if (sr > pri_phys_row) { pri_box_offset_y = 0.0f; } - else if (sr < pri_phys_row) { pri_box_offset_y = -imex_box_wy; } - } - carriage_box_draws.push_back({ prim_pos, s_carriage_colors[0], pri_box_offset_x, pri_box_offset_y }); - - const float pri_zone_x = bed_x_min + (float)pri_zone_col * strip_width; - const float pri_zone_y = bed_y_min + (float)pri_zone_row * row_strip_height; - const float rel_x = prim_pos.x() - pri_zone_x; - const float rel_y = prim_pos.y() - pri_zone_y; - - for (int i = 0; i < sec_count; ++i) { - int sec_phys_col = eff_col_of(sec_tool_ids[i]); - int sec_phys_row = phys_row_of(sec_tool_ids[i]); - int sec_zc = zone_col(sec_phys_col); - int sec_zr = zone_row(sec_phys_row); - const int sec_state = sec_tool_states[sec_tool_ids[i]]; - - // A carriage stays inside its own zone; a Mirror reflects its - // zone-relative offset about that zone's centerline, on the axis of the - // boundary it shares with primary — the same rule the ghosts use: - // Copy → tracks primary on both axes. - // Mirror, same gantry → reflect X (zones sit side by side). - // Mirror, other gantry → reflect Y (zones sit front-to-back); X - // tracks primary, since the part off that - // gantry is a Y-reflection of the tool - // directly behind it. - // The axis comes from the shared helper, so the markers can never drift - // out of step with the plate ghosts. - const bool is_mirror = (sec_state == 3); - const bool cross_gantry = imex_mirror_axis_for(pri_tool, sec_tool_ids[i], - tools_per_gantry) == ImexMirrorAxis::Y; - const float sec_zone_x = bed_x_min + (float)sec_zc * strip_width; - const float sec_zone_y = bed_y_min + (float)sec_zr * row_strip_height; - - const float sec_x = (is_mirror && !cross_gantry) - ? sec_zone_x + (strip_width - rel_x) - : sec_zone_x + rel_x; - const float sec_y = (is_mirror && cross_gantry) - ? sec_zone_y + (row_strip_height - rel_y) - : sec_zone_y + rel_y; - - Vec3f sec_pos{ sec_x, sec_y, prim_pos.z() }; - m_sequential_view.m_imex_secondary_markers[i].set_world_position(sec_pos); - m_sequential_view.m_imex_secondary_markers[i].set_z_offset(m_z_offset + 0.5f); - // The box shows the side a toolhead could COLLIDE from, not merely which - // way its body hangs. Tools sharing a gantry share an X rail and can - // actually run into each other, and only in a same-gantry (X-axis) mirror - // do they converge — so that is the one case where the secondary's box - // flips to face the primary. Tools on different gantries cannot collide - // in X at all, so a cross-gantry mirror keeps the primary's facing, the - // same as a Copy. Do not "fix" this to follow carriage geometry: a box on - // the far side would point away from the only tool it can hit. - float sec_box_offset_x; - if (is_mirror && !cross_gantry) { - if (sec_phys_col > pri_phys_col) sec_box_offset_x = -imex_box_wx; - else if (sec_phys_col < pri_phys_col) sec_box_offset_x = 0.0f; - else sec_box_offset_x = pri_box_offset_x; - } else { - sec_box_offset_x = pri_box_offset_x; - } - // Y follows the same collision rule: face the gantry you could hit. A tool - // on ANOTHER row faces the primary's row; a tool on the primary's OWN row - // shares its gantry and can only hit the same other gantry, so it faces - // wherever the primary faces. The old `else` hardcoded -imex_box_wy, which - // happens to equal pri_box_offset_y on the rear-* layouts (primary's row - // sits above the others, so the loop below settles on -imex_box_wy anyway) - // — hence a no-op there. On the front-* layouts the primary flips to 0.0f - // and the hardcoded value pointed the same-gantry secondary away from the - // only tools it could run into. - float sec_box_offset_y; - if (sec_phys_row > pri_phys_row) sec_box_offset_y = -imex_box_wy; - else if (sec_phys_row < pri_phys_row) sec_box_offset_y = 0.0f; - else sec_box_offset_y = pri_box_offset_y; - carriage_box_draws.push_back({ - sec_pos, s_carriage_colors[(i + 1) % s_carriage_colors.size()], - sec_box_offset_x, sec_box_offset_y }); - } + for (int i = 0; i < sec_count; ++i) { + const ImexMarkerPlan::Carriage& carriage = plan.carriages[i]; + // Tracking an axis translates the primary by the gap between the two + // zone centres; mirroring reflects it about the midpoint of those + // centres — the zones being equal-sized, that midpoint is the boundary + // between them, so the carriage still lands inside its own zone. Which + // axis does which, and both terms, come from resolve_imex_marker_plan(). + const Vec3f sec_pos{ carriage.mirror_x ? carriage.x_term - prim_pos.x() + : prim_pos.x() + carriage.x_term, + carriage.mirror_y ? carriage.y_term - prim_pos.y() + : prim_pos.y() + carriage.y_term, + prim_pos.z() }; + m_sequential_view.m_imex_secondary_markers[i].set_world_position(sec_pos); + m_sequential_view.m_imex_secondary_markers[i].set_z_offset(m_z_offset + 0.5f); + carriage_box_draws.push_back({ + sec_pos, s_carriage_colors[(i + 1) % s_carriage_colors.size()], + carriage.box_offset_x, carriage.box_offset_y }); } } } @@ -1961,18 +2002,22 @@ void GCodeViewer::render(int canvas_width, int canvas_height, int right_margin) // of an app_config entry is also treated as on. const bool show_toolhead_boxes = wxGetApp().app_config->get("show_imex_toolhead_boxes") != "false"; if (show_toolhead_boxes && !carriage_box_draws.empty() && imex_box_wx > 0.0f && imex_box_wy > 0.0f) { - // Rebuild box mesh every frame — dimensions can change via config edit without a - // G-code reload, so dimension-based caching isn't safe. + // The mesh depends only on the two clearance dimensions, which a config edit can + // change without a G-code reload — so rebuild it when they move (or when it has not + // been built yet) rather than on every frame. // Mesh origin: nozzle at x=0, centered in Y, Z starts at nozzle tip level. // Per-carriage box_offset_x shifts the mesh left or right so the nozzle lands // at the correct (collision-side) edge. - { + if (!m_imex_toolhead_box.is_initialized() || + m_imex_box_mesh_wx != imex_box_wx || m_imex_box_mesh_wy != imex_box_wy) { const float box_h = std::max(imex_box_wx, imex_box_wy); indexed_triangle_set its = its_make_cube((double)imex_box_wx, (double)imex_box_wy, (double)box_h); // No vertex pre-shifting — box_offset_x/y in the per-carriage transform // positions the nozzle at the correct collision-side edge. m_imex_toolhead_box.reset(); m_imex_toolhead_box.init_from(its); + m_imex_box_mesh_wx = imex_box_wx; + m_imex_box_mesh_wy = imex_box_wy; } GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 45a44406f2..6a66a2ce71 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -18,6 +18,7 @@ #include <cstdint> #include <float.h> #include <set> +#include <tuple> #include <unordered_set> namespace Slic3r { @@ -210,8 +211,84 @@ private: ConfigOptionMode m_user_mode; bool m_fold = {false}; std::string m_marker_filename; // cached for lazy secondary marker init - std::string m_imex_last_mode; // detect mode changes for secondary marker rebuild + + // IDEX/IQEX: everything render() needs to place the secondary carriage markers and the + // toolhead footprint boxes, resolved from the printer preset, the active mode and the + // plate bed. Resolving it walks the mode string through compute_imex_zone_layout() + // (several string parses plus a zone-grid rebuild), and none of its inputs change + // between frames, so it is resolved once per input change -- see ImexMarkerKey -- and + // replayed on every other frame. + struct ImexMarkerPlan + { + // One entry per secondary carriage that owns a zone, in marker order. Each axis + // either TRACKS the primary (pos + term) or MIRRORS it about the boundary the two + // zones share (term - pos); which of the two, and the term itself, depend only on + // the zone geometry, so both are resolved up front. + struct Carriage + { + bool mirror_x = false; + bool mirror_y = false; + float x_term = 0.0f; + float y_term = 0.0f; + float box_offset_x = 0.0f; + float box_offset_y = 0.0f; + }; + std::vector<Carriage> carriages; // empty => no secondary carriages to draw + float pri_box_offset_x = 0.0f; + float pri_box_offset_y = 0.0f; + float box_wx = 0.0f; // imex_nozzle_clearance_x / _y + float box_wy = 0.0f; + }; + + // Invalidation key for the plan above: every input the plan is derived from, and + // nothing that changes between frames. A stale plan would put the preview markers + // somewhere the plate's own zones and ghosts do not agree with, which is exactly the + // drift the shared layout call exists to prevent -- so this deliberately mirrors + // PartPlate::build_imex_cache_key(), and adds the two inputs only the preview reads: + // the plate's bed extents (zone centres scale with them) and imex_tool_layout (the + // T0-corner flips inside compute_imex_zone_layout). imex_carriage_margin is absent on + // purpose: it only sizes the plate's advisory bands, which the preview never draws. + struct ImexMarkerKey + { + // Scalar half. Built fresh on the stack each frame -- it allocates nothing -- and + // compared as a tuple. + struct Scalars + { + int plate_index = -1; + int gantry_count = 0; + int tools_per_gantry = 0; + int tool_layout = -1; + double clearance_x = 0.0; + double clearance_y = 0.0; + bool firmware_managed = false; + double bed_min_x = 0.0, bed_min_y = 0.0, bed_max_x = 0.0, bed_max_y = 0.0; + + auto tied() const { + return std::tie(plate_index, gantry_count, tools_per_gantry, tool_layout, + clearance_x, clearance_y, firmware_managed, + bed_min_x, bed_min_y, bed_max_x, bed_max_y); + } + bool operator==(const Scalars& rhs) const { return tied() == rhs.tied(); } + }; + Scalars s; + // Resolved active mode (the plate's mode beats the process preset), plus the printer + // preset's whole mode table. The name alone is not identity: two presets can carry + // the same mode name over different tool rosters, and editing a roster in place + // moves neither the name nor any scalar above. Compared by value, never copied + // unless something actually changed. + std::string mode; + std::vector<std::string> mode_names; + std::vector<std::string> mode_active_tools; + }; + ImexMarkerKey m_imex_marker_key; + ImexMarkerPlan m_imex_marker_plan; + static ImexMarkerPlan resolve_imex_marker_plan(const DynamicPrintConfig& printer_cfg, + const std::string& mode, + const BoundingBoxf& bed_extents); + GLModel m_imex_toolhead_box; // shared box mesh for all carriage footprint overlays + float m_imex_box_mesh_wx{ 0.0f }; // clearance dimensions m_imex_toolhead_box was built for + float m_imex_box_mesh_wy{ 0.0f }; size_t m_extruders_count; std::vector<float> m_filament_diameters; From 7c49660c05b5b36b72f06185a480621effa30278 Mon Sep 17 00:00:00 2001 From: Clifford Garwood <cliff@cigii.com> Date: Thu, 3 Sep 2026 00:56:55 -0400 Subject: [PATCH 43/51] Share one routing derivation with the slicer, and stop two GUI paths acting on non-IMEX printers Closes review comment 20; the other two are non-IMEX leaks found auditing the branch. collect_imex_warnings re-derived the active mode, its tools, the primary and the filament routing that Print::validate also derives, so the warning and the hard block could drift apart -- and this function had already had one index-confusion bug, the AFC/MMU wrong-filament names fixed in fbc58d2a1d. Both now read imex_resolve_routing() and derive nothing themselves. The function stays file-static: what is left in it is PresetBundle lookups, bed-type resolution and formatting, none of which can disagree with the slicer about what the plate is doing, and the index-confusion surface is now library code with tests covering the AFC manifold in both directions. A latent out-of-bounds read went with it -- the primary fallback can return -1 and the bounds checks were upper-only, so filament_presets[-1] was reachable on a profile whose roster names a head absent from the map. Slicing eagerly re-rendered every plate thumbnail on the main thread after switching to Preview, up to two blocking offscreen GL renders per plate on every slice click. The work was already redundant: select_view_3D("Preview") invalidates the thumbnails and marks the toolbar dirty, and the next frame force-regenerates them anyway. It could not have served its stated purpose either, since it ran immediately after reslice(), which only starts the background slice. Both calls dropped; the plate badge state is recomputed per frame and is unaffected. The export_3mf thumbnail log lines are back at info, and the slice-event traces restored. The Moonraker device sync wrote physical_extruder_map into the edited printer preset ungated, so any Klipper machine running a current AFC build had its preset marked dirty with no user action, and saving persisted the map into every 3MF after. The map is indexed by logical extruder while the device reports one entry per lane, and nothing in the lane payload carries the logical slot, so the two index spaces coincide only when the counts match. Now gated on is_imex, written only when the counts agree, and only when the value actually differs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- src/slic3r/GUI/Plater.cpp | 136 ++++++++++----------- src/slic3r/Utils/MoonrakerPrinterAgent.cpp | 38 +++++- 2 files changed, 100 insertions(+), 74 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 68b02e03c5..0d1360b37c 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -10508,13 +10508,6 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool else invalidated = background_process.apply(this->model, preset_bundle->full_config(false)); - // IMEX firmware-managed zones: refresh the per-slice XY shift on the print backend. - // Plater::reslice() calls update_background_process with switch_print=false, which skips - // update_slice_context_to_current_plate — so the offset would otherwise stay stale across - // mode changes. Pushing it here guarantees every slice picks up the current mode + zone. - if (auto* cur_plate = this->partplate_list.get_curr_plate()) - cur_plate->refresh_imex_slice_offset(); - if ((invalidated == Print::APPLY_STATUS_CHANGED) || (invalidated == Print::APPLY_STATUS_INVALIDATED)) // BBS: add only gcode mode q->set_only_gcode(false); @@ -12692,10 +12685,17 @@ void Plater::priv::on_action_open_project(SimpleEvent&) // Orca IMEX: Collects all IMEX-related warnings for a plate before slicing. // Returns one formatted bullet string per issue. Empty means no concerns. // Checks: -// 1. Multi-material objects alongside a parallel mode (existing badge condition) -// 2. Bed temperature conflict: primary tool controls the bed; secondary tools warned +// 1. Bed temperature conflict: primary tool controls the bed; secondary tools warned // if their optimal bed temp differs from the primary's by more than 5°C -// 3. Filament type mismatch: materials with incompatible requirements +// 2. Filament type mismatch: materials with incompatible requirements +// +// Deliberately a thin GUI wrapper, and deliberately still file-static. Everything it once +// derived for itself -- the active mode, its tool roster, the declared primary, and whether +// this plate's filaments route to that primary -- now comes from imex_resolve_routing() in +// libslic3r, which Print::validate() calls too and which tests/libslic3r/test_imex_helpers.cpp +// covers. What is left here is genuinely GUI: PresetBundle lookups, bed-type resolution, +// preset -> filament-type strings, and _L() formatting. None of that is worth exposing to a +// test, and none of it can disagree with the slicer about what the plate is doing. static std::vector<wxString> collect_imex_warnings(PartPlate* plate) { std::vector<wxString> warnings; @@ -12714,30 +12714,36 @@ static std::vector<wxString> collect_imex_warnings(PartPlate* plate) PresetBundle* bundle = wxGetApp().preset_bundle; if (!bundle) return warnings; - // Resolve active tool indices for this mode from printer config - const auto& printer_cfg = bundle->printers.get_edited_preset().config; - const auto* mode_names_opt = printer_cfg.option<ConfigOptionStrings>("imex_mode_names"); - const auto* tools_opt = printer_cfg.option<ConfigOptionStrings>("imex_mode_active_tools"); + // The mode's tool roster, its declared primary, and which logical filament slot the + // primary prints with all come from imex_resolve_routing() -- the same library call + // Print::validate() makes for its hard block, so the sentence shown here and the refusal + // shown at slice time cannot describe the plate differently. An unresolved mode, and a + // mode the tools array is too short to cover, both yield an empty roster and no primary, + // which is the same "nothing to warn about" answer the open-coded lookup gave. + // + // The pem source is the GUI's own (effective_physical_extruder_map on the live bundle); + // Print::apply() normalises the slicer's copy through the same helper, so the two agree. + const ConfigOptionInts pem = effective_physical_extruder_map(*bundle); + const ImexRouting routing = imex_resolve_routing(bundle->printers.get_edited_preset().config, + mode, plate->get_extruders(true), pem); - // Upper bound: filament_presets.size() is the practical limit, capped at MAXIMUM_EXTRUDER_NUMBER (64) + // Upper bound: filament_presets.size() is the practical limit, capped at MAXIMUM_EXTRUDER_NUMBER (64). + // GUI-only: every warning below names a filament preset, so a tool with no preset to + // name is one this dialog has nothing to say about. The slicer has no such limit -- + // it refuses the plate outright rather than describing it. const size_t max_tool = std::min(bundle->filament_presets.size(), MAXIMUM_EXTRUDER_NUMBER); std::vector<int> active_tools; - int primary_tool = -1; - if (mode_names_opt && tools_opt) { - for (size_t i = 0; i < mode_names_opt->values.size(); ++i) { - if (i >= tools_opt->values.size() || mode_names_opt->values[i] != mode) continue; - const std::string& entry = tools_opt->values[i]; - primary_tool = imex_primary_tool_for_mode(entry); - for (const auto& [phys_idx, role] : parse_imex_active_tools(entry)) { - (void)role; - if (phys_idx >= 0 && (max_tool == 0 || (size_t)phys_idx < max_tool)) - active_tools.push_back(phys_idx); - } - break; - } + const int primary_tool = routing.primary_phys; + for (const auto& [phys_idx, role] : routing.tools) { + (void)role; + // parse_imex_active_tools already drops negative indices. + if (max_tool == 0 || (size_t)phys_idx < max_tool) + active_tools.push_back(phys_idx); } + // Two or more tools is what makes a primary/secondary comparison meaningful; both checks + // below are primary-vs-secondary. A single-tool roster is left to Print::validate. if (active_tools.size() < 2 || primary_tool < 0) return warnings; const DynamicPrintConfig& full_cfg = bundle->full_config(); // Bed temps are per-plate-type; resolve the active plate's bed type to get the right key. @@ -12746,48 +12752,42 @@ static std::vector<wxString> collect_imex_warnings(PartPlate* plate) const auto* bed_temps = bed_temp_key.empty() ? nullptr : full_cfg.option<ConfigOptionInts>(bed_temp_key); const auto& filament_presets = bundle->filament_presets; - // active_tools and primary_tool are PHYSICAL extruder indices (parsed from + // active_tools and primary_tool are PHYSICAL extruder indices (from // imex_mode_active_tools). filament_presets and bed_temps are indexed by LOGICAL // filament slot. For MMU/AFC layouts where multiple logical slots feed one // physical extruder, looking up filament_presets[physical_idx] returns the wrong // filament. Translate physical -> logical before indexing. // // Primary vs secondary use DIFFERENT translation rules: - // - Primary's filament: the slot the user assigned to the printing object(s). - // Walk plate->get_extruders() and pick a slot whose pem entry maps to the - // primary's physical index. If multiple slots qualify, the first match wins. + // - Primary's filament: routing.primary_logical, the slot the plate's objects put on + // the primary's physical head. -1 there is exactly the condition Print::validate + // refuses the plate on (ImexRouting::primary_unrouted); this dialog runs first and + // still wants a filament to name, so it falls back to the printer's own routing. // - Secondary's filament: per-plate imex_head_filament_map override (set via // the IMEX ghost picker). No object owns a secondary in copy/mirror mode — - // the firmware duplicates the primary, so the override is the only source. - // - Both fall back to first_filament_for_physical_head as a last resort so a - // warning still has *some* filament to name. - const ConfigOptionInts pem = effective_physical_extruder_map(*bundle); + // the firmware duplicates the primary, so the override is the only source. Stays + // GUI-local: the slicer never has to name a secondary's filament. std::map<int, int> plate_head_map; if (auto* hfm = plate->config()->option<ConfigOptionString>("imex_head_filament_map")) plate_head_map = parse_imex_head_filament_map(hfm->value); - auto logical_for_primary = [&](int physical_idx) -> int { - // get_extruders() returns 1-based filament slots used by objects on this plate. - const int from_objects = imex_primary_logical_from_objects( - plate->get_extruders(true), pem, physical_idx); - if (from_objects >= 0) return from_objects; - // No object on the plate routes to this physical: defensive fallback so the - // warning still has *something* to name. In practice this shouldn't fire when - // the active mode says this physical is primary — there has to be something - // assigned to it for the slicer to print. - return first_filament_for_physical_head(pem, physical_idx); - }; auto logical_for_secondary = [&](int physical_idx) -> int { const int logical = resolve_filament_for_head(plate_head_map, pem, physical_idx); return logical >= 0 ? logical : physical_idx; }; - // Primary tool's bed temp and filament type (looked up by logical slot) - const int primary_logical = logical_for_primary(primary_tool); - const int primary_bed_temp = (bed_temps && primary_logical < (int)bed_temps->values.size()) + // Primary tool's bed temp and filament type (looked up by logical slot). Both lookups + // are guarded against a negative slot: first_filament_for_physical_head() returns -1 for + // a primary no logical filament reaches at all, and `-1 < size()` would otherwise index + // in front of the array. + const int primary_logical = routing.routes_to_primary() + ? routing.primary_logical + : first_filament_for_physical_head(pem, primary_tool); + const int primary_bed_temp = (bed_temps && primary_logical >= 0 && + primary_logical < (int)bed_temps->values.size()) ? bed_temps->values[primary_logical] : 0; std::string primary_display_type; - if (primary_logical < (int)filament_presets.size()) { + if (primary_logical >= 0 && primary_logical < (int)filament_presets.size()) { Preset* p = bundle->filaments.find_preset(filament_presets[primary_logical]); if (p) p->get_filament_type(primary_display_type); } @@ -12806,7 +12806,7 @@ static std::vector<wxString> collect_imex_warnings(PartPlate* plate) } if (secondary_display_type.empty()) secondary_display_type = "unknown"; - // Check 2: bed temperature — primary wins, secondary may not get what it needs + // Check 1: bed temperature — primary wins, secondary may not get what it needs if (bed_temps && primary_bed_temp > 0 && secondary_logical < (int)bed_temps->values.size()) { const int secondary_bed_temp = bed_temps->values[secondary_logical]; if (secondary_bed_temp > 0 && std::abs(secondary_bed_temp - primary_bed_temp) > 5) { @@ -12819,7 +12819,7 @@ static std::vector<wxString> collect_imex_warnings(PartPlate* plate) } } - // Check 3: filament type mismatch + // Check 2: filament type mismatch if (primary_display_type != secondary_display_type && primary_display_type != "unknown" && secondary_display_type != "unknown") { warnings.push_back(wxString::Format( @@ -12836,6 +12836,7 @@ static std::vector<wxString> collect_imex_warnings(PartPlate* plate) void Plater::priv::on_action_slice_plate(SimpleEvent&) { if (q != nullptr) { + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ":received slice plate event\n" ; // IMEX parallel mode warnings (current plate only) if (wxGetApp().app_config->get("imex_pre_slice_warnings") != "false") { PartPlate* plate = partplate_list.get_curr_plate(); @@ -12869,8 +12870,6 @@ void Plater::priv::on_action_slice_plate(SimpleEvent&) m_slice_all = false; q->reslice(); q->select_view_3D("Preview"); - // Regenerate any thumbnails that were wiped by the panel switch above. - q->update_all_plate_thumbnails(); } } @@ -12878,6 +12877,7 @@ void Plater::priv::on_action_slice_plate(SimpleEvent&) void Plater::priv::on_action_slice_all(SimpleEvent&) { if (q != nullptr) { + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ":received slice project event\n" ; // IMEX parallel mode warnings (all plates) if (wxGetApp().app_config->get("imex_pre_slice_warnings") != "false") { wxString combined_msg; @@ -12923,8 +12923,6 @@ void Plater::priv::on_action_slice_all(SimpleEvent&) q->reslice(); if (!m_is_publishing) q->select_view_3D("Preview"); - // Regenerate any thumbnails that were wiped by the panel switch above. - q->update_all_plate_thumbnails(); //BBS: wish to select all plates stats item preview->get_canvas3d()->_update_select_plate_toolbar_stats_item(true); } @@ -16998,6 +16996,7 @@ void Plater::invalid_all_plate_thumbnails() { if (using_exported_file() || skip_thumbnail_invalid) return; + BOOST_LOG_TRIVIAL(info) << "thumb: invalid all"; for (int i = 0; i < get_partplate_list().get_plate_count(); i++) { PartPlate* plate = get_partplate_list().get_plate(i); plate->thumbnail_data.reset(); @@ -18811,10 +18810,10 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy ThumbnailData* thumbnail_data = &p->partplate_list.get_plate(i)->thumbnail_data; if (p->partplate_list.get_plate(i)->thumbnail_data.is_valid() && using_exported_file()) { //no need to generate thumbnail - BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": non need to re-generate thumbnail for gcode/exported mode of plate %1%")%i; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": non need to re-generate thumbnail for gcode/exported mode of plate %1%")%i; } else { - BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": re-generate thumbnail for plate %1%") % i; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": re-generate thumbnail for plate %1%") % i; const ThumbnailsParams thumbnail_params = { {}, false, true, true, true, i }; p->generate_thumbnail(p->partplate_list.get_plate(i)->thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, thumbnail_params, Camera::EType::Ortho); @@ -18824,9 +18823,9 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy ThumbnailData *no_light_thumbnail_data = &p->partplate_list.get_plate(i)->no_light_thumbnail_data; if (p->partplate_list.get_plate(i)->no_light_thumbnail_data.is_valid() && using_exported_file()) { // no need to generate thumbnail - BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": non need to re-generate thumbnail for gcode/exported mode of plate %1%") % i; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": non need to re-generate thumbnail for gcode/exported mode of plate %1%") % i; } else { - BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": re-generate thumbnail for plate %1%") % i; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": re-generate thumbnail for plate %1%") % i; const ThumbnailsParams thumbnail_params = {{}, false, true, true, true, i}; p->generate_thumbnail(p->partplate_list.get_plate(i)->no_light_thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, thumbnail_params, Camera::EType::Ortho, Camera::ViewAngleType::Iso, false, true); @@ -18841,10 +18840,10 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy ThumbnailData* top_thumbnail = &p->partplate_list.get_plate(i)->top_thumbnail_data; if (top_thumbnail->is_valid() && using_exported_file()) { //no need to generate thumbnail - BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": non need to re-generate top_thumbnail for gcode/exported mode of plate %1%")%i; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": non need to re-generate top_thumbnail for gcode/exported mode of plate %1%")%i; } else { - BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": re-generate top_thumbnail for plate %1%") % i; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": re-generate top_thumbnail for plate %1%") % i; const ThumbnailsParams thumbnail_params = { {}, false, true, false, true, i }; p->generate_thumbnail(p->partplate_list.get_plate(i)->top_thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, thumbnail_params, Camera::EType::Ortho, Camera::ViewAngleType::Top_Plate, false); @@ -18854,10 +18853,10 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy ThumbnailData* picking_thumbnail = &p->partplate_list.get_plate(i)->pick_thumbnail_data; if (picking_thumbnail->is_valid() && using_exported_file()) { //no need to generate thumbnail - BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": non need to re-generate pick_thumbnail for gcode/exported mode of plate %1%")%i; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": non need to re-generate pick_thumbnail for gcode/exported mode of plate %1%")%i; } else { - BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": re-generate pick_thumbnail for plate %1%") % i; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": re-generate pick_thumbnail for plate %1%") % i; const ThumbnailsParams thumbnail_params = { {}, false, true, false, true, i }; p->generate_thumbnail(p->partplate_list.get_plate(i)->pick_thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, thumbnail_params, Camera::EType::Ortho, Camera::ViewAngleType::Top_Plate, true,true); @@ -21757,11 +21756,8 @@ int Plater::select_plate_by_hover_id(int hover_id, bool right_click, bool isModi std::vector<std::string> modes; modes.push_back(kImexPrimaryMode); const DynamicPrintConfig& printer_cfg = wxGetApp().preset_bundle->printers.get_edited_preset().config; - auto* names_opt = printer_cfg.option<ConfigOptionStrings>("imex_mode_names"); - if (names_opt) { - for (const auto& n : names_opt->values) - if (!n.empty() && n != kImexPrimaryMode) modes.push_back(n); - } + for (const ImexMode& m : imex_mode_table(printer_cfg)) + if (!m.name.empty() && m.name != kImexPrimaryMode) modes.push_back(m.name); if (right_click) { // Show a popup menu with all modes. diff --git a/src/slic3r/Utils/MoonrakerPrinterAgent.cpp b/src/slic3r/Utils/MoonrakerPrinterAgent.cpp index 717154b93f..98e92bfd90 100644 --- a/src/slic3r/Utils/MoonrakerPrinterAgent.cpp +++ b/src/slic3r/Utils/MoonrakerPrinterAgent.cpp @@ -590,10 +590,11 @@ bool MoonrakerPrinterAgent::fetch_filament_info(std::string dev_id) int ams_count = (max_lane_index + 4) / 4; build_ams_payload(ams_count, max_lane_index, trays); - // If every tray reported extruder_index, auto-populate physical_extruder_map - // so IMEX PA and temperature emission use the correct physical extruder qualifier. - // AFC publishes extruder_index=0 for all AFC lanes (they share one carriage) and - // extruder_index=N for independent direct-drive tools on separate carriages. + // If every tray reported extruder_index, auto-populate physical_extruder_map on an + // IMEX printer so IMEX PA and temperature emission use the correct physical extruder + // qualifier. AFC publishes extruder_index=0 for all AFC lanes (they share one carriage) + // and extruder_index=N for independent direct-drive tools on separate carriages. + // The write itself is gated below, on the GUI thread, where the preset can be read. bool all_have_extruder_index = std::all_of(trays.begin(), trays.end(), [](const AmsTrayData& t) { return t.extruder_index >= 0; }); if (all_have_extruder_index) { @@ -605,6 +606,35 @@ bool MoonrakerPrinterAgent::fetch_filament_info(std::string dev_id) auto* bundle = GUI::wxGetApp().preset_bundle; if (!bundle) return; auto& config = bundle->printers.get_edited_preset().config; + + // Only IMEX profiles read physical_extruder_map as logical -> physical extruder. + // Elsewhere in the tree the key carries the BBL extruder-id reading, or is unused + // entirely (a single-nozzle Klipper machine), so writing the device's lane data + // there would silently mutate an unrelated setting -- and dirty the preset with + // no user action -- for every AFC user who is not running IMEX. + const auto* is_imex = config.option<ConfigOptionBool>("is_imex"); + if (!is_imex || !is_imex->value) return; + + // The map has one entry per LOGICAL extruder, i.e. the nozzle_diameter index + // space (see effective_physical_extruder_map() in IMEXHelpers.cpp). The device + // reports one entry per lane, which is the same index space only when the counts + // match; when they differ the lane -> logical extruder correspondence is not + // knowable here, and a wrong-length map is discarded by PrintApply anyway, so + // leave whatever the profile authored alone rather than writing a map that + // nothing will honour. + const auto* nozzles = config.option<ConfigOptionFloats>("nozzle_diameter"); + if (!nozzles || nozzles->values.size() != pem.size()) { + BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent: skipping physical_extruder_map sync, device reports " + << pem.size() << " lanes but the printer profile has " + << (nozzles ? nozzles->values.size() : 0) << " logical extruders"; + return; + } + + // Write only on a real change: an unconditional set_key_value() marks the printer + // preset dirty on every device poll, so the user sees unsaved changes they never made. + const auto* current = config.option<ConfigOptionInts>("physical_extruder_map"); + if (current && current->values == pem) return; + config.set_key_value("physical_extruder_map", new ConfigOptionInts(pem)); BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent: auto-populated physical_extruder_map from AFC extruder_index"; }); From bd8dfd6250e03a0bc2321bd1e36a3cbceb1e2a26 Mon Sep 17 00:00:00 2001 From: Clifford Garwood <cliff@cigii.com> Date: Thu, 3 Sep 2026 00:57:14 -0400 Subject: [PATCH 44/51] Cover the IMEX slice offset, the mode G-code placeholders, and the non-IMEX heater guard Closes review comments 13, 14 and 15, and adds the test for a shipped-profile regression that nothing guarded. - 14 and 15: compute_imex_slice_offset had eight tests on the calculation and none on the result, which is the whole firmware-managed path. test_imex_slice_offset now covers the derivation end (which config produces a non-zero offset, and that it is plate-local rather than moving with the plate origin -- the bug that shifted every plate after the first) and the consumption end (emitted coordinates and first_layer_print_min/max both move by the derived amount). The first_layer case also cross-checks the two consumers against each other: the declared bounds must keep the same relationship to the emitted toolpaths in both frames, which fails if exactly one of them is shifted. It deliberately does not pin the size of that gap -- it is 2.225 mm here, set by the wall generator, the same with no offset at all, and pinning it would fail on an unrelated change. - 13: nothing exercised the imex_mode / imex_mode_index / imex_mode_gcode placeholders or the {global} flow into machine_start_gcode that their ordering exists to guarantee. Seven cases now do, including the ordering itself -- the mode script declares a global and machine_start_gcode reads it back, so moving the mode processing later leaves the variable undefined and fails the export -- plus the inert cases (Primary mode, and a printer with the table filled in but is_imex off). All matching is whole-line, because the config block the exporter appends repeats machine_start_gcode verbatim and would make substring checks meaningless. - New: GCodeWriter passes this->config.is_imex.value into the heater remap, and nothing tested that it passes the flag rather than a constant. Hardcode true there and the whole suite stays green while fdm_bbl_3dp_002_common, which ships physical_extruder_map [1,0], starts sending filament 0's M104/M109 to heater 1. The new case runs a two-nozzle non-IMEX printer with that map and asserts each filament's temperature reaches only its own tool. It uses idle_temperature via ooze prevention rather than nozzle_temperature: keys in filament_options_with_variant are re-indexed per filament by variant slot at apply time, and this harness pins nozzle_diameter to one value, so every filament resolves to the same slot and the temperatures stop telling the heads apart. Also fixes two weaknesses in tests added earlier in this branch: an assertion that would have been prefix-satisfied by the very routing it was meant to exclude, and a whole-file command comparison between two slices, which this slicer's output is not stable enough to support. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- tests/fff_print/CMakeLists.txt | 2 + tests/fff_print/test_imex_mode_gcode.cpp | 317 +++++++++++++ tests/fff_print/test_imex_slice_offset.cpp | 489 +++++++++++++++++++++ tests/fff_print/test_multifilament.cpp | 160 +++++++ 4 files changed, 968 insertions(+) create mode 100644 tests/fff_print/test_imex_mode_gcode.cpp create mode 100644 tests/fff_print/test_imex_slice_offset.cpp diff --git a/tests/fff_print/CMakeLists.txt b/tests/fff_print/CMakeLists.txt index fc46bb8fdc..f81fdb239a 100644 --- a/tests/fff_print/CMakeLists.txt +++ b/tests/fff_print/CMakeLists.txt @@ -10,6 +10,8 @@ add_executable(${_TEST_NAME}_tests test_flow.cpp test_gcode_timing.cpp test_gcodewriter.cpp + test_imex_mode_gcode.cpp + test_imex_slice_offset.cpp test_model.cpp test_multifilament.cpp test_perimeters.cpp diff --git a/tests/fff_print/test_imex_mode_gcode.cpp b/tests/fff_print/test_imex_mode_gcode.cpp new file mode 100644 index 0000000000..d09feb93c4 --- /dev/null +++ b/tests/fff_print/test_imex_mode_gcode.cpp @@ -0,0 +1,317 @@ +#include <catch2/catch_all.hpp> + +#include "libslic3r/Config.hpp" +#include "libslic3r/PrintConfig.hpp" + +#include "test_helpers.hpp" +#include "test_utils.hpp" + +#include <cstddef> +#include <string> +#include <vector> + +using namespace Slic3r; +using namespace Slic3r::Test; + +// The IMEX mode placeholders ({imex_mode}, {imex_mode_index}, {imex_mode_gcode}) and the mode +// script that consumes them are set up in GCode.cpp's _do_export, immediately before +// machine_start_gcode is processed. Two contracts live in that ordering: +// * the three placeholders exist for every G-code script the export runs, IMEX or not; +// * the mode script is itself run through the placeholder parser, and it runs FIRST, so a +// {global ...} it declares is in scope by the time machine_start_gcode is processed. +// Nothing else in the suite exercises them. + +// Offset of the first line of `gcode` that equals `expected` once trailing whitespace is +// stripped, or npos. Whole-line matching is deliberate on both counts: prefix matching would +// let ";IMEX_MODE_INDEX:2" pass for an emitted index of 20, and the config block the exporter +// appends to every file repeats machine_start_gcode and imex_mode_gcodes verbatim (as +// "; key = value"), which would make any substring search for the templates below trivially +// true and every "not emitted" assertion trivially false. +static std::size_t find_exact_line(const std::string &gcode, const std::string &expected) +{ + std::size_t pos = 0; + while (pos <= gcode.size()) { + const std::size_t eol = gcode.find('\n', pos); + const std::size_t end = (eol == std::string::npos) ? gcode.size() : eol; + std::string line = gcode.substr(pos, end - pos); + while (!line.empty() && (line.back() == '\r' || line.back() == ' ' || line.back() == '\t')) + line.pop_back(); + if (line == expected) + return pos; + if (eol == std::string::npos) + break; + pos = eol + 1; + } + return std::string::npos; +} + +static bool has_line(const std::string &gcode, const std::string &expected) +{ + return find_exact_line(gcode, expected) != std::string::npos; +} + +// Mode scripts. Free of placeholders so that a test can tell "the script was emitted" apart +// from "the script was expanded"; the expansion case below supplies its own template. +static const char *kCopyScript = "SET_DUAL_CARRIAGE MODE=COPY"; +static const char *kQuadScript = "SET_QUAD_CARRIAGE MODE=COPY"; + +// Reports all three placeholders on their own lines so find_exact_line can pin each value. +static const char *kReportStartGcode = ";IMEX_MODE:{imex_mode}\n" + ";IMEX_MODE_INDEX:{imex_mode_index}\n" + ";IMEX_MODE_GCODE:{imex_mode_gcode}\n"; + +// Shared IMEX printer geometry: 7 logical extruders across 4 physical heads, three modes. +// physical_extruder_map is only honoured when its length matches the nozzle count +// (PrintApply feeds effective_physical_extruder_map the nozzle_diameter size), so the nozzle +// keys must be sized to 7 or the map is silently replaced with the identity and IMEX quietly +// stops happening at all. Mirrors imex_7x4_printer() in test_multifilament.cpp; `iq-copy` is +// carried over from the IQEX case there, which is a mode combination known to slice. +// +// imex_mode_gcodes is left to each test: the position a mode's script occupies in this list is +// exactly what {imex_mode_index} is asserted against. +static void imex_7x4_printer(DynamicPrintConfig &config) +{ + config.set_deserialize_strict({ + { "nozzle_diameter", "0.4,0.4,0.4,0.4,0.4,0.4,0.4" }, + { "printer_extruder_id", "1,2,3,4,5,6,7" }, + { "printer_extruder_variant", "Direct Drive Standard,Direct Drive Standard,Direct Drive Standard," + "Direct Drive Standard,Direct Drive Standard,Direct Drive Standard," + "Direct Drive Standard" }, + { "extruder_printable_height", "0,0,0,0,0,0,0" }, + { "physical_extruder_map", "0,0,0,0,1,2,3" }, + { "is_imex", "1" }, + { "imex_mode_names", "primary;copy;iq-copy" }, + { "imex_mode_active_tools", "0:P;0:P,1:C;0:P,1:C,2:C,3:C" }, + { "skirt_loops", "0" }, + { "brim_type", "no_brim" }, + // Klipper skips the bed/extruder temperature block that would otherwise be written + // between the mode script and machine_start_gcode, so the ordering assertion below + // compares the two scripts and nothing else. + { "gcode_flavor", "klipper" }, + }); +} + +// Set the mode scripts positionally, one per name in imex_mode_names. Assigning the vector +// beats set_deserialize_strict here: a coStrings round trip through a ';'-joined string has to +// quote and escape empty entries and embedded braces, and the empty first entry (primary, which +// deliberately has no script) is exactly the entry that would be lost. +static void set_mode_gcodes(DynamicPrintConfig &config, const std::vector<std::string> &gcodes) +{ + config.option<ConfigOptionStrings>("imex_mode_gcodes", true)->values = gcodes; +} + +// Route every region to one filament. An unset *_filament_id is not "inherit": +// clamp_feature_filament_to_valid rewrites <=0 to 1, which would drag tool 0 into +// tool_ordering. Filament 1 is logical slot 0, which pem routes to head 0 -- the head every +// mode here declares Primary -- so Print::validate() accepts the plate. +static void all_regions_on_filament(DynamicPrintConfig &config, int filament_1based) +{ + for (const char *key : { "outer_wall_filament_id", "inner_wall_filament_id", + "sparse_infill_filament_id", "internal_solid_filament_id", + "top_surface_filament_id", "bottom_surface_filament_id" }) + config.set_deserialize_strict({ { key, std::to_string(filament_1based) } }); +} + + +// {imex_mode} is the plate's active mode, {imex_mode_index} its position in imex_mode_names and +// {imex_mode_gcode} the raw script at that same position. Two modes are exercised because a +// single one cannot tell a resolved index apart from a constant: `copy` sits at 1 and `iq-copy` +// at 2, so an index that stopped tracking imex_mode_names fails at least one of them. +TEST_CASE("IMEX mode placeholders resolve to the active mode's name, index and script", + "[ImexModeGcode][IMEX]") +{ + auto [mode, mode_index, mode_script] = GENERATE(table<std::string, int, std::string>({ + { "copy", 1, kCopyScript }, + { "iq-copy", 2, kQuadScript }, + })); + INFO("active mode: " << mode); + + DynamicPrintConfig config = multifilament_config(7); + imex_7x4_printer(config); + all_regions_on_filament(config, 1); + set_mode_gcodes(config, { "", kCopyScript, kQuadScript }); + config.set_deserialize_strict({ + { "imex_parallel_mode", mode }, + { "machine_start_gcode", kReportStartGcode }, + }); + + const std::string gcode = slice({ cube(20) }, config); + + CHECK(has_line(gcode, ";IMEX_MODE:" + mode)); + CHECK(has_line(gcode, ";IMEX_MODE_INDEX:" + std::to_string(mode_index))); + CHECK(has_line(gcode, ";IMEX_MODE_GCODE:" + mode_script)); + // The script for the active mode -- and only that one -- reaches the file. + CHECK(has_line(gcode, mode_script)); + CHECK_FALSE(has_line(gcode, mode == "copy" ? kQuadScript : kCopyScript)); +} + +// The mode script is a G-code template, not a literal: it goes through +// placeholder_parser_process like machine_start_gcode does. Because the three IMEX placeholders +// are set before that call, the script can also read its own mode -- which is what +// distinguishes "the script is processed" from "the script is processed too early to see them". +TEST_CASE("A placeholder inside an IMEX mode's G-code script is expanded", + "[ImexModeGcode][IMEX]") +{ + const std::string templ = "SET_DUAL_CARRIAGE MODE={imex_mode} INDEX={imex_mode_index}" + " TEMP={nozzle_temperature_initial_layer[0]}"; + + DynamicPrintConfig config = multifilament_config(7); + imex_7x4_printer(config); + all_regions_on_filament(config, 1); + set_mode_gcodes(config, { "", templ, kQuadScript }); + config.set_deserialize_strict({ + { "imex_parallel_mode", "copy" }, + // The multi-extruder normalization collapses the per-filament temperature vector to a + // single value, so [0] is this literal 200 rather than a per-slot default. + { "nozzle_temperature_initial_layer", "200" }, + { "machine_start_gcode", ";START\n" }, + }); + + const std::string gcode = slice({ cube(20) }, config); + + CHECK(has_line(gcode, "SET_DUAL_CARRIAGE MODE=copy INDEX=1 TEMP=200")); + // If the script were written straight to the file the braces would survive verbatim. + CHECK_FALSE(has_line(gcode, templ)); +} + +// The ordering guarantee, and the reason the placeholder block sits where it does: the mode +// script is processed BEFORE machine_start_gcode, so a {global} the mode declares is in scope +// for machine_start_gcode. Reorder the two and machine_start_gcode references an undefined +// variable, which the placeholder parser raises as an error out of the export -- so a +// regression here fails this test whether the export throws or merely writes nothing useful. +TEST_CASE("A global declared in the IMEX mode G-code is visible to machine_start_gcode", + "[ImexModeGcode][IMEX]") +{ + DynamicPrintConfig config = multifilament_config(7); + imex_7x4_printer(config); + all_regions_on_filament(config, 1); + set_mode_gcodes(config, { "", std::string("{global imex_carriage_count = 2}") + kCopyScript, kQuadScript }); + config.set_deserialize_strict({ + { "imex_parallel_mode", "copy" }, + { "machine_start_gcode", ";IMEX_CARRIAGES:{imex_carriage_count}\n" }, + }); + + const std::string gcode = slice({ cube(20) }, config); + + // The value is the mode script's, not a default: nothing else in this config defines it. + const std::size_t start_gcode_at = find_exact_line(gcode, ";IMEX_CARRIAGES:2"); + REQUIRE(start_gcode_at != std::string::npos); + + // ...and the two land in the file in that same order. Ordering is the contract here, so it + // is asserted directly rather than left implicit in the global resolving. + const std::size_t mode_script_at = find_exact_line(gcode, kCopyScript); + REQUIRE(mode_script_at != std::string::npos); + CHECK(mode_script_at < start_gcode_at); +} + +// Primary is single-carriage printing: it names a real mode (position 0 of imex_mode_names, not +// the not-found fallback) but carries no script, so the export must add nothing. This is what +// keeps the mode machinery out of the way of an IMEX printer that is not printing in parallel. +TEST_CASE("Primary-mode IMEX prints emit no mode G-code", "[ImexModeGcode][IMEX]") +{ + DynamicPrintConfig config = multifilament_config(7); + imex_7x4_printer(config); + all_regions_on_filament(config, 1); + set_mode_gcodes(config, { "", kCopyScript, kQuadScript }); + config.set_deserialize_strict({ + { "imex_parallel_mode", "primary" }, + { "machine_start_gcode", kReportStartGcode }, + }); + + const std::string gcode = slice({ cube(20) }, config); + + CHECK(has_line(gcode, ";IMEX_MODE:primary")); + CHECK(has_line(gcode, ";IMEX_MODE_INDEX:0")); + CHECK(has_line(gcode, ";IMEX_MODE_GCODE:")); + CHECK_FALSE(has_line(gcode, kCopyScript)); + CHECK_FALSE(has_line(gcode, kQuadScript)); +} + +// A plate stores its IMEX mode as the mode's *name* and the exporter resolves that name against +// the printer's imex_mode_names at slice time, so the two drift apart whenever the mode is +// renamed or deleted after a plate was set to it, or the project is opened against a printer +// preset that names its modes differently. A name matching no row must be treated as Primary -- +// not as a parallel mode whose every name-keyed lookup happens to come back empty, which is how +// it used to behave: no mode script (there is none to find), no active-tool roster, and yet the +// parallel branches taken all the way through the export. +// +// Primary is a row like any other, so falling back to it means running its script too; a +// non-empty script is used here so "fell back to Primary" is distinguishable from "resolved +// nothing and emitted nothing". +TEST_CASE("An IMEX mode the printer no longer defines falls back to Primary", + "[ImexModeGcode][IMEX]") +{ + static const char *kPrimaryScript = "SET_DUAL_CARRIAGE MODE=PRIMARY"; + + DynamicPrintConfig config = multifilament_config(7); + imex_7x4_printer(config); + all_regions_on_filament(config, 1); + set_mode_gcodes(config, { kPrimaryScript, kCopyScript, kQuadScript }); + config.set_deserialize_strict({ + // A name no row in imex_mode_names carries -- what `copy` becomes once it is renamed. + { "imex_parallel_mode", "copy-renamed" }, + { "machine_start_gcode", kReportStartGcode }, + }); + + const std::string gcode = slice({ cube(20) }, config); + + // The placeholders report the mode the export actually ran, so the stale name must not + // survive into them -- a mode script keyed on {imex_mode} would otherwise set the printer + // up for a mode the slicer did not slice for. + CHECK(has_line(gcode, ";IMEX_MODE:primary")); + CHECK(has_line(gcode, ";IMEX_MODE_INDEX:0")); + CHECK(has_line(gcode, ";IMEX_MODE_GCODE:" + std::string(kPrimaryScript))); + + // Primary's own script runs; neither parallel mode's does. + CHECK(has_line(gcode, kPrimaryScript)); + CHECK_FALSE(has_line(gcode, kCopyScript)); + CHECK_FALSE(has_line(gcode, kQuadScript)); +} + +// The whole block is gated on is_imex. A printer preset can carry a filled-in mode table and +// still not be an IMEX machine -- and a plate config can still carry a stale imex_parallel_mode +// -- so with the flag off the placeholders stay empty and no mode script is injected. Run on an +// ordinary single-extruder printer on purpose: the guard is one boolean, and the multi-head +// geometry the other cases need would only add ways for this one to fail for another reason. +TEST_CASE("A printer with IMEX disabled resolves the mode placeholders to nothing", + "[ImexModeGcode][IMEX]") +{ + DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); + set_mode_gcodes(config, { "", kCopyScript, kQuadScript }); + config.set_deserialize_strict({ + { "imex_mode_names", "primary;copy;iq-copy" }, + { "imex_mode_active_tools", "0:P;0:P,1:C;0:P,1:C,2:C,3:C" }, + { "is_imex", "0" }, + { "imex_parallel_mode", "copy" }, + { "skirt_loops", "0" }, + { "brim_type", "no_brim" }, + { "gcode_flavor", "klipper" }, + { "machine_start_gcode", kReportStartGcode }, + }); + + const std::string gcode = slice({ cube(20) }, config); + + CHECK(has_line(gcode, ";IMEX_MODE:")); + CHECK(has_line(gcode, ";IMEX_MODE_INDEX:0")); + CHECK(has_line(gcode, ";IMEX_MODE_GCODE:")); + CHECK_FALSE(has_line(gcode, kCopyScript)); + CHECK_FALSE(has_line(gcode, kQuadScript)); +} + +// The placeholders are set unconditionally, ahead of the is_imex check, so they are defined for +// every printer. A single-extruder preset that mentions {imex_mode} must expand it to an empty +// string rather than fail the export on an unknown variable. +TEST_CASE("IMEX mode placeholders are defined on an ordinary single-extruder printer", + "[ImexModeGcode][IMEX]") +{ + const std::string gcode = slice({ cube(20) }, { + { "skirt_loops", "0" }, + { "brim_type", "no_brim" }, + { "gcode_flavor", "klipper" }, + { "machine_start_gcode", kReportStartGcode }, + }); + + CHECK(has_line(gcode, ";IMEX_MODE:")); + CHECK(has_line(gcode, ";IMEX_MODE_INDEX:0")); + CHECK(has_line(gcode, ";IMEX_MODE_GCODE:")); +} diff --git a/tests/fff_print/test_imex_slice_offset.cpp b/tests/fff_print/test_imex_slice_offset.cpp new file mode 100644 index 0000000000..c12c0f20cb --- /dev/null +++ b/tests/fff_print/test_imex_slice_offset.cpp @@ -0,0 +1,489 @@ +#include <catch2/catch_all.hpp> + +#include "libslic3r/GCodeReader.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Print.hpp" + +#include "test_helpers.hpp" +#include "test_utils.hpp" + +#include <algorithm> +#include <cmath> +#include <exception> +#include <limits> +#include <sstream> +#include <string> +#include <string_view> +#include <vector> + +using namespace Slic3r; +using namespace Slic3r::Test; +using Catch::Matchers::WithinAbs; + +// The IMEX slice offset is the firmware-managed handoff: an extra XY shift applied at emission +// so the primary tool's zone lands centred on the bed origin and the firmware can fan copies / +// mirrors out from there. `Print::update_imex_slice_offset()` DERIVES it from the applied +// config -- nobody hands it in. That matters because the only thing that used to hand it in was +// the plater, so a headless `orca-slicer --slice` produced slicer-frame coordinates while the +// mode G-code told the firmware to apply its own offsets on top. +// +// This file covers both halves: +// +// * Derivation -- which config makes the offset non-zero, what value it takes, and (the part +// the GUI push got wrong) that it is in PLATE-LOCAL mm and therefore does not move when the +// plate origin does. `compute_imex_slice_offset()` and `compute_imex_zone_layout()` are +// covered as pure functions in tests/libslic3r/; what is covered here is the Print reaching +// them with the right inputs. +// * Consumption -- that a slice actually comes out shifted. Two sites consume the offset: +// GCode::set_gcode_offset_with_imex_shift() (GCode.hpp), which augments the writer offset +// so every emitted coordinate moves, and Print::translate_to_print_space() (Print.cpp), +// which feeds the first_layer_print_min/max placeholders a start-G-code template uses to +// declare the print area to firmware. The two must stay in one frame, so the last test +// cross-checks them against each other. +// +// The offset is applied at emission, after slicing, so it is a pure translation: assertions are +// on the SHIFT between two slices of the same plate, never on absolute coordinates or on a +// golden file. That keeps them independent of where the arranger puts the cube, and immune to +// the run-to-run variation in this slicer's parallel infill generation. + +// --------------------------------------------------------------------------------------------- +// Helpers (unnamed namespace: every suite links into one binary, so nothing here may collide +// with a same-named helper in a sibling test file) +// --------------------------------------------------------------------------------------------- +namespace { + +// The bed the derivation divides up, and the answer it must reach. +// +// With `imex_gantry_count` 1, `imex_tools_per_gantry` 2 and `imex_tool_layout` front-left, T0 +// owns the left column and T1 the right one, so a mode declaring `0:P,1:C` gives the primary +// the left half of the bed: x [0, 150], y [0, 200]. Its centre is the offset. Both numbers are +// set by the config below, not inherited from a default. +constexpr double kBedWidth = 300.0; +constexpr double kBedDepth = 200.0; +const Vec2d kPrimaryZoneCentre(kBedWidth / 4.0, kBedDepth / 2.0); + +// XY extent of a set of emitted moves. `empty()` means nothing matched. +struct XYBounds +{ + double min_x = std::numeric_limits<double>::max(); + double min_y = std::numeric_limits<double>::max(); + double max_x = std::numeric_limits<double>::lowest(); + double max_y = std::numeric_limits<double>::lowest(); + + bool empty() const { return min_x > max_x; } + double size_x() const { return max_x - min_x; } + double size_y() const { return max_y - min_y; } +}; + +// Extent of the END points of every extruding move commented "perimeter", up to `z_max`. +// +// Perimeters only: they are the outermost extrusions, so they carry the plate's extent, and +// unlike infill their geometry and ordering are stable run to run. End points only: the parse +// callback runs BEFORE the reader advances, so the start point of the first extrusion of a +// polyline is whatever the preceding travel left behind -- and a cube's perimeters are closed +// loops, whose last point is their first, so the end points alone already give the true extent. +static XYBounds perimeter_bounds(const std::string &gcode, double z_max = std::numeric_limits<double>::max()) +{ + XYBounds bounds; + GCodeReader reader; + reader.parse_buffer(gcode, [&bounds, z_max](GCodeReader &self, const GCodeReader::GCodeLine &line) { + if (!line.extruding(self)) + return; + if (line.comment().find("perimeter") == std::string_view::npos) + return; + if (double(line.new_Z(self)) > z_max) + return; + const double x = line.new_X(self); + const double y = line.new_Y(self); + bounds.min_x = std::min(bounds.min_x, x); + bounds.max_x = std::max(bounds.max_x, x); + bounds.min_y = std::min(bounds.min_y, y); + bounds.max_y = std::max(bounds.max_y, y); + }); + return bounds; +} + +// Read "<tag>x,y" out of `gcode`. The config block the exporter appends restates +// machine_start_gcode verbatim, so the tag also occurs there with the placeholder still +// unexpanded; occurrences are tried in turn and the first one that parses as two numbers wins. +static bool read_marker(const std::string &gcode, const std::string &tag, Vec2d &out) +{ + for (size_t at = gcode.find(tag); at != std::string::npos; at = gcode.find(tag, at + 1)) { + const size_t from = at + tag.size(); + const size_t to = gcode.find('\n', from); + const std::string payload = gcode.substr(from, to == std::string::npos ? std::string::npos : to - from); + const size_t comma = payload.find(','); + if (comma == std::string::npos) + continue; + try { + out = Vec2d(std::stod(payload.substr(0, comma)), std::stod(payload.substr(comma + 1))); + } catch (const std::exception &) { + continue; + } + return true; + } + return false; +} + +// An IMEX machine: 7 logical extruders across 4 physical heads, mirroring the geometry the IMEX +// cases in test_multifilament.cpp use, on a 2-tool single-gantry grid. +// +// physical_extruder_map is only honoured when its length matches the nozzle count (PrintApply +// hands effective_physical_extruder_map the nozzle_diameter size), so the nozzle keys have to be +// sized to 7 as well -- otherwise the map is silently replaced with the identity and the plate +// stops being an IMEX plate at all. +// +// The grid, the tool layout and the bed are all set explicitly: they are exactly the inputs the +// zone layout divides to reach kPrimaryZoneCentre, so none of them may come from a default. +// `imex_firmware_managed_zones` is deliberately NOT set here -- it is the switch under test, and +// every case states it for itself. +// +// Everything that would put extrusions outside the object footprint is off (skirt, brim, prime +// tower, infill, top/bottom shells): that leaves perimeters as the only extrusions, so the +// emitted extent and the first-layer convex hull both reduce to the cube's own outline. +static void imex_printer(DynamicPrintConfig &config) +{ + config.set_deserialize_strict({ + { "nozzle_diameter", "0.4,0.4,0.4,0.4,0.4,0.4,0.4" }, + { "printer_extruder_id", "1,2,3,4,5,6,7" }, + { "printer_extruder_variant", "Direct Drive Standard,Direct Drive Standard,Direct Drive Standard," + "Direct Drive Standard,Direct Drive Standard,Direct Drive Standard," + "Direct Drive Standard" }, + { "extruder_printable_height", "0,0,0,0,0,0,0" }, + { "physical_extruder_map", "0,0,0,0,1,2,3" }, + { "printable_area", "0x0,300x0,300x200,0x200" }, + { "is_imex", "1" }, + { "imex_gantry_count", "1" }, + { "imex_tools_per_gantry", "2" }, + { "imex_tool_layout", "front-left" }, + { "imex_mode_names", "primary;copy" }, + { "imex_mode_active_tools", "0:P;0:P,1:C" }, + // `copy` declares head 0 Primary, and filament 1 (logical slot 0) routes there, so the + // plate is well-formed and Print::validate() lets it through. + { "imex_parallel_mode", "copy" }, + { "skirt_loops", "0" }, + { "brim_type", "no_brim" }, + { "enable_prime_tower", "0" }, + { "sparse_infill_density", "0%" }, + { "top_shell_layers", "0" }, + { "bottom_shell_layers", "0" }, + { "wall_loops", "2" }, + { "layer_height", "0.2" }, + { "initial_layer_print_height","0.2" }, + { "gcode_flavor", "klipper" }, + }); +} + +// Route every region to one filament. An unset *_filament_id is not "inherit": +// clamp_feature_filament_to_valid rewrites <=0 to 1, so leaving them unset would drag extra +// tools into tool_ordering. PrintObject.cpp's call to that function is the source of truth for +// this key list. +static void all_regions_on_filament(DynamicPrintConfig &config, int filament_1based) +{ + for (const char *key : { "outer_wall_filament_id", "inner_wall_filament_id", + "sparse_infill_filament_id", "internal_solid_filament_id", + "top_surface_filament_id", "bottom_surface_filament_id" }) + config.set_deserialize_strict({ { key, std::to_string(filament_1based) } }); +} + +// A ready-to-slice firmware-managed IMEX plate. `firmware_managed` is the one thing that +// varies between a baseline slice and a shifted one. +static DynamicPrintConfig imex_config(bool firmware_managed) +{ + DynamicPrintConfig config = multifilament_config(7); + imex_printer(config); + all_regions_on_filament(config, 1); // filament 1 => logical slot 0 => physical head 0 + config.set_deserialize_strict({ { "imex_firmware_managed_zones", firmware_managed ? "1" : "0" } }); + return config; +} + +// The offset the Print works out for itself, with nothing pushed in. Applying the config is +// enough -- the derivation reads only the config and the objects, so this needs no slice. +static Vec2d derived_offset(const DynamicPrintConfig &config, const Vec3d &plate_origin = Vec3d::Zero()) +{ + Print print; + Model model; + init_print({ cube(20) }, print, model, config); + print.set_plate_origin(plate_origin); + print.update_imex_slice_offset(); + return print.get_imex_slice_offset(); +} + +// Slice one 20mm cube. Note what is NOT here: no offset is handed to the Print. Whatever shift +// the G-code comes out with, the Print derived on its own from `config`. +static std::string slice_cube(const DynamicPrintConfig &config, const Vec3d &plate_origin = Vec3d::Zero()) +{ + Print print; + Model model; + init_print({ cube(20) }, print, model, config); + print.set_plate_origin(plate_origin); + return gcode(print); +} + +} // namespace + +// --------------------------------------------------------------------------------------------- +// Derivation +// --------------------------------------------------------------------------------------------- + +// The bug this file exists for: the offset used to arrive only from PartPlate, which a headless +// slice never runs, so `--slice` on a firmware-managed plate emitted slicer-managed coordinates +// while the mode G-code told the firmware to fan copies out from them. Nothing pushes anything +// here; the Print is expected to reach the primary zone's centre from the config alone. +TEST_CASE("A firmware-managed IMEX plate derives its slice offset with nothing pushed in", + "[IMEXSliceOffset][IMEX]") +{ + const Vec2d offset = derived_offset(imex_config(true)); + + CHECK_THAT(offset.x(), WithinAbs(kPrimaryZoneCentre.x(), 1e-9)); + CHECK_THAT(offset.y(), WithinAbs(kPrimaryZoneCentre.y(), 1e-9)); +} + +// The offset is a PLATE-LOCAL quantity. Both consumers already subtract the plate origin +// separately, so an offset that moved with the plate would subtract it twice and put every +// plate after the first a full plate stride out. This is precisely what the old plater-side +// computation got wrong: it divided the plate's world-frame outline, not the bed. +TEST_CASE("The derived IMEX slice offset is plate-local and does not move with the plate origin", + "[IMEXSliceOffset][IMEX]") +{ + const DynamicPrintConfig config = imex_config(true); + + const Vec2d at_origin = derived_offset(config); + const Vec2d on_plate3 = derived_offset(config, Vec3d(kBedWidth * 2.0, -kBedDepth * 2.0, 0.0)); + + CHECK_THAT(on_plate3.x(), WithinAbs(at_origin.x(), 1e-9)); + CHECK_THAT(on_plate3.y(), WithinAbs(at_origin.y(), 1e-9)); +} + +// The offset tracks the bed it divides, so it is not a constant that happens to match one +// printer. Halving the bed halves the primary zone and its centre with it. +TEST_CASE("The derived IMEX slice offset follows the printable area", "[IMEXSliceOffset][IMEX]") +{ + DynamicPrintConfig config = imex_config(true); + config.set_deserialize_strict({ { "printable_area", "0x0,150x0,150x100,0x100" } }); + + const Vec2d offset = derived_offset(config); + + CHECK_THAT(offset.x(), WithinAbs(kPrimaryZoneCentre.x() / 2.0, 1e-9)); + CHECK_THAT(offset.y(), WithinAbs(kPrimaryZoneCentre.y() / 2.0, 1e-9)); +} + +// Every case that must leave the offset at exactly Vec2d::Zero(). This is what protects +// existing users: an exactly-zero offset is what makes the firmware-managed path reduce to the +// old set_gcode_offset() behaviour, to the last digit. +TEST_CASE("The derived IMEX slice offset is zero unless firmware-managed zones are in play", + "[IMEXSliceOffset][IMEX]") +{ + // A Print nobody has applied anything to starts at zero. This is the value every + // non-IMEX printer keeps, and the reason nothing else in the exporter had to change. + Print fresh; + REQUIRE_THAT(fresh.get_imex_slice_offset().x(), WithinAbs(0.0, 1e-12)); + REQUIRE_THAT(fresh.get_imex_slice_offset().y(), WithinAbs(0.0, 1e-12)); + + Vec2d offset = Vec2d::Zero(); + + SECTION("an ordinary printer with no IMEX configuration at all") { + DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "sparse_infill_density", "0%" }, + { "layer_height", "0.2" }, + { "initial_layer_print_height", "0.2" }, + }); + offset = derived_offset(config); + } + SECTION("an IMEX printer in a parallel mode, but firmware-managed zones off") { + offset = derived_offset(imex_config(false)); + } + SECTION("firmware-managed zones on, but the plate is in Primary mode") { + DynamicPrintConfig config = imex_config(true); + config.set_deserialize_strict({ { "imex_parallel_mode", "primary" } }); + offset = derived_offset(config); + } + SECTION("firmware-managed zones on, but the plate has no mode at all") { + DynamicPrintConfig config = imex_config(true); + config.set_deserialize_strict({ { "imex_parallel_mode", "" } }); + offset = derived_offset(config); + } + // A plate can name a mode this printer does not define -- a mode renamed or deleted after + // the plate was set to it, or a project opened against a different printer preset. The + // exporter falls back to Primary and warns; the offset has to make the same choice, or the + // file would be shifted for a mode nothing ever activates. + SECTION("firmware-managed zones on, but the plate's mode is not one this printer defines") { + DynamicPrintConfig config = imex_config(true); + config.set_deserialize_strict({ { "imex_parallel_mode", "renamed-since" } }); + offset = derived_offset(config); + } + // The layout hangs off the primary tool's cell. `imex_tools_per_gantry` 1 on a single + // gantry is a one-cell grid: there is nothing to divide, so there is nothing to shift by. + SECTION("firmware-managed zones on, but the tool grid holds a single tool") { + DynamicPrintConfig config = imex_config(true); + config.set_deserialize_strict({ { "imex_tools_per_gantry", "1" }, + { "imex_mode_active_tools", "0:P;0:P" } }); + offset = derived_offset(config); + } + + CHECK_THAT(offset.x(), WithinAbs(0.0, 1e-12)); + CHECK_THAT(offset.y(), WithinAbs(0.0, 1e-12)); +} + +// --------------------------------------------------------------------------------------------- +// Consumption +// --------------------------------------------------------------------------------------------- + +// The whole point of the firmware-managed path: the emitted toolpaths move, and they move by the +// derived offset. The writer subtracts plate origin + IMEX shift from every point it formats, so +// the firmware-managed slice comes out at (baseline - offset). Asserting the shift rather than +// absolute coordinates keeps this independent of wherever the arranger drops the cube. +TEST_CASE("A firmware-managed IMEX plate emits coordinates shifted by the offset it derived", + "[IMEXSliceOffset][IMEX]") +{ + const XYBounds baseline = perimeter_bounds(slice_cube(imex_config(false))); + const XYBounds shifted = perimeter_bounds(slice_cube(imex_config(true))); + REQUIRE_FALSE(baseline.empty()); + REQUIRE_FALSE(shifted.empty()); + + CHECK_THAT(shifted.min_x, WithinAbs(baseline.min_x - kPrimaryZoneCentre.x(), 1e-3)); + CHECK_THAT(shifted.max_x, WithinAbs(baseline.max_x - kPrimaryZoneCentre.x(), 1e-3)); + CHECK_THAT(shifted.min_y, WithinAbs(baseline.min_y - kPrimaryZoneCentre.y(), 1e-3)); + CHECK_THAT(shifted.max_y, WithinAbs(baseline.max_y - kPrimaryZoneCentre.y(), 1e-3)); + + // A translation, not a re-slice: the plate keeps its size. + CHECK_THAT(shifted.size_x(), WithinAbs(baseline.size_x(), 1e-3)); + CHECK_THAT(shifted.size_y(), WithinAbs(baseline.size_y(), 1e-3)); +} + +// The IMEX shift is added to the plate origin, not substituted for it. A multi-plate project +// already carries a non-zero plate origin, so dropping either term from +// set_gcode_offset_with_imex_shift() would put every emitted coordinate on the wrong plate -- +// invisibly to a test that only ever slices plate 1 at the origin. The expected total is +// origin + offset precisely because the derived offset does NOT itself contain the origin. +TEST_CASE("An IMEX slice offset composes with the plate origin rather than replacing it", + "[IMEXSliceOffset][IMEX]") +{ + const Vec3d plate_origin(kBedWidth * 1.1, -kBedDepth * 1.1, 0.0); + + const XYBounds baseline = perimeter_bounds(slice_cube(imex_config(false))); + const XYBounds shifted = perimeter_bounds(slice_cube(imex_config(true), plate_origin)); + REQUIRE_FALSE(baseline.empty()); + REQUIRE_FALSE(shifted.empty()); + + const double expected_x = plate_origin.x() + kPrimaryZoneCentre.x(); + const double expected_y = plate_origin.y() + kPrimaryZoneCentre.y(); + CHECK_THAT(shifted.min_x, WithinAbs(baseline.min_x - expected_x, 1e-3)); + CHECK_THAT(shifted.max_x, WithinAbs(baseline.max_x - expected_x, 1e-3)); + CHECK_THAT(shifted.min_y, WithinAbs(baseline.min_y - expected_y, 1e-3)); + CHECK_THAT(shifted.max_y, WithinAbs(baseline.max_y - expected_y, 1e-3)); +} + +// The guard for everyone who is not using this feature. `imex_firmware_managed_zones` is read +// by nothing else in the engine, so setting it on a printer the derivation refuses to shift must +// leave the slice where it was -- it must short-circuit on `is_imex` before it ever looks at a +// bed or a mode. The zero-offset sections above cover an ordinary printer that never mentions +// the option; this covers the option turned ON where nothing may act on it. +// +// Asserted as the derived offset plus the extent of the emitted perimeters, NOT as a line-by-line +// comparison of the two exports. This slicer's output is not stable run to run -- parallel infill +// generation is the documented source -- and the M73 time estimates, the seam placement and the +// travel ordering all ride on that variation, so comparing every emitted command would flake in +// CI rather than catch a shift. The offset is applied at emission as a pure translation, so a +// non-zero one moves the extent and this catches it; that it is exactly zero is what the +// derivation check states. +TEST_CASE("Turning on firmware-managed zones changes nothing on a non-IMEX printer", + "[IMEXSliceOffset][IMEX]") +{ + auto ordinary_printer = [](bool firmware_managed) { + DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "sparse_infill_density", "0%" }, + { "top_shell_layers", "0" }, + { "bottom_shell_layers", "0" }, + { "wall_loops", "2" }, + { "layer_height", "0.2" }, + { "initial_layer_print_height", "0.2" }, + { "skirt_loops", "0" }, + { "brim_type", "no_brim" }, + { "enable_prime_tower", "0" }, + { "imex_firmware_managed_zones", firmware_managed ? "1" : "0" }, + }); + return config; + }; + + // Nothing to apply in the first place. + const Vec2d offset = derived_offset(ordinary_printer(true)); + CHECK_THAT(offset.x(), WithinAbs(0.0, 1e-12)); + CHECK_THAT(offset.y(), WithinAbs(0.0, 1e-12)); + + // ...and the toolpaths bear that out: same plate, same place. Infill, skirt, brim and the + // prime tower are all off in this config, so the perimeters carry the whole extent. + const XYBounds baseline = perimeter_bounds(slice_cube(ordinary_printer(false))); + const XYBounds with_flag = perimeter_bounds(slice_cube(ordinary_printer(true))); + REQUIRE_FALSE(baseline.empty()); + REQUIRE_FALSE(with_flag.empty()); + + CHECK_THAT(with_flag.min_x, WithinAbs(baseline.min_x, 1e-3)); + CHECK_THAT(with_flag.max_x, WithinAbs(baseline.max_x, 1e-3)); + CHECK_THAT(with_flag.min_y, WithinAbs(baseline.min_y, 1e-3)); + CHECK_THAT(with_flag.max_y, WithinAbs(baseline.max_y, 1e-3)); +} + +// first_layer_print_min/max are what a start-G-code template hands the firmware to declare the +// print area (bed mesh bounds, PRINT_MIN/PRINT_MAX). They come from the first-layer convex hull +// pushed through Print::translate_to_print_space(), which subtracts the same IMEX shift the +// writer does, so they have to travel with the toolpaths. If they did not, a firmware-managed +// plate would probe one area and print in another. +TEST_CASE("first_layer_print_min/max track the derived IMEX slice offset", + "[IMEXSliceOffset][IMEX]") +{ + auto with_markers = [](bool firmware_managed) { + DynamicPrintConfig config = imex_config(firmware_managed); + config.set_deserialize_strict({ + { "machine_start_gcode", + ";FLMIN:{first_layer_print_min[0]},{first_layer_print_min[1]}\n" + ";FLMAX:{first_layer_print_max[0]},{first_layer_print_max[1]}\n" }, + }); + return config; + }; + + const std::string baseline_gcode = slice_cube(with_markers(false)); + const std::string shifted_gcode = slice_cube(with_markers(true)); + + Vec2d baseline_min, baseline_max, shifted_min, shifted_max; + REQUIRE(read_marker(baseline_gcode, ";FLMIN:", baseline_min)); + REQUIRE(read_marker(baseline_gcode, ";FLMAX:", baseline_max)); + REQUIRE(read_marker(shifted_gcode, ";FLMIN:", shifted_min)); + REQUIRE(read_marker(shifted_gcode, ";FLMAX:", shifted_max)); + + CHECK_THAT(shifted_min.x(), WithinAbs(baseline_min.x() - kPrimaryZoneCentre.x(), 1e-3)); + CHECK_THAT(shifted_min.y(), WithinAbs(baseline_min.y() - kPrimaryZoneCentre.y(), 1e-3)); + CHECK_THAT(shifted_max.x(), WithinAbs(baseline_max.x() - kPrimaryZoneCentre.x(), 1e-3)); + CHECK_THAT(shifted_max.y(), WithinAbs(baseline_max.y() - kPrimaryZoneCentre.y(), 1e-3)); + + // Declared area and toolpaths must be in ONE frame. The declared bounds come from the + // first-layer convex hull, which Print::first_layer_islands() builds from the object's SLICE + // CONTOUR (lslices) -- not from any extrusion path -- so it sits outside the emitted + // centrelines by whatever wall geometry lies between the two. That distance is a property of + // the wall generator, not of this feature, so it is not asserted as a constant here. + // + // What IS asserted: the declared bounds enclose the toolpaths, and the gap between the two is + // the SAME in both frames. A frame divergence -- one of the two consumers shifted, the other + // not -- moves the declared box relative to the toolpaths and breaks this by the offset. + const XYBounds baseline_layer = perimeter_bounds(baseline_gcode, 0.3); // initial_layer_print_height 0.2 + const XYBounds shifted_layer = perimeter_bounds(shifted_gcode, 0.3); + REQUIRE_FALSE(baseline_layer.empty()); + REQUIRE_FALSE(shifted_layer.empty()); + + CHECK(shifted_min.x() <= shifted_layer.min_x + 1e-3); + CHECK(shifted_min.y() <= shifted_layer.min_y + 1e-3); + CHECK(shifted_max.x() >= shifted_layer.max_x - 1e-3); + CHECK(shifted_max.y() >= shifted_layer.max_y - 1e-3); + + CHECK_THAT(shifted_layer.min_x - shifted_min.x(), + WithinAbs(baseline_layer.min_x - baseline_min.x(), 1e-3)); + CHECK_THAT(shifted_layer.min_y - shifted_min.y(), + WithinAbs(baseline_layer.min_y - baseline_min.y(), 1e-3)); + CHECK_THAT(shifted_max.x() - shifted_layer.max_x, + WithinAbs(baseline_max.x() - baseline_layer.max_x, 1e-3)); + CHECK_THAT(shifted_max.y() - shifted_layer.max_y, + WithinAbs(baseline_max.y() - baseline_layer.max_y, 1e-3)); +} diff --git a/tests/fff_print/test_multifilament.cpp b/tests/fff_print/test_multifilament.cpp index 24f5185d8f..05d5993c07 100644 --- a/tests/fff_print/test_multifilament.cpp +++ b/tests/fff_print/test_multifilament.cpp @@ -13,6 +13,7 @@ #include <cstdlib> #include <fstream> #include <limits> +#include <map> #include <optional> #include <set> #include <sstream> @@ -856,6 +857,63 @@ TEST_CASE("Primary-mode IMEX prints still transition to the second-layer tempera CHECK(gcode.find("M104 S240") != std::string::npos); } +// A plate carries its IMEX mode as a name, matched against the printer's imex_mode_names at +// slice time, so a mode renamed or deleted underneath the plate -- or a project opened against a +// preset that names its modes differently -- leaves the plate pointing at nothing. That used to +// take every "not Primary" branch in the exporter while every name-keyed lookup came back empty, +// which is worse than either interpretation on its own: +// * the 1st->2nd layer temperature branch is mutually exclusive with the standard one, so an +// empty active-tool roster meant NO head was transitioned and every one of them held +// nozzle_temperature_initial_layer for the whole print; and +// * the initial T<n> was suppressed on the assumption that the mode's setup script would +// select the tool, while that script -- resolved by the same name -- did not exist. +// Print::validate() does not catch it either: the unresolved name yields an empty tools string, +// so there is no declared primary and its IMEX routing guard is skipped. +// +// Falling back to Primary is what makes the file coherent again. Asserted on the two emissions +// that were actually broken rather than on the mode string, which the placeholder test in +// test_imex_mode_gcode.cpp covers. +TEST_CASE("An IMEX plate set to a mode the printer no longer defines slices as Primary", + "[MultiFilament][IMEX]") +{ + DynamicPrintConfig config = multifilament_config(7); + imex_7x4_printer(config); + all_regions_on_filament(config, 1); // filament 1 => logical slot 0 => physical head 0 + config.set_deserialize_strict({ + // imex_mode_names is "primary;copy" -- this is `copy` after a rename. + { "imex_parallel_mode", "copy-renamed" }, + { "nozzle_temperature_initial_layer", "200" }, + { "nozzle_temperature", "240" }, + }); + + const std::string gcode = slice({ cube(20) }, config); + + // The head the toolpaths run on steps 200 -> 240 at the second layer, via the standard + // per-extruder path a Primary-mode print uses. + CHECK(gcode.find("M104 S240") != std::string::npos); + // ...and only that head, addressed the way a single-head print addresses it: nothing drives + // a copy carriage here, so the fallback goes through the standard per-extruder path, where + // only filament slot 0 prints. GCodeWriter::set_temperature therefore sees + // multiple_extruders == false and emits no tool qualifier at all. Excluding the whole + // " T" suffix rather than " T1" is what makes that the assertion: a regression that routed + // the transition to T2 or T3 instead would satisfy an exclusion of T1, and the unqualified + // find above is itself prefix-satisfied by any "M104 S240 T<n>". + CHECK(gcode.find("M104 S240 T") == std::string::npos); + + // The initial tool selection is emitted. Matched as a line-leading token rather than a whole + // line so the assertion does not depend on the trailing "; change extruder" comment, which + // is switched off by a global unrelated to IMEX. + bool selects_initial_tool = false; + std::istringstream tool_lines(gcode); + std::string line; + while (std::getline(tool_lines, line)) + if (line.rfind("T0", 0) == 0) { + selects_initial_tool = true; + break; + } + CHECK(selects_initial_tool); +} + // IQEX: when the second gantry is active the mode drives all four carriages, so every one of // them needs its own filament resolved -- for the first layer via is_extruder_used (consumed by // machine_start_gcode) and for the second via the per-tool transition. pem routes filament 1 to @@ -947,6 +1005,108 @@ TEST_CASE("IMEX heater commands name the physical head, not the logical filament CHECK(offenders.empty()); } +// The other half of that translation, and the half nothing else covers: GCodeWriter::set_temperature +// passes `this->config.is_imex.value` as the guard, NOT a constant, so a printer that is not an +// IMEX printer keeps addressing heaters by logical filament id exactly as upstream does. +// +// physical_extruder_map is not an IMEX-only key. Shipping dual-nozzle BBL profiles author it -- +// fdm_bbl_3dp_002_common ships {1, 0} -- for the inherited BBL reading of the key, and PrintApply +// deliberately leaves a non-IMEX printer's map exactly as it arrives (IMEXHelpers.hpp spells out +// the two readings). Hardcode `true` at that call site and this whole suite still passes, because +// every other case here runs either on an IMEX printer or on one with no authored map -- while +// those profiles start sending filament 0's M104/M109 to heater 1 and filament 1's to heater 0. +// +// The two filaments carry DIFFERENT idle temperatures, so the S value and the T index cross-check +// each other: a remap moves both onto the other tool and fails both halves, and no assertion can +// be satisfied by a prefix. +// +// Idle temperature rather than nozzle_temperature, for a reason specific to THIS HARNESS. Keys in +// filament_options_with_variant are rewritten at apply time by +// update_values_to_printer_extruders_for_multiple_filaments, which sets each filament's value to +// `opt->get_at(variant_index[f])` -- it RE-INDEXES per filament by that filament's extruder +// variant, it does not flatten. Per-filament nozzle temperature is a real, working feature and +// survives that pass on a printer whose filaments resolve to different variant slots. +// multifilament_config pins nozzle_diameter to a single 0.4, so every filament here resolves to +// the SAME variant slot and therefore ends up with the same value -- which is why the IMEX cases +// above tell heads apart by tool qualifier rather than by temperature. idle_temperature is not in +// that key set, so "151,173" reaches the emitter intact and the two filaments stay distinguishable. +// Ooze prevention is what puts the idle temperatures into the file at all. +TEST_CASE("Heater commands keep the logical filament id on a non-IMEX printer", + "[MultiFilament][IMEX][Regression]") +{ + DynamicPrintConfig config = multifilament_config(2, { + { "nozzle_diameter", "0.4,0.4" }, + { "printer_extruder_id", "1,2" }, + { "printer_extruder_variant", "Direct Drive Standard,Direct Drive Standard" }, + { "extruder_printable_height", "0,0" }, + // The shipping two-nozzle profile: not an IMEX printer, but it authors the swap map. + { "is_imex", "0" }, + { "physical_extruder_map", "1,0" }, + { "single_extruder_multi_material", "0" }, + // Ooze prevention drops the outgoing filament to its idle temperature on every tool + // change, through the instance set_temperature overload that carries the guard. + { "ooze_prevention", "1" }, + { "standby_temperature_delta", "-50" }, // unused while idle_temperature is set + // Per filament and distinct: these are the values the assertions pair with a heater. + { "idle_temperature", "151,173" }, + { "nozzle_temperature_initial_layer", "215,215" }, + { "nozzle_temperature", "240,240" }, + // GCodeProcessor's preheat pass rewrites the tool-change temperature commands and drops + // the ";cooldown" M104s outright, applying physical_extruder_map itself as it does. That + // pass is not the code under test, so switch it off and let the writer's emissions stand. + { "preheat_time", "0" }, + { "enable_prime_tower", "0" }, + // The assertions spell "M104 S<t> T<n>"; RepRapFirmware emits "G10 S<t> P<n>" from the + // same code, so the flavor is pinned rather than defaulted. + { "gcode_flavor", "klipper" }, + }); + + // One filament per object, so both heaters are addressed and a tool change happens in both + // directions. Assigned at the object level: a region-level filament id would not raise the + // used-filament count the tool ordering works from. + const std::vector<std::vector<ConfigBase::SetDeserializeItem>> overrides{ + { { "extruder", "1" } }, + { { "extruder", "2" } }, + }; + const std::string gcode = slice_with_object_overrides({ cube(20), cube(20) }, config, overrides); + + // Every heater command that names a tool, collected as temperature -> the tools it was + // addressed to. Scanning beats fixed-string finds: "M104 S151" on its own is prefix-satisfied + // by "M104 S151 T1", and excluding just " T1" would let a command routed to some third tool + // through. Mirrors the offender scan in the IMEX case above. + std::map<int, std::set<int>> tools_by_temp; + std::istringstream ss(gcode); + for (std::string line; std::getline(ss, line);) { + if (line.rfind("M104", 0) != 0 && line.rfind("M109", 0) != 0) + continue; + const size_t s = line.find('S'); + const size_t t = line.find(" T"); + if (s == std::string::npos || t == std::string::npos) + continue; + if (s + 1 >= line.size() || !std::isdigit((unsigned char) line[s + 1])) + continue; + if (t + 2 >= line.size() || !std::isdigit((unsigned char) line[t + 2])) + continue; + tools_by_temp[std::stoi(line.substr(s + 1))].insert(std::stoi(line.substr(t + 2))); + } + + std::string seen; + for (const auto& [temperature, tools] : tools_by_temp) { + seen += " S" + std::to_string(temperature) + "->"; + for (int tool : tools) + seen += "T" + std::to_string(tool); + } + INFO("heater commands naming a tool:" << seen); + + // Both idle temperatures have to be in the file, or the pairing below would prove nothing. + REQUIRE(tools_by_temp.count(151) == 1); + REQUIRE(tools_by_temp.count(173) == 1); + // Filament 0's idle temperature goes to heater 0 and nowhere else, filament 1's to heater 1. + // Applying physical_extruder_map {1, 0} here would swap both. + CHECK(tools_by_temp[151] == std::set<int>{ 0 }); + CHECK(tools_by_temp[173] == std::set<int>{ 1 }); +} + // The IMEX Primary tool prints the sliced paths directly, so it can only use a filament the // printer's physical_extruder_map routes to it. The ghost filament picker enforces that for // the secondary tools; the primary's filament comes from the ordinary object selector, which From f92bd811904b6223241fd967c54cfa1554e6f017 Mon Sep 17 00:00:00 2001 From: Kris Austin <kris.austin@gmail.com> Date: Thu, 3 Sep 2026 07:56:33 -0500 Subject: [PATCH 45/51] fix: build_win.bat builds with whatever clang-cl is first on PATH (#15504) * fix: build_win.bat builds with whatever clang-cl is first on PATH VsDevCmd appends the Visual Studio LLVM directory to the end of PATH, so a standalone LLVM already on it shadows the Visual Studio one. -l -x passed a bare clang-cl.exe for CMake to resolve, so the build ran on whichever copy came first. For one reporter that was an LLVM 11, which failed the compiler check before anything was compiled: -- Check for working C compiler: C:/Program Files/LLVM/bin/clang-cl.exe - broken lld-link: error: undefined symbol: __guard_eh_cont_table The compiler is now resolved through vswhere and passed as a full path, so PATH order no longer matters. CMake derives the linker from the compiler directory, so lld-link follows. Only a configure passes it to CMake, so -p and --no-configure resolve nothing and stay buildable on a machine with no clang installed. When Visual Studio has no clang toolset the script falls back to the first clang-cl on PATH and names it. With none installed at all it now errors with what to add, instead of failing later inside CMake. Every clang-cl run that configures prints the compiler it resolved. The suite gains a clang-cl fixture earlier on PATH than the Visual Studio one, and an empty ProgramFiles(x86) to put vswhere out of reach, which covers both fallbacks without touching the machine. * fix: build_win.bat pointed at a solution file that is not there The Visual Studio 2026 generator writes OrcaSlicer.slnx and the releases before it OrcaSlicer.sln. The summary hard-coded the second, so the path it printed after an MSVC build against 2026 was wrong. --- build_win.bat | 79 +++++++++++++++++++++++++++++++++---- scripts/test_build_win.ps1 | 80 +++++++++++++++++++++++++++++++++----- 2 files changed, 142 insertions(+), 17 deletions(-) diff --git a/build_win.bat b/build_win.bat index 926468687b..15399d5e3d 100644 --- a/build_win.bat +++ b/build_win.bat @@ -370,13 +370,13 @@ if "%use_ninja%" == "ON" ( set "using_ninja=ON" ) +call :resolve_clang_cl +%repeat_error% + if "%using_ninja%" == "ON" ( if "%use_clang_cl%" == "ON" ( - REM Bare, so it resolves from the PATH the dev shell just set up, which - REM is the clang shipped with Visual Studio. --clang-path names another. - set "clang_exe=clang-cl.exe" - if not "%clang_path%" == "" set "clang_exe="%clang_path%"" - set "gen_args=-DCMAKE_C_COMPILER=!clang_exe! -DCMAKE_CXX_COMPILER=!clang_exe!" + REM Quoted, because the resolved path has spaces in it. + set "gen_args=-DCMAKE_C_COMPILER="!clang_exe!" -DCMAKE_CXX_COMPILER="!clang_exe!"" ) ) else ( set "gen_args=-A !arch!" @@ -473,6 +473,7 @@ REM forward slashes, and anything that prints the directory has to show a REM real path rather than one glued onto the repository root. for %%p in ("!build_dir!") do set "build_full=%%~fp" echo Configuration: %build_type%, %arch% +if not "%clang_exe%" == "" echo Compiler: %clang_exe% set "SIG_FLAG=" if defined ORCA_UPDATER_SIG_KEY set "SIG_FLAG=-DORCA_UPDATER_SIG_KEY=%ORCA_UPDATER_SIG_KEY%" @@ -734,6 +735,14 @@ REM worked out the same way in either run. set "slicer_exe=%build_dir%\src\%build_type%\orca-slicer.exe" if "%install_slicer%" == "ON" set "slicer_exe=%build_dir%\OrcaSlicer\orca-slicer.exe" for %%p in ("!slicer_exe!") do set "slicer_full=%%~fp" + REM The 2026 generator writes OrcaSlicer.slnx, the releases before it + REM OrcaSlicer.sln. A file already there wins, in case an older CMake + REM configured the build. + set "solution=OrcaSlicer.sln" + if "%vs_version%" == "2026" set "solution=OrcaSlicer.slnx" + if exist "!build_full!\OrcaSlicer.sln" set "solution=OrcaSlicer.sln" + if exist "!build_full!\OrcaSlicer.slnx" set "solution=OrcaSlicer.slnx" + REM Naming a target builds it and its dependencies, not its dependents, REM so only a full build or the executable's own target relinks. set "linked=ON" @@ -751,14 +760,14 @@ REM worked out the same way in either run. if "%build_deps%" == "ON" echo Dependencies !dep_full! if "%build_slicer%" == "ON" if "%linked%" == "ON" echo OrcaSlicer !slicer_full! if "%build_slicer%" == "ON" if not "%linked%" == "ON" echo Target %slicer_target% - if "%build_slicer%" == "ON" if not "%using_ninja%" == "ON" echo Solution %build_full%\OrcaSlicer.sln + if "%build_slicer%" == "ON" if not "%using_ninja%" == "ON" echo Solution %build_full%\!solution! if "%pack_deps%" == "ON" if defined bundle echo Bundle !bundle! echo. echo Next if "%build_slicer%" == "ON" ( if "%linked%" == "ON" echo Run it !slicer_exe! - if not "%using_ninja%" == "ON" echo Open in Visual Studio %build_dir%\OrcaSlicer.sln + if not "%using_ninja%" == "ON" echo Open in Visual Studio %build_dir%\!solution! if "%linked%" == "ON" echo Rebuild after edits build_win.bat -s!recall! --no-configure if not "%linked%" == "ON" echo Relink the binary build_win.bat -s!recall! --no-configure if "%linked%" == "ON" if "%using_ninja%" == "ON" echo Rebuild one target build_win.bat -s!recall! --no-configure --slicer-target libslic3r @@ -1080,6 +1089,62 @@ REM echo_var <variable> exit /b 0 +REM resolve_clang_cl - set clang_exe to the clang-cl a Ninja build uses. +REM VsDevCmd appends the Visual Studio LLVM directory to the end of PATH, +REM so a standalone LLVM already there shadows it. Name a full path. +:resolve_clang_cl + set "clang_exe=" + if not "%using_ninja%" == "ON" exit /b 0 + if not "%use_clang_cl%" == "ON" exit /b 0 + REM Only a configure uses it, so -p and --no-configure need none. + if "%no_configure%" == "ON" exit /b 0 + if "%build_deps%%build_slicer%" == "" exit /b 0 + + REM --clang-path wins. Forward slashes either way, so CMake does not + REM read a backslash as an escape. + if not "%clang_path%" == "" ( + set "clang_exe=%clang_path:\=/%" + exit /b 0 + ) + + setlocal + + REM Keyed on the host, not %arch%, because the x64 compiler + REM cross-compiles to ARM64. + set "llvm_host=x64" + if /I "%PROCESSOR_ARCHITECTURE%" == "ARM64" set "llvm_host=ARM64" + + set "found=" + %VSWHERE% -nologo >nul 2>nul + if !errorlevel! == 0 ( + for /f "tokens=*" %%i in ('%VSWHERE% -nologo -products * -latest -property resolvedInstallationPath') do ( + if exist "%%i\VC\Tools\Llvm\!llvm_host!\bin\clang-cl.exe" ( + set "found=%%i\VC\Tools\Llvm\!llvm_host!\bin\clang-cl.exe" + ) + ) + ) + + REM No clang toolset in Visual Studio. where lists every match, and the + REM first is the one PATH would resolve. + if "!found!" == "" ( + for /f "tokens=*" %%i in ('where clang-cl.exe 2^>nul') do ( + if "!found!" == "" set "found=%%i" + ) + if not "!found!" == "" echo Visual Studio has no clang-cl; using !found! from PATH. + ) + + if "!found!" == "" ( + echo No clang-cl found. Add the C++ Clang Compiler component with + echo %script_name% --install-vs ide -l + echo or name a standalone one with --clang-path. + endlocal + exit /b 1 + ) + + endlocal & set "clang_exe=%found:\=/%" + + exit /b 0 + REM clean_tree <path> - remove a build tree, refusing anything that is not REM one. Nothing here should ever fire; it is a floor under a bug that REM produced a path far shorter than it looks. diff --git a/scripts/test_build_win.ps1 b/scripts/test_build_win.ps1 index 62eaaae77b..563430559f 100644 --- a/scripts/test_build_win.ps1 +++ b/scripts/test_build_win.ps1 @@ -85,6 +85,24 @@ foreach ($v in @{ old = '1.11.1'; new = '1.12.0' }.GetEnumerator()) { $ninjaPaths[$v.Key] = "$d;$env:PATH" } +# A clang-cl earlier on PATH than the Visual Studio one, which is what the +# compiler used to resolve to. Nothing runs it; the script only locates it. +$clangDir = Join-Path $fixtures 'clang' +New-Item -ItemType Directory -Force -Path $clangDir | Out-Null +Copy-Item "$env:SystemRoot\System32\where.exe" (Join-Path $clangDir 'clang-cl.exe') -Force +$clangOnPath = "$clangDir;$env:PATH" + +# ProgramFiles(x86) is where the script looks for vswhere, so an empty one +# stands in for a machine whose Visual Studio has no clang toolset. +$noVs = Join-Path $fixtures 'no-vs' +New-Item -ItemType Directory -Force -Path $noVs | Out-Null + +# A build directory that already holds a classic solution, for the case where +# what is on disk disagrees with what the generator would write. +$slnDir = Join-Path $fixtures 'sln' +New-Item -ItemType Directory -Force -Path $slnDir | Out-Null +Set-Content -Path (Join-Path $slnDir 'OrcaSlicer.sln') -Value '' -Encoding ascii + # The pack stamp is checked against real dates, so a locale-dependent parse # in the script cannot pass by looking date-shaped. Yesterday is accepted too, # so a run that crosses midnight does not flake. @@ -131,7 +149,36 @@ $cases = @( Contains = @('-G "Ninja Multi-Config"') NotContains = @('clang-cl', '-A x64') } @{ Name = '-l -x builds with clang-cl under Ninja'; Args = @('-d', '-l', '-x') - Contains = @('-G "Ninja Multi-Config"', '-DCMAKE_C_COMPILER=clang-cl.exe', '-DCMAKE_CXX_COMPILER=clang-cl.exe') } + Contains = @('-G "Ninja Multi-Config"') + Match = @('-DCMAKE_C_COMPILER="[^"]+/clang-cl\.exe"', '-DCMAKE_CXX_COMPILER="[^"]+/clang-cl\.exe"') } + # PATH order used to decide the compiler. VsDevCmd appends the Visual + # Studio LLVM directory to the end of PATH, so a standalone LLVM already + # there was resolved instead, and an old one failed the compiler check. + @{ Name = 'the compiler is resolved from Visual Studio, not PATH'; Args = @('-s', '-l', '-x') + Env = @{ PATH = $clangOnPath } + Match = @('^Compiler: .*/VC/Tools/Llvm/[^/]+/bin/clang-cl\.exe$') } + @{ Name = 'msvc names no compiler, having resolved none'; Args = @('-s') + NotContains = @('Compiler: ') } + @{ Name = '-l without -x names none either, the toolset picks it'; Args = @('-s', '-l') + NotContains = @('Compiler: ') } + # An empty ProgramFiles(x86) puts vswhere out of reach, which is a machine + # whose Visual Studio has no clang toolset. + @{ Name = 'without a Visual Studio clang the one on PATH is used and named'; Args = @('-s', '-l', '-x') + Env = @{ 'ProgramFiles(x86)' = $noVs; PATH = $clangOnPath } + Contains = @('Visual Studio has no clang-cl') + Match = @('^Compiler: .*/clang/clang-cl\.exe$') } + @{ Name = 'no clang-cl anywhere stops before configuring'; Args = @('-s', '-l', '-x'); ExpectExit = 1 + Env = @{ 'ProgramFiles(x86)' = $noVs; PATH = 'C:\Windows\system32;C:\Windows' } + Contains = @('No clang-cl found', '--install-vs ide -l') + NotContains = @('cmake -B') } + # Only a configure passes the compiler to CMake, so an action that does + # not configure resolves none, and cannot start needing one installed. + @{ Name = 'packing resolves no compiler'; Args = @('-p', '-l', '-x') + Contains = @('Packing the dependencies') + NotContains = @('Compiler: ') } + @{ Name = '--no-configure resolves none either'; Args = @('-s', '-l', '-x', '--no-configure') + Contains = @('cmake --build "build-clang"') + NotContains = @('Compiler: ') } @{ Name = '-l alone uses the ClangCL toolset on the VS generator'; Args = @('-d', '-l') Contains = @('-G "Visual Studio', '-T ClangCL') NotContains = @('-DCMAKE_C_COMPILER') } @@ -148,11 +195,13 @@ $cases = @( NotContains = @('clang-cl') } @{ Name = '--msbuild with -l gives the VS generator and the ClangCL toolset'; Args = @('-d', '--msbuild', '-l') Contains = @('-G "Visual Studio', '-T ClangCL') } - # A developer with a standalone LLVM points at it; the VS-bundled clang - # is what a bare clang-cl.exe resolves to after the dev shell runs. + # A developer with a standalone LLVM points at it, and the path is passed + # with forward slashes so CMake cannot read a backslash as an escape. @{ Name = '--clang-path names the compiler, quoted for its spaces'; Args = @('-d', '-x', '--clang-path', 'C:\Program Files\LLVM\bin\clang-cl.exe') - Contains = @('-DCMAKE_C_COMPILER="C:\Program Files\LLVM\bin\clang-cl.exe"', - '-DCMAKE_CXX_COMPILER="C:\Program Files\LLVM\bin\clang-cl.exe"') } + Contains = @('-DCMAKE_C_COMPILER="C:/Program Files/LLVM/bin/clang-cl.exe"', + '-DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang-cl.exe"') } + @{ Name = '--clang-path beats the Visual Studio clang'; Args = @('-s', '-x', '--clang-path', 'C:\Program Files\LLVM\bin\clang-cl.exe') + Contains = @('Compiler: C:/Program Files/LLVM/bin/clang-cl.exe') } @{ Name = '--clang-path is a clang request on its own'; Args = @('-d', '-x', '--clang-path', 'C:\Program Files\LLVM\bin\clang-cl.exe') Contains = @('deps/build-clang') } @{ Name = '--clang-path needs Ninja to take effect'; Args = @('-d', '--clang-path', 'C:\Program Files\LLVM\bin\clang-cl.exe'); ExpectExit = 1 @@ -195,7 +244,8 @@ $cases = @( @{ Name = 'the architecture is matched case-insensitively'; Args = @('-d', '--arch', 'ARM64') Contains = @('-A ARM64', 'deps/build-arm64') } @{ Name = 'arm64 under Ninja has no -A but keeps the arm64 tree'; Args = @('-d', '--arch', 'arm64', '-x', '-l') - Contains = @('deps/build-clang-arm64', '-DCMAKE_C_COMPILER=clang-cl.exe') + Contains = @('deps/build-clang-arm64') + Match = @('-DCMAKE_C_COMPILER="[^"]+/clang-cl\.exe"') NotContains = @('-A ') } 'build configurations' @@ -699,18 +749,28 @@ $cases = @( Contains = @('Next', 'Rebuild after edits') } 'pointing at the solution' + # The extension follows the generator, so these two pin the release and a + # build directory that cannot already hold a solution of either kind. + @{ Name = 'the 2026 generator gets the XML solution'; Args = @('-s', '--vs', '2026', '--build-dir', 'D:\tree') + Contains = @('Solution D:\tree\OrcaSlicer.slnx', 'Open in Visual Studio D:\tree\OrcaSlicer.slnx') } + @{ Name = 'the releases before it get the classic one'; Args = @('-s', '--vs', '2022', '--build-dir', 'D:\tree') + Contains = @('Solution D:\tree\OrcaSlicer.sln', 'Open in Visual Studio D:\tree\OrcaSlicer.sln') } + @{ Name = 'a solution already on disk wins over the generator'; Args = @('-s', '--vs', '2026', '--build-dir', $slnDir) + Match = @('^ Solution .*\\OrcaSlicer\.sln$') } + # Extension-agnostic from here: these cases are about the directory, and + # the release is whatever is installed. @{ Name = 'the VS generator says where the solution is'; Args = @('-s') - Match = @('^ Solution .*\\build\\OrcaSlicer\.sln$') } + Match = @('^ Solution .*\\build\\OrcaSlicer\.slnx?$') } @{ Name = 'the solution path follows the configuration'; Args = @('-s', '--config', 'debug') - Match = @('^ Solution .*\\build-dbg\\OrcaSlicer\.sln$') } + Match = @('^ Solution .*\\build-dbg\\OrcaSlicer\.slnx?$') } @{ Name = 'the solution line survives an install'; Args = @('-s', '-i') Contains = @(' Solution ') } # The path is resolved, not pasted onto the repository root, so it is # right whether --build-dir came absolute or with forward slashes. @{ Name = 'a moved build still prints one real path'; Args = @('-s', '--build-dir', 'out/build/x64-clang') - Match = @('^ Solution [A-Za-z]:\\[^/]+\\OrcaSlicer\.sln$') } + Match = @('^ Solution [A-Za-z]:\\[^/]+\\OrcaSlicer\.slnx?$') } @{ Name = 'an absolute --build-dir is not glued onto the repo root'; Args = @('-s', '--build-dir', 'D:\tree') - Contains = @('Solution D:\tree\OrcaSlicer.sln') } + Match = @('^ Solution D:\\tree\\OrcaSlicer\.slnx?$') } ) function Invoke-BuildScript { From 5eac300d91a284b37e0bef7cec7e8c14995de5c4 Mon Sep 17 00:00:00 2001 From: Clifford Garwood <cliff@cigii.com> Date: Thu, 3 Sep 2026 10:05:37 -0400 Subject: [PATCH 46/51] Use IDEX/IQEX in the user-facing strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes review comment 10. `461c69c83e` settled this in April — IMEX internally, IDEX/IQEX as the user-facing label — but the UI strings were never converted. Every translated string naming the feature now reads IDEX/IQEX: 41 occurrences across the printer and process option labels and tooltips, the modes editor, the plate mode indicator, the pre-slice warnings, the placement refusals and the slicing errors. The reviewer listed eight; the rest were in the same class. Nothing else moves. The config keys keep the `imex_` spelling — `is_imex`, `imex_mode_names`, `imex_parallel_mode` and the rest are on-disk format in existing printer presets and 3MF projects, so renaming them would break every profile and project already saved. C++ identifiers, filenames, comments and test names keep IMEX as well: it stays the internal name of the subsystem, which is what covers the topology space (one gantry with 2-4 tools, 2x1 and 2x2 grids) that neither acronym names on its own. Where a tooltip quotes a key, the key spelling is preserved and only the feature word around it changed. The `is_imex` tooltip is reworded rather than substituted: it already named the hardware families parenthetically, so a literal replacement would have said IDEX/IQEX twice in one sentence. No translation impact — no IMEX string had reached OrcaSlicer.pot or any catalogue, so there is nothing to migrate. One test asserted on the old error text and now matches the new one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- src/libslic3r/GCode.cpp | 8 +++--- src/libslic3r/Print.cpp | 4 +-- src/libslic3r/PrintConfig.cpp | 34 +++++++++++++------------- src/slic3r/GUI/IMEXModesCtrl.cpp | 4 +-- src/slic3r/GUI/MainFrame.cpp | 4 +-- src/slic3r/GUI/PartPlate.cpp | 4 +-- src/slic3r/GUI/Plater.cpp | 12 ++++----- src/slic3r/GUI/Tab.cpp | 6 ++--- tests/fff_print/test_multifilament.cpp | 2 +- 9 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 58d681890c..e28402c155 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -3731,13 +3731,13 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato print.active_step_add_warning( PrintStateBase::WarningLevel::NON_CRITICAL, imex_mode_resolved - ? Slic3r::format(_(L("The IMEX mode \"%1%\" has no tools assigned on the selected printer. " + ? Slic3r::format(_(L("The IDEX/IQEX mode \"%1%\" has no tools assigned on the selected printer. " "Printing in Primary mode instead. Assign the mode's tools in Printer " - "Settings, or pick another mode from the plate's IMEX button.")), + "Settings, or pick another mode from the plate's IDEX/IQEX button.")), imex_active_mode) - : Slic3r::format(_(L("This plate is set to the IMEX mode \"%1%\", which the selected printer " + : Slic3r::format(_(L("This plate is set to the IDEX/IQEX mode \"%1%\", which the selected printer " "does not define. Printing in Primary mode instead. Pick a mode from the " - "plate's IMEX button, or restore the mode in Printer Settings.")), + "plate's IDEX/IQEX button, or restore the mode in Printer Settings.")), imex_active_mode)); imex_active_mode = kImexPrimaryMode; imex_active_mode_index = 0; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 6a0c8eefec..c32cde9eb9 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1377,7 +1377,7 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin StringObjectException err; // "Mixed filament" is the term the rest of the UI uses -- the button that // creates one, and the sibling refusal for the wipe tower filament. - err.string = L("Mixed filaments are not supported in IMEX parallel modes. " + err.string = L("Mixed filaments are not supported in IDEX/IQEX parallel modes. " "Switch this plate to Primary mode."); err.object = m_objects.front(); return err; @@ -1442,7 +1442,7 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin StringObjectException err; err.string = Slic3r::format( - L("IMEX mode \"%1%\" prints with T%2%, but this plate's filaments are on %3%. " + L("IDEX/IQEX mode \"%1%\" prints with T%2%, but this plate's filaments are on %3%. " "Assign a filament loaded on T%2%, or switch this plate to Primary mode."), parallel_mode, routing.primary_phys, routed_list); // Gives the notification a "Jump to <object>" link, which selects the object diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index fc946211a5..fd7bad0945 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -6611,8 +6611,8 @@ void PrintConfigDef::init_fff_params() // g-code. They all carry non-nil defaults, so emitting them would add a line to every // printer's dump. Kept out of the g-code config block (banned_keys). def = this->add("is_imex", coBool); - def->label = L("IMEX Printer"); - def->tooltip = L("Enable IMEX parallel printing for printers with multiple independent carriages (IDEX, IQEX, and similar)."); + def->label = L("IDEX/IQEX Printer"); + def->tooltip = L("Enable parallel printing for printers with multiple independent carriages (IDEX, IQEX, and similar)."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(false)); @@ -6693,7 +6693,7 @@ void PrintConfigDef::init_fff_params() def = this->add("imex_viz_theme", coEnum); def->label = L("Visualization Theme"); - def->tooltip = L("Color theme for IMEX bed zone visualization. Choose a colorblind-friendly theme if needed."); + def->tooltip = L("Color theme for IDEX/IQEX bed zone visualization. Choose a colorblind-friendly theme if needed."); def->mode = comAdvanced; def->enum_keys_map = &ConfigOptionEnum<ImexVizTheme>::get_enum_values(); def->enum_values.push_back("standard"); @@ -6707,32 +6707,32 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionEnum<ImexVizTheme>(ImexVizTheme::Standard)); def = this->add("imex_parallel_mode", coString); - def->label = L("IMEX Print Mode"); - def->tooltip = L("Name of the active IMEX parallel print mode, or \"primary\" for single-carriage printing. Requires IMEX Printer enabled in the Printer preset (Printer \u2192 Multimaterial \u2192 IMEX Configuration)."); + def->label = L("IDEX/IQEX Print Mode"); + def->tooltip = L("Name of the active IDEX/IQEX parallel print mode, or \"primary\" for single-carriage printing. Requires IDEX/IQEX Printer enabled in the Printer preset (Printer \u2192 Multimaterial \u2192 IDEX/IQEX Configuration)."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionString("primary")); def = this->add("imex_head_filament_map", coString); - def->label = L("IMEX head filament map"); + def->label = L("IDEX/IQEX head filament map"); def->tooltip = L("Per-plate override mapping physical heads to filament slots " "(1-based). Empty means use pem-inversion defaults."); def->mode = comDevelop; def->set_default_value(new ConfigOptionString("")); def = this->add("imex_mode_names", coStrings); - def->label = L("IMEX Mode Names"); - def->tooltip = L("Display names for each user-defined IMEX parallel print mode."); + def->label = L("IDEX/IQEX Mode Names"); + def->tooltip = L("Display names for each user-defined IDEX/IQEX parallel print mode."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionStrings()); def = this->add("imex_mode_active_tools", coStrings); - def->label = L("IMEX Mode Active Tools"); - def->tooltip = L("Tool role assignments for each mode. Format: \"idx:P,idx:C,idx:M\" where P=Primary, C=Copy, M=Mirror (e.g. \"0:P,1:C,2:M,3:M\"). Managed by the IMEX Modes editor in the Printer preset."); + def->label = L("IDEX/IQEX Mode Active Tools"); + def->tooltip = L("Tool role assignments for each mode. Format: \"idx:P,idx:C,idx:M\" where P=Primary, C=Copy, M=Mirror (e.g. \"0:P,1:C,2:M,3:M\"). Managed by the IDEX/IQEX Modes editor in the Printer preset."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionStrings()); def = this->add("imex_mode_gcodes", coStrings); - def->label = L("IMEX Mode G-codes"); + def->label = L("IDEX/IQEX Mode G-codes"); def->tooltip = L("G-code or macro call to inject at print start for each mode."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionStrings()); @@ -12629,16 +12629,16 @@ OtherSlicingStatesConfigDef::OtherSlicingStatesConfigDef() new_def("in_head_wrap_detect_zone", coBool, "In head wrap detect zone", "Indicates if the first layer overlaps with the head wrap zone."); def = this->add("imex_mode", coString); - def->label = L("IMEX active mode"); - def->tooltip = L("Name of the active IMEX parallel print mode for this plate (e.g. 'primary', 'mirror', 'copy'). Empty string if IMEX is not enabled."); + def->label = L("IDEX/IQEX active mode"); + def->tooltip = L("Name of the active IDEX/IQEX parallel print mode for this plate (e.g. 'primary', 'mirror', 'copy'). Empty string if IDEX/IQEX is not enabled."); def = this->add("imex_mode_index", coInt); - def->label = L("IMEX active mode index"); - def->tooltip = L("Zero-based index of the active IMEX parallel print mode within imex_mode_names."); + def->label = L("IDEX/IQEX active mode index"); + def->tooltip = L("Zero-based index of the active IDEX/IQEX parallel print mode within imex_mode_names."); def = this->add("imex_mode_gcode", coString); - def->label = L("IMEX active mode G-code"); - def->tooltip = L("The raw mode G-code template for the active IMEX parallel print mode, after placeholder evaluation. Globals defined here flow into machine_start_gcode."); + def->label = L("IDEX/IQEX active mode G-code"); + def->tooltip = L("The raw mode G-code template for the active IDEX/IQEX parallel print mode, after placeholder evaluation. Globals defined here flow into machine_start_gcode."); } PrintStatisticsConfigDef::PrintStatisticsConfigDef() diff --git a/src/slic3r/GUI/IMEXModesCtrl.cpp b/src/slic3r/GUI/IMEXModesCtrl.cpp index f1a3570e97..a07d95191c 100644 --- a/src/slic3r/GUI/IMEXModesCtrl.cpp +++ b/src/slic3r/GUI/IMEXModesCtrl.cpp @@ -104,7 +104,7 @@ void IMEXModesCtrl::rebuild_info_and_header() { auto* hdr_name = new wxStaticText(m_hdr_panel, wxID_ANY, _L("Name")); auto* hdr_tools = new wxStaticText(m_hdr_panel, wxID_ANY, _L("Tools")); auto* hdr_gcode = new wxStaticText(m_hdr_panel, wxID_ANY, _L("G-code")); - hdr_name->SetToolTip(_L("How the mode is labelled in the plate's IMEX mode selector. " + hdr_name->SetToolTip(_L("How the mode is labelled in the plate's IDEX/IQEX mode selector. " "Required — a mode with no name cannot be selected.")); hdr_tools->SetToolTip(_L("Which tool heads take part in the mode and what role each one plays. " "Click a tile to cycle its role.")); @@ -368,7 +368,7 @@ void IMEXModesCtrl::add_row(const std::string& name, r.orig_name = nm; r.name = new wxTextCtrl(r.panel, wxID_ANY, from_u8(nm), wxDefaultPosition, FromDIP(wxSize(130, -1))); r.name->SetHint(_L("Mode name (required)")); - r.name->SetToolTip(_L("Name of this parallel mode, as it appears in the plate's IMEX mode " + r.name->SetToolTip(_L("Name of this parallel mode, as it appears in the plate's IDEX/IQEX mode " "selector. Stored in the project by name, so renaming a mode that " "plates already use makes them fall back to Primary. Cannot be empty " "— a blank name is replaced with a generated one.")); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 7f0001be4e..a2b6c9d7a5 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -3190,8 +3190,8 @@ void MainFrame::init_menubar_as_editor() // change adds true toolhead model support (cf. printer bed models) this same toggle // governs that. Only relevant on Preview, and only meaningful when the active // printer is IDEX/IQEX — gated to keep the menu uncluttered for everyone else. - append_menu_check_item(viewMenu, wxID_ANY, _L("Show IMEX Toolhead"), - _L("Show the IMEX toolhead representation around each active nozzle in the G-code preview."), + append_menu_check_item(viewMenu, wxID_ANY, _L("Show IDEX/IQEX Toolhead"), + _L("Show the IDEX/IQEX toolhead representation around each active nozzle in the G-code preview."), [this](wxCommandEvent&) { const bool current = wxGetApp().app_config->get("show_imex_toolhead_boxes") != "false"; wxGetApp().app_config->set("show_imex_toolhead_boxes", current ? "false" : "true"); diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index a828936ed0..b32c438b9b 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -2127,7 +2127,7 @@ void PartPlate::render_icons(bool bottom, bool only_name, int hover_id) render_icon_texture(m_imex_mode_icon.model, m_partplate_list->m_imex_mode_hovered_texture); std::string cur = get_imex_mode(); if (cur == kImexPrimaryMode) cur = _u8L("Primary"); - show_tooltip(_u8L("IMEX mode: ") + cur + _u8L(" (left-click to cycle, right-click for menu)")); + show_tooltip(_u8L("IDEX/IQEX mode: ") + cur + _u8L(" (left-click to cycle, right-click for menu)")); } else { render_icon_texture(m_imex_mode_icon.model, m_partplate_list->m_imex_mode_texture); } @@ -2135,7 +2135,7 @@ void PartPlate::render_icons(bool bottom, bool only_name, int hover_id) if (has_imex_multimaterial_conflict()) { render_icon_texture(m_imex_warn_icon, m_partplate_list->m_imex_warn_texture); if (hover_id == (int)PLATE_IMEX_MODE_ID) - show_tooltip(_u8L("Warning: this plate uses a parallel IMEX mode with multi-material objects. Proceed with caution — verify your G-code handles this combination correctly.")); + show_tooltip(_u8L("Warning: this plate uses a parallel IDEX/IQEX mode with multi-material objects. Proceed with caution — verify your G-code handles this combination correctly.")); } } } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 0d1360b37c..aa0a5f14a6 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -10457,10 +10457,10 @@ std::string imex_placement_error(PartPlate* plate) return {}; switch (plate->imex_placement_violation()) { case PartPlate::ImexPlacementViolation::Object: - return _u8L("Cannot slice: an object overlaps an area reserved for IMEX parallel printing " + return _u8L("Cannot slice: an object overlaps an area reserved for IDEX/IQEX parallel printing " "(a secondary zone, or a carriage clearance strip inside the primary zone)."); case PartPlate::ImexPlacementViolation::PrimeTower: - return _u8L("Cannot slice: the prime tower overlaps an area reserved for IMEX parallel printing " + return _u8L("Cannot slice: the prime tower overlaps an area reserved for IDEX/IQEX parallel printing " "(a secondary zone, or a carriage clearance strip inside the primary zone)."); case PartPlate::ImexPlacementViolation::None: break; @@ -12843,11 +12843,11 @@ void Plater::priv::on_action_slice_plate(SimpleEvent&) std::vector<wxString> warnings = collect_imex_warnings(plate); if (!warnings.empty()) { int plate_num = partplate_list.get_curr_plate_index() + 1; - wxString msg = wxString::Format(_L("Plate %d has IMEX parallel mode active with the following concerns:\n\n"), plate_num); + wxString msg = wxString::Format(_L("Plate %d has IDEX/IQEX parallel mode active with the following concerns:\n\n"), plate_num); for (const wxString& w : warnings) msg += L"\u2022 " + w + "\n\n"; msg += _L("Continue slicing?"); - RichMessageDialog dlg(q, msg, _L("IMEX Parallel Mode Warning"), wxICON_WARNING | wxYES | wxNO); + RichMessageDialog dlg(q, msg, _L("IDEX/IQEX Parallel Mode Warning"), wxICON_WARNING | wxYES | wxNO); dlg.ShowCheckBox(_L("Don't show these warnings again")); int result = dlg.ShowModal(); if (dlg.IsCheckBoxChecked()) @@ -12892,10 +12892,10 @@ void Plater::priv::on_action_slice_all(SimpleEvent&) combined_msg += "\n"; } if (!combined_msg.empty()) { - wxString msg = _L("The following IMEX parallel mode concerns were detected:\n\n") + wxString msg = _L("The following IDEX/IQEX parallel mode concerns were detected:\n\n") + combined_msg + _L("Continue slicing?"); - RichMessageDialog dlg(q, msg, _L("IMEX Parallel Mode Warning"), wxICON_WARNING | wxYES | wxNO); + RichMessageDialog dlg(q, msg, _L("IDEX/IQEX Parallel Mode Warning"), wxICON_WARNING | wxYES | wxNO); dlg.ShowCheckBox(_L("Don't show these warnings again")); int result = dlg.ShowModal(); if (dlg.IsCheckBoxChecked()) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 62e133a53f..f952223a71 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -5636,7 +5636,7 @@ if (is_marlin_flavor) optgroup->append_single_option_line("machine_tool_change_time", "printer_multimaterial_advanced#tool-change-time"); // IDEX/IQEX (IMEX) parallel printing configuration - optgroup = page->new_optgroup(L("IMEX Configuration"), L"param_advanced"); + optgroup = page->new_optgroup(L("IDEX/IQEX Configuration"), L"param_advanced"); optgroup->append_single_option_line("is_imex"); optgroup->append_single_option_line("imex_firmware_managed_zones"); optgroup->append_single_option_line("imex_gantry_count"); @@ -5657,7 +5657,7 @@ if (is_marlin_flavor) // activate_line to return early before build_field. ConfigOptionDef placeholder_def; placeholder_def.label = L("Pre-slice warnings"); - placeholder_def.tooltip = L("Show a warning dialog before slicing if IMEX parallel mode " + placeholder_def.tooltip = L("Show a warning dialog before slicing if IDEX/IQEX parallel mode " "concerns are detected (bed temperature conflicts, filament type " "mismatches, multi-material conflicts). Can be suppressed from the " "dialog itself. Re-enable here if suppressed accidentally."); @@ -5678,7 +5678,7 @@ if (is_marlin_flavor) } optgroup->append_single_option_line("imex_viz_theme"); { - auto modes_og = page->new_optgroup(L("IMEX Parallel Modes"), L"param_advanced"); + auto modes_og = page->new_optgroup(L("IDEX/IQEX Parallel Modes"), L"param_advanced"); auto line = Line{ L("Modes"), L("") }; line.full_width = 1; line.widget = [this](wxWindow* parent) -> wxSizer* { diff --git a/tests/fff_print/test_multifilament.cpp b/tests/fff_print/test_multifilament.cpp index 05d5993c07..a871af5aa9 100644 --- a/tests/fff_print/test_multifilament.cpp +++ b/tests/fff_print/test_multifilament.cpp @@ -1246,7 +1246,7 @@ TEST_CASE("A mixed filament outranks the multi-color rule on the same plate", Slic3r::Print print; const StringObjectException err = validate_plate(build(true), print, model); REQUIRE_FALSE(err.string.empty()); - CHECK(err.string.find("not supported in IMEX parallel modes") != std::string::npos); + CHECK(err.string.find("not supported in IDEX/IQEX parallel modes") != std::string::npos); CHECK(err.string.find("Multi-color") == std::string::npos); // The two rules differ in more than wording: the mixed path attaches an object (for the // notification's "Jump to" link), the multi-color path returns none. Pins which fired From 6a13cc2ab6a3a9ceb610aa5cfb481c881d6b3a7a Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Fri, 4 Sep 2026 00:25:21 +0300 Subject: [PATCH 47/51] Fix Detach from parent checkbox not updating visually (#15520) Refresh detach-from-parent checkbox state Allow the detach checkbox toggle event to propagate to the custom CheckBox control so it refreshes its bitmap after the value changes. --- src/slic3r/GUI/SavePresetDialog.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/SavePresetDialog.cpp b/src/slic3r/GUI/SavePresetDialog.cpp index b3f34a8cb9..65b75c3d92 100644 --- a/src/slic3r/GUI/SavePresetDialog.cpp +++ b/src/slic3r/GUI/SavePresetDialog.cpp @@ -149,7 +149,10 @@ SavePresetDialog::Item::Item(Preset::Type type, const std::string &suffix, wxBox // Set initial state (unchecked by default) detach_checkbox->SetValue(m_detach); // Bind the checkbox event to update the detach state for this item - detach_checkbox->Bind(wxEVT_TOGGLEBUTTON, [this, detach_checkbox](wxCommandEvent&) { m_detach = detach_checkbox->GetValue(); }); + detach_checkbox->Bind(wxEVT_TOGGLEBUTTON, [this, detach_checkbox](wxCommandEvent& event) { + m_detach = detach_checkbox->GetValue(); + event.Skip(); // Let CheckBox update its bitmap for the new state. + }); detach_label->SetForegroundColour(wxColour("#363636")); From c57ea0ec67591fa986961dcc59b19185fe190ba6 Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Fri, 4 Sep 2026 00:28:26 +0300 Subject: [PATCH 48/51] Fix nozzle type undo and unsaved changes tracking (#15515) --- src/slic3r/GUI/Tab.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 644c5258a1..e650c45126 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -5130,7 +5130,7 @@ void TabPrinter::build_fff() optgroup->append_single_option_line("adaptive_bed_mesh_margin", "printer_basic_information_adaptive_bed_mesh#mesh-margin"); optgroup = page->new_optgroup(L("Accessory"), "param_accessory"); - optgroup->append_single_option_line("nozzle_type", "printer_basic_information_accessory#nozzle-type"); + optgroup->append_single_option_line("nozzle_type", "printer_basic_information_accessory#nozzle-type", 0); optgroup->append_single_option_line("nozzle_hrc", "printer_basic_information_accessory#nozzle-hrc"); optgroup->append_single_option_line("auxiliary_fan", "printer_basic_information_accessory#auxiliary-part-cooling-fan"); optgroup->append_single_option_line("fan_direction"); From b370d8ef316f77bfe61ba651c3f5b07510fff56b Mon Sep 17 00:00:00 2001 From: Kris Austin <kris.austin@gmail.com> Date: Thu, 3 Sep 2026 16:35:10 -0500 Subject: [PATCH 49/51] build: clear 31 warnings - copy and move declarations (#15507) --- src/libslic3r/Measure.hpp | 9 --------- src/libslic3r/Orient.cpp | 1 - src/libslic3r/Point.hpp | 2 -- src/libslic3r/Preset.hpp | 14 +++++++------- src/libslic3r/SLA/Hollowing.hpp | 3 --- src/libslic3r/Support/SupportCommon.cpp | 4 ---- src/libslic3r/Support/TreeSupport.hpp | 5 +++-- src/libslic3r/calib.hpp | 20 +++----------------- src/slic3r/GUI/PartPlate.hpp | 10 ---------- 9 files changed, 13 insertions(+), 55 deletions(-) diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 2f378f5778..0374c5d4aa 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -33,15 +33,6 @@ public: SurfaceFeature(const Vec3d& pt) : m_type{SurfaceFeatureType::Point}, m_pt1{pt} {} - SurfaceFeature(const SurfaceFeature& sf){ - this->clone(sf); - volume = sf.volume; - plane_indices = sf.plane_indices; - world_tran = sf.world_tran; - world_plane_features = sf.world_plane_features; - origin_surface_feature = sf.origin_surface_feature; - } - void clone(const SurfaceFeature &sf) { m_type = sf.get_type(); diff --git a/src/libslic3r/Orient.cpp b/src/libslic3r/Orient.cpp index ae1954087d..7d54048176 100644 --- a/src/libslic3r/Orient.cpp +++ b/src/libslic3r/Orient.cpp @@ -39,7 +39,6 @@ namespace orientation { float height_to_bottom_hull_ratio = 0; // affects stability, the lower the better float unprintability = 0; Eigen::VectorXf areas_cooling; - CostItems(CostItems const & other) = default; CostItems() = default; static std::string field_names() { return " overhang, bottom, bothull, contour, A_laf, A_prj, unprintability"; diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 039f361eaa..21e5355fc5 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -195,7 +195,6 @@ public: Point(int64_t x, int32_t y) : Vec2crd(coord_t(x), coord_t(y)) {} Point(int32_t x, int64_t y) : Vec2crd(coord_t(x), coord_t(y)) {} Point(double x, double y) : Vec2crd(coord_t(std::round(x)), coord_t(std::round(y))) {} - Point(const Point &rhs) { *this = rhs; } explicit Point(const Vec2d& rhs) : Vec2crd(coord_t(std::round(rhs.x())), coord_t(std::round(rhs.y()))) {} // This constructor allows you to construct Point from Eigen expressions // This constructor has to be implicit (non-explicit) to allow implicit conversion from Eigen expressions. @@ -278,7 +277,6 @@ public: Point3(int32_t x, int32_t y, int32_t z = 0) : Vec3crd(coord_t(x), coord_t(y), coord_t(z)) {} Point3(int64_t x, int64_t y, int64_t z = 0) : Vec3crd(coord_t(x), coord_t(y), coord_t(z)) {} Point3(double x, double y, double z = 0.0) : Vec3crd(coord_t(std::round(x)), coord_t(std::round(y)), coord_t(std::round(z))) {} - Point3(const Point3 &rhs) { *this = rhs; } explicit Point3(const Vec2crd& vec2crd, coord_t z = 0) : Vec3crd(vec2crd.x(), vec2crd.y(), z) {} explicit Point3(const Vec3crd &vec3crd) : Vec3crd(vec3crd) {} // This constructor allows you to construct Point from Eigen expressions diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index c9b3197a6f..22089be0b6 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -840,13 +840,12 @@ public: protected: PresetCollection() = default; - // Copy constructor and copy operators are not to be used from outside PresetBundle, - // as the Profile::vendor points to an instance of VendorProfile stored at parent PresetBundle! - PresetCollection(const PresetCollection &other) = default; - //BBS: add operator= logic insteadof default + // Deleted by the std::recursive_mutex member. PresetBundle copies by assignment. + PresetCollection(const PresetCollection &other) = delete; + //BBS: hand-written because m_mutex cannot be copy-assigned. PresetCollection& operator=(const PresetCollection &other); - // After copying a collection with the default operators above, call this function - // to adjust Profile::vendor pointers. + // Copying leaves every Preset::vendor pointing into the source bundle's vendor map. + // This re-points them at the matching entries in vendors. void update_vendor_ptrs_after_copy(const VendorMap &vendors); // Select a preset, if it exists. If it does not exist, select an invalid (-1) index. @@ -984,7 +983,8 @@ public: bool only_default_printers() const; private: PrinterPresetCollection() = default; - PrinterPresetCollection(const PrinterPresetCollection &other) = default; + // Deleted along with the base copy constructor. + PrinterPresetCollection(const PrinterPresetCollection &other) = delete; PrinterPresetCollection& operator=(const PrinterPresetCollection &other) = default; friend class PresetBundle; diff --git a/src/libslic3r/SLA/Hollowing.hpp b/src/libslic3r/SLA/Hollowing.hpp index b57513fe72..f6beaadb24 100644 --- a/src/libslic3r/SLA/Hollowing.hpp +++ b/src/libslic3r/SLA/Hollowing.hpp @@ -44,9 +44,6 @@ struct DrainHole : pos(p), normal(n), radius(r), height(h), failed(fl) {} - DrainHole(const DrainHole& rhs) : - DrainHole(rhs.pos, rhs.normal, rhs.radius, rhs.height, rhs.failed) {} - bool operator==(const DrainHole &sp) const; bool operator!=(const DrainHole &sp) const { return !(sp == (*this)); } diff --git a/src/libslic3r/Support/SupportCommon.cpp b/src/libslic3r/Support/SupportCommon.cpp index 0c7a4b832e..b6df219866 100644 --- a/src/libslic3r/Support/SupportCommon.cpp +++ b/src/libslic3r/Support/SupportCommon.cpp @@ -1234,10 +1234,6 @@ static void modulate_extrusion_by_overlapping_layers( (fragment_end.is_start ? &polyline.points.front() : &polyline.points.back()); } private: - ExtrusionPathFragmentEndPointAccessor& operator=(const ExtrusionPathFragmentEndPointAccessor&) { - return *this; - } - const std::vector<ExtrusionPathFragment> &m_path_fragments; }; const coord_t search_radius = 7; diff --git a/src/libslic3r/Support/TreeSupport.hpp b/src/libslic3r/Support/TreeSupport.hpp index e0446ad5f1..61e030ef86 100644 --- a/src/libslic3r/Support/TreeSupport.hpp +++ b/src/libslic3r/Support/TreeSupport.hpp @@ -204,8 +204,9 @@ public: clear_nodes(); } - TreeSupportData(TreeSupportData&&) = default; - TreeSupportData& operator=(TreeSupportData&&) = default; + // Deleted by the tbb::spin_mutex member. + TreeSupportData(TreeSupportData&&) = delete; + TreeSupportData& operator=(TreeSupportData&&) = delete; TreeSupportData(const TreeSupportData&) = delete; TreeSupportData& operator=(const TreeSupportData&) = delete; diff --git a/src/libslic3r/calib.hpp b/src/libslic3r/calib.hpp index ed0f76ee86..abca5e79dc 100644 --- a/src/libslic3r/calib.hpp +++ b/src/libslic3r/calib.hpp @@ -91,29 +91,15 @@ class CaliPresetInfo { public: int tray_id; - int extruder_id; - NozzleVolumeType nozzle_volume_type; - BedType bed_type; + int extruder_id = 0; + NozzleVolumeType nozzle_volume_type{nvtStandard}; + BedType bed_type{btDefault}; float nozzle_diameter; int nozzle_pos_id{-1}; std::string nozzle_sn; std::string filament_id; std::string setting_id; std::string name; - - CaliPresetInfo &operator=(const CaliPresetInfo &other) - { - this->tray_id = other.tray_id; - this->extruder_id = other.extruder_id; - this->nozzle_volume_type = other.nozzle_volume_type; - this->nozzle_diameter = other.nozzle_diameter; - this->nozzle_pos_id = other.nozzle_pos_id; - this->nozzle_sn = other.nozzle_sn; - this->filament_id = other.filament_id; - this->setting_id = other.setting_id; - this->name = other.name; - return *this; - } }; struct PrinterCaliInfo diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index 5760320b49..58c0f95b87 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -675,16 +675,6 @@ public: offset = Vec2d(0, 0); } - TexturePart(const TexturePart& part) { - this->x = part.x; - this->y = part.y; - this->w = part.w; - this->h = part.h; - this->offset = part.offset; - this->buffer = part.buffer; - this->filename = part.filename; - this->texture = part.texture; - } void update_pos(float xx, float yy, float ww, float hh) { x = xx; y = yy; From 7acea3ed09b19b58fe0e1fbe2980ad417ddc2764 Mon Sep 17 00:00:00 2001 From: TheLegendTubaGuy <95944177+thelegendtubaguy@users.noreply.github.com> Date: Thu, 3 Sep 2026 17:42:31 -0500 Subject: [PATCH 50/51] Honor symbolic default bed types for new printers (#15273) Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> --- resources/profiles/Snapmaker.json | 2 +- .../profiles/Snapmaker/machine/fdm_U1.json | 2 +- src/libslic3r/Preset.cpp | 16 +++++--- src/libslic3r/PresetBundle.cpp | 10 +++++ .../libslic3r/test_preset_bundle_loading.cpp | 38 +++++++++++++++++++ 5 files changed, 60 insertions(+), 8 deletions(-) diff --git a/resources/profiles/Snapmaker.json b/resources/profiles/Snapmaker.json index 9a6fab7942..65b1d12a3a 100644 --- a/resources/profiles/Snapmaker.json +++ b/resources/profiles/Snapmaker.json @@ -1,6 +1,6 @@ { "name": "Snapmaker", - "version": "02.04.00.09", + "version": "02.04.00.10", "force_update": "0", "description": "Snapmaker configurations", "machine_model_list": [ diff --git a/resources/profiles/Snapmaker/machine/fdm_U1.json b/resources/profiles/Snapmaker/machine/fdm_U1.json index 717215b507..0b3d89a303 100644 --- a/resources/profiles/Snapmaker/machine/fdm_U1.json +++ b/resources/profiles/Snapmaker/machine/fdm_U1.json @@ -184,7 +184,7 @@ "nozzle_type": "undefine", "auxiliary_fan": "0", "support_multi_bed_types": "1", - "default_bed_type": "4", + "default_bed_type": "Textured PEI Plate", "printable_area": [ "0.5x1", "270.5x1", diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 304c8957d5..235ea66ad2 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -983,15 +983,19 @@ BedType Preset::get_default_bed_type(PresetBundle* preset_bundle) if (config.has("default_bed_type") && !config.opt_string("default_bed_type").empty()) { try { std::string str_bed_type = config.opt_string("default_bed_type"); - - // Try parsing as integer first (legacy format) + BedType bed_type; + if (ConfigOptionEnum<BedType>::from_string(str_bed_type, bed_type) && + bed_type > btDefault && bed_type < btCount) { + return bed_type; + } + + // Try parsing as integer (legacy format) int bed_type_value = atoi(str_bed_type.c_str()); - if (bed_type_value > 0) { + if (bed_type_value > 0 && bed_type_value < BedType::btCount) { return BedType(bed_type_value); } - else { - BOOST_LOG_TRIVIAL(error) << "default_bed_type: invalid bed type: " << str_bed_type; - } + + BOOST_LOG_TRIVIAL(error) << "default_bed_type: invalid bed type: " << str_bed_type; return BedType::btPEI; } catch(...) { diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index 8e5d565c55..2dfc967e3f 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -2920,6 +2920,16 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p // If executed due to a Config Wizard update, preferred_printer contains the first newly installed printer, otherwise nullptr. const Preset *preferred_printer = printers.find_system_preset_by_model_and_variant(preferred_selection.printer_model_id, preferred_selection.printer_variant); printers.select_preset_by_name(preferred_printer ? preferred_printer->name : initial_printer_profile_name, true); + Preset &selected_printer = printers.get_edited_preset(); + if (selected_printer.printer_technology() == ptFFF) { + BedType bed_type = selected_printer.get_default_bed_type(this); + const std::string saved_bed_type = config.get_printer_setting(selected_printer.name, "curr_bed_type"); + const int saved_bed_type_value = atoi(saved_bed_type.c_str()); + if (saved_bed_type_value > btDefault && saved_bed_type_value < btCount) + bed_type = static_cast<BedType>(saved_bed_type_value); + project_config.set_key_value("curr_bed_type", new ConfigOptionEnum<BedType>(bed_type)); + config.set("curr_bed_type", std::to_string(static_cast<int>(bed_type))); + } CNumericLocalesSetter locales_setter; // Orca: load from orca_presets diff --git a/tests/libslic3r/test_preset_bundle_loading.cpp b/tests/libslic3r/test_preset_bundle_loading.cpp index 55c18bfa9e..c75a05949e 100644 --- a/tests/libslic3r/test_preset_bundle_loading.cpp +++ b/tests/libslic3r/test_preset_bundle_loading.cpp @@ -184,6 +184,44 @@ TEST_CASE("Printer extruder count tolerates missing nozzle diameter", "[Preset][ CHECK(bundle.get_printer_extruder_count() == 2); } +TEST_CASE("Selected printer uses its default or saved bed type", "[Preset][Bundle]") +{ + PresetBundle bundle; + Preset& printer = add_inmemory_preset(bundle.printers, "Test Printer"); + printer.is_system = true; + printer.config.option<ConfigOptionString>("printer_model")->value = "TEST-MODEL"; + printer.config.option<ConfigOptionString>("printer_variant")->value = "0.4"; + printer.config.option<ConfigOptionString>("default_bed_type")->value = "Engineering Plate"; + + AppConfig app_config; + app_config.set("curr_bed_type", std::to_string(static_cast<int>(btPTE))); + PresetBundle::PresetPreferences preferred_selection; + BedType expected_bed_type; + + SECTION("New printer uses its symbolic default") { + expected_bed_type = btEP; + preferred_selection = {"TEST-MODEL", "0.4"}; + } + SECTION("Re-enabled printer uses its saved selection") { + expected_bed_type = btPC; + preferred_selection = {"TEST-MODEL", "0.4"}; + app_config.set_printer_setting("Test Printer", "curr_bed_type", + std::to_string(static_cast<int>(expected_bed_type))); + } + SECTION("Existing printer keeps its saved selection after presets reload") { + expected_bed_type = btPCT; + app_config.set("presets", PRESET_PRINTER_NAME, "Test Printer"); + app_config.set_printer_setting("Test Printer", "curr_bed_type", + std::to_string(static_cast<int>(expected_bed_type))); + } + + bundle.load_selections(app_config, preferred_selection); + bundle.export_selections(app_config); + + CHECK(bundle.project_config.opt_enum<BedType>("curr_bed_type") == expected_bed_type); + CHECK(app_config.get_printer_setting("Test Printer", "curr_bed_type") == std::to_string(static_cast<int>(expected_bed_type))); +} + TEST_CASE("find_preset resolves a system preset's renamed_from", "[Preset][Rename]") { RenameTestCollection coll; From 57ce18d70d0e6084884d2cb8bcf07792a852e74b Mon Sep 17 00:00:00 2001 From: HanifKoh <76276251+HanifKoh@users.noreply.github.com> Date: Fri, 4 Sep 2026 11:31:42 +0800 Subject: [PATCH 51/51] [CLI]: CLI Argument Parsing Fixes (#15478) * Reject invalid CLI argument values instead of silently accepting them * Add read_cli accept/reject tests * Update Option Type for LogFile argument * Add read_cli vector option tests * Accept common bool spellings on the CLI, cover --logfile in tests * Add unit tests for truthy bool parsing --- src/OrcaSlicer.cpp | 2 +- src/libslic3r/Config.cpp | 53 +++++++- src/libslic3r/PrintConfig.cpp | 8 +- tests/libslic3r/test_config.cpp | 223 ++++++++++++++++++++++++++++++++ 4 files changed, 274 insertions(+), 12 deletions(-) diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 33669abcf2..ab26a3f7c8 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -7384,7 +7384,7 @@ void CLI::print_help(bool include_print_options, PrinterTechnology printer_techn << std::endl << "Print setting priorities:" << std::endl << "\t1) setting values from the command line (highest priority)"<< std::endl - << "\t2) setting values loaded with --load_settings and --load_filaments" << std::endl + << "\t2) setting values loaded with --load-settings and --load-filaments" << std::endl << "\t3) setting values loaded from 3mf(lowest priority)" << std::endl; /*if (include_print_options) { diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 242e4bb146..a2756a9f8e 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -1715,6 +1715,36 @@ const ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key) co return (it == options.end()) ? nullptr : it->second.get(); } +// ConfigOptionBool(s)::deserialize only understands "1" and "0", but scripts commonly spell CLI +// flags as --opt=true or --opt=no. Map the usual spellings onto what deserialize() accepts, per +// comma-separated item so vector options keep working, and pass anything else through unchanged +// so a genuine typo is still reported as invalid. +static std::string normalize_cli_bool_value(const std::string &value) +{ + static const char* true_values[] = { "1", "true", "yes", "on", "enabled" }; + static const char* false_values[] = { "0", "false", "no", "off", "disabled" }; + + auto matches = [](const std::string &item, const char* const* candidates, size_t count) { + return std::any_of(candidates, candidates + count, [&item](const char* candidate) { return boost::iequals(item, candidate); }); + }; + + std::string normalized; + std::istringstream is(value); + std::string item; + while (std::getline(is, item, ',')) { + boost::trim(item); + if (! normalized.empty()) + normalized += ","; + if (matches(item, true_values, std::size(true_values))) + normalized += "1"; + else if (matches(item, false_values, std::size(false_values))) + normalized += "0"; + else + normalized += item; + } + return normalized; +} + bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys) { // cache the CLI option => opt_key mapping @@ -1812,17 +1842,32 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option // to the end of the value. if (opt_base->type() == coBools && value.empty()) static_cast<ConfigOptionBools*>(opt_base)->values.push_back(!no); - else + else { // Deserialize any other vector value (ConfigOptionInts, Floats, Percents, Points) the same way // they get deserialized from an .ini file. For ConfigOptionStrings, that means that the C-style unescape // will be applied for values enclosed in quotes, while values non-enclosed in quotes are left to be // unescaped by the calling shell. - opt_vector->deserialize(value, true); + const std::string vector_value = opt_base->type() == coBools ? normalize_cli_bool_value(value) : value; + bool deserialized = false; + try { + deserialized = opt_vector->deserialize(vector_value, true); + } catch (const std::exception &ex) { + // e.g. "nil" deserialized into a non-nullable vector option throws instead of + // returning false - treat that the same as any other invalid value here. + deserialized = false; + } + if (! deserialized) { + boost::nowide::cerr << "Invalid value for option --" << token.c_str() << std::endl; + return false; + } + } } else if (opt_base->type() == coBool) { if (value.empty()) static_cast<ConfigOptionBool*>(opt_base)->value = !no; - else - opt_base->deserialize(value); + else if (! opt_base->deserialize(normalize_cli_bool_value(value))) { + boost::nowide::cerr << "Invalid value for option --" << token.c_str() << std::endl; + return false; + } } else if (opt_base->type() == coString) { // Do not unescape single string values, the unescaping is left to the calling shell. static_cast<ConfigOptionString*>(opt_base)->value = value; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 29362fcf39..7d93341b98 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -11990,13 +11990,11 @@ CLIActionsConfigDef::CLIActionsConfigDef() def = this->add("load_defaultfila", coBool); def->label = L("Load default filaments"); def->tooltip = L("Load first filament as default for those not loaded."); - def->cli_params = "option"; def->set_default_value(new ConfigOptionBool(false)); def = this->add("min_save", coBool); def->label = L("Minimum save"); def->tooltip = L("Export 3MF with minimum size."); - def->cli_params = "option"; def->set_default_value(new ConfigOptionBool(false)); def = this->add("mtcpp", coInt); @@ -12022,7 +12020,6 @@ CLIActionsConfigDef::CLIActionsConfigDef() def = this->add("normative_check", coBool); def->label = L("Normative check"); def->tooltip = L("Check the normative items."); - def->cli_params = "option"; def->set_default_value(new ConfigOptionBool(true)); /*def = this->add("help_fff", coBool); @@ -12289,7 +12286,7 @@ CLIMiscConfigDef::CLIMiscConfigDef() def->cli_params = "level"; def->set_default_value(new ConfigOptionInt(1)); - def = this->add("logfile", coInt); + def = this->add("logfile", coString); def->label = L("Log file"); def->tooltip = L("Redirects debug logging to file.\n"); def->cli_params = "file"; @@ -12337,7 +12334,6 @@ CLIMiscConfigDef::CLIMiscConfigDef() def = this->add("skip_modified_gcodes", coBool); def->label = L("Skip modified G-code in 3MF"); def->tooltip = L("Skip the modified G-code in 3MF from printer or filament presets."); - def->cli_params = "option"; def->set_default_value(new ConfigOptionBool(false)); def = this->add("makerlab_name", coString); @@ -12367,14 +12363,12 @@ CLIMiscConfigDef::CLIMiscConfigDef() def = this->add("allow_newer_file", coBool); def->label = L("Allow 3MF with newer version to be sliced"); def->tooltip = L("Allow 3MF with newer version to be sliced."); - def->cli_params = "option"; def->set_default_value(new ConfigOptionBool(false)); def = this->add("allow_mix_temp", coBool); // internal use only, don't need translation def->label = "Allow filaments with high/low temperature to be printed together"; def->tooltip = "Allow filaments with high/low temperature to be printed together."; - def->cli_params = "option"; def->set_default_value(new ConfigOptionBool(false)); } diff --git a/tests/libslic3r/test_config.cpp b/tests/libslic3r/test_config.cpp index 12b161322d..2627c3cda0 100644 --- a/tests/libslic3r/test_config.cpp +++ b/tests/libslic3r/test_config.cpp @@ -828,3 +828,226 @@ SCENARIO("ConfigOptionVector::set_to_index throws on incompatible type", "[Confi } } } + +TEST_CASE("read_cli applies valid values and collects non-option arguments", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--nozzle-temperature", "210,190", "--reduce-crossing-wall=1", "model.3mf"}; + REQUIRE(config.read_cli(5, argv, &extra, &keys)); + REQUIRE(config.opt<ConfigOptionInts>("nozzle_temperature")->values == std::vector<int>{210, 190}); + REQUIRE(config.opt<ConfigOptionBool>("reduce_crossing_wall")->value); + REQUIRE(extra == t_config_option_keys{"model.3mf"}); + REQUIRE(keys == t_config_option_keys{"nozzle_temperature", "reduce_crossing_wall"}); +} + +TEST_CASE("read_cli rejects nil for a non-nullable vector option", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--nozzle-temperature", "nil"}; + REQUIRE_FALSE(config.read_cli(3, argv, &extra, &keys)); +} + +TEST_CASE("read_cli rejects an invalid boolean value", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--reduce-crossing-wall=maybe"}; + REQUIRE_FALSE(config.read_cli(2, argv, &extra, &keys)); +} + +TEST_CASE("read_cli accepts the common spellings of a boolean value", "[Config]") { + const auto [text, expected] = GENERATE(table<const char*, bool>({ + {"--reduce-crossing-wall=1", true }, + {"--reduce-crossing-wall=true", true }, + {"--reduce-crossing-wall=Yes", true }, + {"--reduce-crossing-wall=on", true }, + {"--reduce-crossing-wall=enabled", true }, + {"--reduce-crossing-wall=TRUE", true }, + {"--reduce-crossing-wall=oN", true }, + {"--reduce-crossing-wall=0", false}, + {"--reduce-crossing-wall=false", false}, + {"--reduce-crossing-wall=No", false}, + {"--reduce-crossing-wall=off", false}, + {"--reduce-crossing-wall=disabled", false}, + {"--reduce-crossing-wall=FALSE", false}, + {"--reduce-crossing-wall=DiSaBlEd", false}, + })); + + DYNAMIC_SECTION(text) { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", text}; + REQUIRE(config.read_cli(2, argv, &extra, &keys)); + REQUIRE(config.opt<ConfigOptionBool>("reduce_crossing_wall")->value == expected); + } +} + +TEST_CASE("read_cli accepts the common boolean spellings inside a bools vector", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--filament-soluble=true,no,1"}; + REQUIRE(config.read_cli(2, argv, &extra, &keys)); + REQUIRE(config.opt<ConfigOptionBools>("filament_soluble")->values == std::vector<unsigned char>{1, 0, 1}); +} + +TEST_CASE("read_cli trims whitespace around boolean spellings", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--reduce-crossing-wall= true ", "--filament-soluble= true , no ,1"}; + REQUIRE(config.read_cli(3, argv, &extra, &keys)); + REQUIRE(config.opt<ConfigOptionBool>("reduce_crossing_wall")->value); + REQUIRE(config.opt<ConfigOptionBools>("filament_soluble")->values == std::vector<unsigned char>{1, 0, 1}); +} + +TEST_CASE("read_cli normalizes boolean spellings when a bools vector is repeated", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--filament-soluble=true", "--filament-soluble=off"}; + REQUIRE(config.read_cli(3, argv, &extra, &keys)); + REQUIRE(config.opt<ConfigOptionBools>("filament_soluble")->values == std::vector<unsigned char>{1, 0}); +} + +TEST_CASE("read_cli keeps nil alongside boolean spellings in a nullable bools vector", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--enable-overhang-speed=nil,yes,off"}; + REQUIRE(config.read_cli(2, argv, &extra, &keys)); + auto* opt = config.opt<ConfigOptionBoolsNullable>("enable_overhang_speed"); + REQUIRE(opt != nullptr); + REQUIRE(opt->values.size() == 3); + REQUIRE(opt->is_nil(0)); + REQUIRE(opt->values[1] == 1); + REQUIRE(opt->values[2] == 0); +} + +TEST_CASE("read_cli rejects an empty item inside a bools vector", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--filament-soluble=true,,1"}; + REQUIRE_FALSE(config.read_cli(2, argv, &extra, &keys)); +} + +TEST_CASE("read_cli rejects an unknown spelling next to a valid one in a bools vector", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--filament-soluble=true,affirmative"}; + REQUIRE_FALSE(config.read_cli(2, argv, &extra, &keys)); +} + +// The normalization lives in read_cli's boolean branches, so options of other types keep the +// value verbatim - a path named "on" or a colour named "true" must not turn into "1". +TEST_CASE("read_cli leaves boolean spellings alone for non-boolean options", "[Config]") { + SECTION("string option") { + Slic3r::DynamicPrintAndCLIConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--logfile=true"}; + REQUIRE(config.read_cli(2, argv, &extra, &keys)); + REQUIRE(config.opt<ConfigOptionString>("logfile")->value == "true"); + } + SECTION("strings vector option") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--filament-colour=on;off"}; + REQUIRE(config.read_cli(2, argv, &extra, &keys)); + REQUIRE(config.opt<ConfigOptionStrings>("filament_colour")->values == std::vector<std::string>{"on", "off"}); + } +} + +TEST_CASE("read_cli treats a bare boolean flag as true without consuming the next argument", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--reduce-crossing-wall", "model.3mf"}; + REQUIRE(config.read_cli(3, argv, &extra, &keys)); + REQUIRE(config.opt<ConfigOptionBool>("reduce_crossing_wall")->value); + REQUIRE(extra == t_config_option_keys{"model.3mf"}); +} + +TEST_CASE("read_cli rejects an invalid scalar numeric value", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--top-shell-layers", "several"}; + REQUIRE_FALSE(config.read_cli(3, argv, &extra, &keys)); +} + +TEST_CASE("read_cli appends values when a vector option is repeated", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--nozzle-temperature", "210", "--nozzle-temperature", "190,200"}; + REQUIRE(config.read_cli(5, argv, &extra, &keys)); + REQUIRE(config.opt<ConfigOptionInts>("nozzle_temperature")->values == std::vector<int>{210, 190, 200}); + // the key is recorded once, on first use + REQUIRE(keys == t_config_option_keys{"nozzle_temperature"}); +} + +TEST_CASE("read_cli parses a bools vector given in the --flag=values form", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--filament-soluble=1,0,1"}; + REQUIRE(config.read_cli(2, argv, &extra, &keys)); + REQUIRE(config.opt<ConfigOptionBools>("filament_soluble")->values == std::vector<unsigned char>{1, 0, 1}); +} + +TEST_CASE("read_cli rejects an invalid value inside a bools vector", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--filament-soluble=1,maybe"}; + REQUIRE_FALSE(config.read_cli(2, argv, &extra, &keys)); +} + +TEST_CASE("read_cli appends true for a bare bools vector flag", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--filament-soluble"}; + REQUIRE(config.read_cli(2, argv, &extra, &keys)); + REQUIRE(config.opt<ConfigOptionBools>("filament_soluble")->values == std::vector<unsigned char>{1}); +} + +TEST_CASE("read_cli splits a strings vector on semicolons and unescapes quoted items", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--filament-colour", "#FF0000;\"a\\nb\";#00FF00"}; + REQUIRE(config.read_cli(3, argv, &extra, &keys)); + auto& values = config.opt<ConfigOptionStrings>("filament_colour")->values; + REQUIRE(values == std::vector<std::string>{"#FF0000", "a\nb", "#00FF00"}); +} + +TEST_CASE("read_cli rejects a strings vector with an unterminated quote", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--filament-colour", "\"oops"}; + REQUIRE_FALSE(config.read_cli(3, argv, &extra, &keys)); +} + +TEST_CASE("read_cli parses a points vector in the NxM coordinate form", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--printable-area", "0x0,200x0,200x200,0x200"}; + REQUIRE(config.read_cli(3, argv, &extra, &keys)); + auto& points = config.opt<ConfigOptionPoints>("printable_area")->values; + REQUIRE(points.size() == 4); + REQUIRE_THAT(points[1].x(), Catch::Matchers::WithinAbs(200.0, 1e-9)); + REQUIRE_THAT(points[1].y(), Catch::Matchers::WithinAbs(0.0, 1e-9)); + REQUIRE_THAT(points[3].x(), Catch::Matchers::WithinAbs(0.0, 1e-9)); + REQUIRE_THAT(points[3].y(), Catch::Matchers::WithinAbs(200.0, 1e-9)); +} + +// logfile is a CLI-only option, so it needs the config type whose def pulls in cli_misc_config_def. +TEST_CASE("read_cli stores the log file path as a string", "[Config]") { + Slic3r::DynamicPrintAndCLIConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--logfile", "orca.log"}; + REQUIRE(config.read_cli(3, argv, &extra, &keys)); + REQUIRE(config.opt<ConfigOptionString>("logfile")->value == "orca.log"); +} + +TEST_CASE("read_cli accepts nil entries for a nullable vector option", "[Config]") { + Slic3r::DynamicPrintConfig config; + t_config_option_keys extra, keys; + const char* argv[] = {"orca-slicer", "--filament-retraction-length", "nil,2.5"}; + REQUIRE(config.read_cli(3, argv, &extra, &keys)); + auto* opt = config.opt<ConfigOptionFloatsNullable>("filament_retraction_length"); + REQUIRE(opt != nullptr); + REQUIRE(opt->values.size() == 2); + REQUIRE(opt->is_nil(0)); + REQUIRE_FALSE(opt->is_nil(1)); + REQUIRE_THAT(opt->values[1], Catch::Matchers::WithinAbs(2.5, 1e-9)); +}