Merge branch 'main' into cad-mainline

This commit is contained in:
SoftFever
2026-08-27 17:06:37 +08:00
committed by GitHub
252 changed files with 47868 additions and 2359 deletions
+5
View File
@@ -1,2 +1,7 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Shell scripts are run by Git Bash on Windows CI, which cannot read a script
# 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
+2
View File
@@ -15,6 +15,7 @@ on:
- 'localization/**'
- 'resources/**'
- ".github/workflows/build_*.yml"
- 'scripts/build_preset_cache.*'
- 'scripts/flatpak/**'
- 'scripts/msix/**'
- 'tests/**'
@@ -34,6 +35,7 @@ on:
- 'build_release_vs.bat'
- 'build_release_vs2022.bat'
- 'build_release_macos.sh'
- 'scripts/build_preset_cache.*'
- 'scripts/flatpak/**'
- 'scripts/msix/**'
- 'tests/**'
+29
View File
@@ -162,6 +162,14 @@ jobs:
retention-days: 5
if-no-files-found: error
- name: Build system preset cache (macOS)
if: runner.os == 'macOS' && !inputs.macos-combine-only
working-directory: ${{ github.workspace }}
shell: bash
# The bundle was already packed from resources/, so the caches have to be
# installed into it here; the source tree keeps its JSONs for later jobs.
run: ./scripts/build_preset_cache.sh -b build/${{ inputs.arch }} build/${{ inputs.arch }}/OrcaSlicer/OrcaSlicer.app/Contents/Resources/profiles
- name: Pack macOS app bundle ${{ inputs.arch }}
if: runner.os == 'macOS' && !inputs.macos-combine-only
working-directory: ${{ github.workspace }}
@@ -390,6 +398,13 @@ jobs:
if ($arch -eq "arm64") { .\build_release_vs.bat slicer arm64 tests } else { .\build_release_vs.bat slicer tests }
shell: pwsh
- name: Build system preset cache (Windows)
if: runner.os == 'Windows'
shell: cmd
# Shipped into both the already-installed tree (portable zip, MSIX) and
# the checkout cpack re-installs from when it builds the NSIS installer.
run: scripts\build_preset_cache.bat --prune-source "%BUILD_DIR%" "resources\profiles" "%BUILD_DIR%\OrcaSlicer\resources\profiles"
- name: Pack unit tests Win
if: runner.os == 'Windows'
working-directory: ${{ github.workspace }}
@@ -539,6 +554,20 @@ jobs:
retention-days: 5
if-no-files-found: error
- name: Build system preset cache (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
# Both were packed from resources/ before the caches existed, so the
# AppImage is unpacked first and the caches shipped into it and into
# the package tree; the source tree keeps its JSONs for later steps.
appimage=$(find build -maxdepth 1 -name "OrcaSlicer_Linux_AppImage*.AppImage" | head -1)
chmod +x "$appimage"
"$appimage" --appimage-extract
./scripts/build_preset_cache.sh -b build build/package/resources/profiles squashfs-root/resources/profiles
appimagetool=$(find build -name "appimagetool.AppImage" | head -1)
ARCH=$(uname -m) "$appimagetool" --appimage-extract-and-run squashfs-root "$appimage"
rm -rf squashfs-root
# Ship the freshly-built validator so slice_check_linux (build_all.yml)
# can slice-sweep the shipped profiles with this PR's engine. Taken from
# the aarch64 leg so the sweep also exercises the arm build; x86_64 on
+2
View File
@@ -2,6 +2,7 @@ Build
Build.bat
/build*/
CMakeLists.txt.user
CMakeUserPresets.json
**/CMakeLists.txt.autosave
deps/build*
MYMETA.json
@@ -49,3 +50,4 @@ internal_docs/
# Python bytecode
__pycache__/
*.pyc
*.opc
+80 -6
View File
@@ -59,6 +59,13 @@ if (APPLE)
message(STATUS "CMAKE_OSX_DEPLOYMENT_TARGET: ${CMAKE_OSX_DEPLOYMENT_TARGET}")
endif ()
# Keep MSVC's default /W3 out of CMAKE_<LANG>_FLAGS so it can be applied to our own
# targets only. Silencing a bundled target would otherwise override a warning level,
# which cl reports as D9025 for every file it compiles.
if (POLICY CMP0092)
cmake_policy(SET CMP0092 NEW)
endif ()
project(OrcaSlicer)
# Backward compatibility for old CMake versions
@@ -127,6 +134,8 @@ option(SLIC3R_CAD "Compile OrcaSlicer with the parametric Design/C
option(SLIC3R_FHS "Assume OrcaSlicer is to be installed in a FHS directory structure" 0)
option(SLIC3R_PROFILE "Compile OrcaSlicer with an invasive Shiny profiler" 0)
option(SLIC3R_PCH "Use precompiled headers" 1)
option(SLIC3R_WARNINGS "Emit compiler warnings for OrcaSlicer sources" 1)
option(SLIC3R_BUNDLED_WARNINGS "Emit compiler warnings for bundled third-party sources" 0)
option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
@@ -340,15 +349,20 @@ if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL Clang)
# clang-cl can interpret SYSTEM header paths if -imsvc is used
set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-imsvc")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall \
-Wno-old-style-cast -Wno-reserved-id-macro -Wno-c++98-compat-pedantic")
else ()
set(IS_CLANG_CL FALSE)
endif ()
if (MSVC)
if (SLIC3R_MSVC_COMPILE_PARALLEL AND NOT IS_CLANG_CL)
# CMP0092 only applies when the cache is created; an existing tree keeps its /W3,
# which a silenced bundled target would then override (D9025, once per file).
string(REGEX REPLACE "/W[0-4]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
# /MP only matters for the VS generators, where CMake turns it into the
# MultiProcessorCompilation property. Ninja parallelises on its own, and
# clang-cl warns "argument unused" if the flag reaches it.
if (SLIC3R_MSVC_COMPILE_PARALLEL AND CMAKE_GENERATOR MATCHES "Visual Studio")
add_compile_options(/MP)
endif ()
# /bigobj (Increase Number of Sections in .Obj file)
@@ -528,8 +542,15 @@ if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals" )
endif()
if (NOT MSVC AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
if (NOT MINGW)
if ((NOT MSVC OR IS_CLANG_CL) AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
if (IS_CLANG_CL)
# clang-cl reads -Wall as MSVC /Wall, which clang maps to -Weverything. /W4 is
# its -Wall -Wextra and, unlike /clang:-Wall, is ordered with the -Wno-* below
# instead of after them. The -Wextra-only warnings are dropped again so the set
# matches what -Wall gives the GNU/Clang builds.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4" )
add_compile_options(-Wno-unused-parameter -Wno-ignored-qualifiers -Wno-missing-field-initializers)
elseif (NOT MINGW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall" )
endif ()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder" )
@@ -1071,8 +1092,57 @@ function(orcaslicer_copy_dlls target config postfix output_dlls)
endfunction()
# Bundled sources set their own warning flags, and a plain -Wall there means /Wall
# (= -Weverything) under clang-cl. Target options are applied after the ones a target
# set on itself, so these win. Targets are discovered rather than listed so a newly
# bundled library needs no maintenance here.
function(orcaslicer_silence_third_party_warnings _dir)
get_property(_subdirs DIRECTORY "${_dir}" PROPERTY SUBDIRECTORIES)
foreach (_subdir IN LISTS _subdirs)
orcaslicer_silence_third_party_warnings("${_subdir}")
endforeach ()
get_property(_targets DIRECTORY "${_dir}" PROPERTY BUILDSYSTEM_TARGETS)
foreach (_target IN LISTS _targets)
get_target_property(_type ${_target} TYPE)
if (NOT _type STREQUAL "INTERFACE_LIBRARY" AND NOT _type STREQUAL "UTILITY")
if (MSVC AND NOT IS_CLANG_CL)
# Drop any level the target set for itself, or -w overrides it and cl
# reports D9025 once per file.
get_target_property(_opts ${_target} COMPILE_OPTIONS)
if (_opts)
string(REGEX REPLACE "/W[0-4]|/Wall" "" _opts "${_opts}")
string(REGEX REPLACE ";;+" ";" _opts "${_opts}")
set_target_properties(${_target} PROPERTIES COMPILE_OPTIONS "${_opts}")
endif ()
# CMake maps a level into the VS generator's WarningLevel element, while a
# bare -w stays on the command line and trips D9025 there, once per file.
target_compile_options(${_target} PRIVATE /W0)
else ()
target_compile_options(${_target} PRIVATE -w)
endif ()
endif ()
endforeach ()
endfunction()
# libslic3r, OrcaSlicer GUI and the OrcaSlicer executable.
add_subdirectory(deps_src)
if (NOT SLIC3R_BUNDLED_WARNINGS)
orcaslicer_silence_third_party_warnings("${CMAKE_CURRENT_SOURCE_DIR}/deps_src")
endif ()
# Warning level for the targets added below: our sources, plus glad and libvgcode,
# which are vendored but live under src/. The deps_src libraries were configured just
# above. CMP0092 left MSVC without a default level, so it is set here.
if (NOT SLIC3R_WARNINGS)
add_compile_options(-w)
elseif (MSVC AND NOT IS_CLANG_CL)
# /we4715 is C4715, no return from a non-void function, matching the
# -Werror=return-type the GNU/Clang builds apply.
add_compile_options(/W3 /we4715)
endif ()
add_subdirectory(src)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT OrcaSlicer_app_gui)
@@ -1084,6 +1154,10 @@ endif()
if(BUILD_TESTS)
add_subdirectory(tests)
if (NOT SLIC3R_BUNDLED_WARNINGS)
# Catch2 is vendored under tests/ and sets its own warning flags too.
orcaslicer_silence_third_party_warnings("${CMAKE_CURRENT_SOURCE_DIR}/tests/catch2")
endif ()
endif()
if (NOT WIN32 AND NOT APPLE)
+2
View File
@@ -567,6 +567,8 @@ if [[ -n "${BUILD_ORCA}" ]] || [[ -n "${BUILD_TESTS}" ]] ; then
print_and_run cmake --build $BUILD_DIR --config "${BUILD_CONFIG}" --target OrcaSlicer
echo "Building OrcaSlicer_profile_validator .."
print_and_run cmake --build $BUILD_DIR --config "${BUILD_CONFIG}" --target OrcaSlicer_profile_validator
echo "Building generate_system_cache ..."
print_and_run cmake --build $BUILD_DIR --config "${BUILD_CONFIG}" --target generate_system_cache
./scripts/run_gettext.sh
fi
if [[ -n "${BUILD_TESTS}" ]] ; then
+40
View File
@@ -0,0 +1,40 @@
if(CMAKE_VERSION VERSION_LESS 3.22)
set(_assimp_url "https://github.com/assimp/assimp/archive/refs/tags/v5.3.1.tar.gz")
set(_assimp_hash "SHA256=a07666be71afe1ad4bc008c2336b7c688aca391271188eb9108d0c6db1be53f1")
else()
set(_assimp_url "https://github.com/assimp/assimp/archive/refs/tags/v5.4.3.tar.gz")
set(_assimp_hash "SHA256=66dfbaee288f2bc43172440a55d0235dfc7bf885dda6435c038e8000e79582cb")
endif()
# Assimp's bundled zlib (contrib/zlib) is too old to compile against the modern
# macOS SDK: its zutil.h takes the classic-Mac branch under TARGET_OS_MAC and
# does `#define fdopen(fd,mode) NULL`, which then clobbers the SDK's real
# `fdopen` prototype in <stdio.h> and breaks the build. On macOS use the system
# zlib (already found by find_package(ZLIB) in deps-unix-common) instead.
if(APPLE)
set(_assimp_build_zlib "-DASSIMP_BUILD_ZLIB=OFF")
else()
set(_assimp_build_zlib "-DASSIMP_BUILD_ZLIB=ON")
endif()
orcaslicer_add_cmake_project(Assimp
URL ${_assimp_url}
URL_HASH ${_assimp_hash}
CMAKE_ARGS
-DASSIMP_BUILD_TESTS=OFF
-DASSIMP_BUILD_SAMPLES=OFF
-DASSIMP_BUILD_ASSIMP_TOOLS=OFF
-DASSIMP_INSTALL_PDB=OFF
-DASSIMP_NO_EXPORT=ON
-DASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT=OFF
-DASSIMP_BUILD_GLTF_IMPORTER=ON
-DASSIMP_BUILD_OBJ_IMPORTER=ON
-DASSIMP_BUILD_FBX_IMPORTER=ON
${_assimp_build_zlib}
-DASSIMP_WARNINGS_AS_ERRORS=OFF
-DBUILD_WITH_STATIC_CRT=OFF
)
if (MSVC)
add_debug_dep(dep_Assimp)
endif ()
+4
View File
@@ -368,6 +368,9 @@ include(libnoise/libnoise.cmake)
include(Draco/Draco.cmake)
# Assimp: glTF/GLB/FBX import for the texture-to-color feature.
include(Assimp/Assimp.cmake)
# I *think* 1.1 is used for *just* md5 hashing?
# 3.1 has everything in the right place, but the md5 funcs used are deprecated
@@ -450,6 +453,7 @@ set(_dep_list
dep_libnoise
dep_python3
dep_wxInspector
dep_Assimp
)
if (MSVC)
+402
View File
@@ -0,0 +1,402 @@
# System Preset Cache — High Level Design
## Why it exists
OrcaSlicer ships tens of thousands of system preset JSON files. Every launch used to
parse all of them: read each vendor profile, walk its machine, process and filament
sub-files, resolve inheritance, and build the preset collections from scratch. That
parse dominated startup, and it produced the same result every time, because system
presets only change when the app is updated or a profile update is installed.
The preset cache replaces that parse with a read. Each vendor's presets are serialized
once — at build time, in CI — into a single binary file the app reads in one pass. The
read replaces the file walk and the JSON parsing, which is where the time went;
resolving inheritance and registering the presets still runs at load, through the same
code the JSON path uses, so the result is the parse's result without the parse.
The cache is **only ever an optimization**. Every rule below exists to guarantee that a
cache is either provably equivalent to parsing the JSONs, or rejected. There is no
"mostly right" cache.
## The unit is one vendor
A cache covers exactly one vendor. `BBL.opc` sits beside `BBL.json` and holds
everything `BBL.json` and the `BBL/` sub-file tree would have produced.
Per-vendor granularity is what makes the system practical:
- A vendor whose profile is bumped invalidates only its own cache. The other 60-odd
vendors keep theirs — even when the bumped vendor is the shared Orca filament
library everyone else inherits from.
- The setup wizard, which loads vendors one at a time, gets the same speedup as
startup without a second code path.
- A vendor with no cache, or a broken one, costs only that vendor a parse.
A cache holds *system* presets only. User presets, project settings and modified
presets are never serialized — they have their own storage and their own lifecycle.
## Where the files live
| Location | Contents on a shipped build | Role |
|---|---|---|
| `resources/profiles/` | `<vendor>.opc` alone — the profile and its preset JSONs both pruned | What the app ships with; what installing copies from, and the only thing it is read for |
| `<data_dir>/system/` | `<vendor>.opc` alone, or `<vendor>.json` + `<vendor>/` after an update | What the user has installed |
| `<data_dir>/system/` (dev build) | `<vendor>.json` + `<vendor>/` + `<vendor>.opc` written at runtime | A developer tree caches as it parses |
| `<data_dir>/cache/wizard_profile_data.json` | The wizard's derived vendor catalog plus the stamps it was built from | Written and read by the setup wizard only; never shipped (see "The wizard's profile-data cache") |
Two forms of the same vendor therefore exist, and the system's central rule is that
**a vendor's cache is the whole of it**. Where a cache ships or is installed, no profile
and no preset JSONs sit beside it: the cache carries the presets, the vendor profile,
and the version stamp that says which release it came from. A vendor is "installed" if
either form is present *and usable*, and its installed version is read from whichever
form a load would serve.
What stays beside the caches in `resources/profiles/` is everything that is not a
preset: each vendor's directory of printer thumbnails, cover images, bed models and
hotend meshes, which are read from disk by path and were never part of the cache. Files
that are not vendors at all, `blacklist.json` chief among them, are untouched.
The alternative — shipping both and treating the cache as a sidecar — was rejected. It
doubles the installed size, and it creates a class of bug where the two disagree and
the app's behavior depends on which one a given code path happened to read.
## What a cache file is
A fixed-size header followed by one binary stream.
The header carries a magic number, the cache format version, the payload size and a
CRC32 of the payload. It exists so that a truncated download, a half-written file or a
file from an entirely different program is rejected in microseconds, before anything
tries to interpret it.
The payload opens with the stamps that decide whether the cache may be used at all —
format version, vendor name, vendor version — then a dictionary, and then the vendor's
data: its vendor profile, three lists of preset entries (process, filament, machine),
and the count of errors the original parse hit.
Each entry is one preset **in source form**: what its JSON sub-file states and nothing
that resolving it derives — the preset's own config diff, the name of the preset it
inherits, and the parse metadata (name, sub-path, description, instantiation, setting
and filament ids, renames). Non-instantiated base presets are stored too; the children
that inherit from them cannot resolve without them.
**The payload names its own keys.** The dictionary holds the distinct `opt_key`s the
file uses, the `ConfigOptionType` each was written as, and the distinct enum *value
names*; an option in an entry's config is then a `uint16` index into that dictionary
plus its value. Names are written once per file rather than once per occurrence, and a
reader resolves the dictionary against this build's `print_config_def` once, after
which reading an option is a vector index.
This is what makes the cache survive config-schema drift. The alternative — keying an
option by its `serialization_key_ordinal`, the position `ConfigDef::add` assigns by
declaration order at static init — cannot: inserting one option into the middle of
`PrintConfig.cpp` shifts every later ordinal, and the lookup on the way back in then
*succeeds on the wrong option*, silently, wherever the two share a type. Because a
name-keyed payload instead drops the individual options this build cannot place, the
file as a whole stays readable, and there is no schema fingerprint — no checksum over
the option schema that would reject every cache on every release. An option this build
no longer defines, or now defines with a different type, gets exactly what it gets from
a JSON profile: read, dropped, and the rest of the preset loads.
The ordinal-keyed cereal hooks in `PrintConfig.hpp` are untouched — they are also the
undo/redo wire format, where the process cannot change underneath them. The cache has
its own serialization in `PresetCacheFormat.{hpp,cpp}`.
Three deliberate choices in the layout:
- **Stamps come first**, so the question "what version is this vendor installed at?"
can be answered by reading the first kilobyte. The updater asks that question for
every vendor on every launch; reading tens of megabytes to answer it would give back
the startup time the cache saved. The dictionary sits behind them, ahead of the
entries, so a reader that does go on resolves it once and then indexes.
- **Nothing inherited is baked in.** A filament preset that inherits from the shared
library is stored as its own diff plus its parent's name, and the parent is looked up
when the entry is installed, against whatever library is loaded then. A cache
therefore carries no other vendor's values, and no other vendor's update — the
library's included — can make it stale.
- **Nothing derived is stored.** Default presets, flattened configs, aliases and
lookup maps are all reconstructed at load by the same code the JSON path runs, and
state that path never fills (obsolete-preset lists) is not stored either. This keeps
the cache a record of the vendor's data, not a memory image of the program's state.
## When a cache may be used
A cache is accepted only if every gate below passes. Any failure means "parse the
JSONs instead" — never a hard error, never a partial load.
**1. Integrity.** Magic number, a declared body size that is exactly the rest of the
file, CRC32 over the payload. The size is checked against the file's real length before
anything is allocated on the strength of it, so an eight-byte field in an unauthenticated
file cannot ask for a gigabyte.
**2. Cache format version.** A single integer bumped by hand whenever the binary layout
changes in a way nothing else would catch: reordering or retyping a hand-written
serialized field, or changing what the cache's own stamps mean. Config-schema drift is
explicitly *not* such a change — the dictionary handles it — so this no longer moves
every release.
**3. Vendor identity and version.** The cache names the vendor it holds and the profile
version it was built from. It is accepted only if that version is at least as new as
the profile now on disk. Where no profile sits beside the cache — the shipped,
cache-only form — the comparison is skipped, because nothing on disk can be newer than
a cache that is the installation.
**4. Every entry installs.** Entries are installed as they are read, and an entry that
cannot be — typically one that inherits a parent the currently loaded filament library
no longer provides — rejects the whole cache, never just the entry. A partial vendor is
not a vendor.
There is deliberately no stamp for the shared filament library. A cache stores its
filaments' inheritance by name and resolves it at load, so a library update changes
what a cache load *produces*, never whether the cache is *valid* — the same file yields
the updated result. This matters most on a shipped build, where a vendor is its cache
and nothing else: a profile update that delivered only the library would otherwise have
stranded every other vendor with a cache it invalidated and no JSONs to fall back on.
A vendor profile with no parsable version is never cached and never served from a
cache. There would be no way to tell later whether the cache had gone stale, and a
cache nothing can invalidate is worse than no cache.
## How a vendor is loaded
Vendors load in a fixed order, because filament inheritance crosses exactly one
boundary: any vendor's filament may inherit from the shared Orca filament library,
and nothing else reaches across vendors. The library therefore goes first, alone;
every other vendor follows in parallel, resolving against it; and the results are
merged in a stable order:
```mermaid
flowchart LR
lib["1 · OrcaFilamentLibrary<br/>loaded first, synchronously"] --> par["2 · every other vendor in parallel,<br/>each into its own bundle, filaments<br/>resolving against the loaded library"] --> merge["3 · bundles merged into one,<br/>sequentially, in stable vendor order"]
```
Whether a vendor comes from its cache or from a parse changes nothing in that
order — both produce the same bundle, so cached and parsed vendors mix freely in
one startup.
**A vendor is loaded from where it is installed and nowhere else.** For startup that
is `<data_dir>/system/`; resources reaches the app by being *installed* into that
directory first, never by being loaded from. (The setup wizard is the one caller with
a different notion of "where": it also shows vendors the user has not installed, and
loads those from `resources/profiles` — see "The wizard's profile-data cache".) There
is one lookup tier and one parse source:
```
load vendor V from <data_dir>/system:
system/V.opc passes CACHE_VERSION + size + CRC + vendor name + version gate?
yes -> serve from it
no -> parse system/V.json, then write system/V.opc back
```
The same decision drawn out — "the gates" are the four acceptance checks above:
```mermaid
flowchart TB
start["load vendor V from a directory dir<br/>— normally &lt;data_dir&gt;/system/"]
start --> stamp["installed version = version of dir/V.json<br/>— or ∞ with no profile there,<br/>the cache then being the installation"]
stamp --> g1{"dir/V.opc<br/>passes all four gates?"}
g1 -- "yes" --> hit(["served from the<br/>installed cache"])
g1 -- "no" --> pd["parse the JSONs in dir"]
pd --> ver{"profile version<br/>parsable?"}
ver -- "yes" --> save(["loaded; dir/V.opc written back —<br/>the next load takes the top path"])
ver -- "no" --> raw(["loaded, never cached"])
```
A second tier into `resources/profiles/` used to sit between those two, and a parse
fallback to the same place behind them. Both existed only because an installed cache
died on every app upgrade, when the schema fingerprint rejected it; with the fingerprint
gone there is nothing for them to rescue. They also had a cost: on a developer tree the
shipped cache answered first, so the profile in `<data_dir>/system/` was never parsed
and its cache was never written back.
Serving from a cache is not a memory-image restore. The entries are deserialized and
then installed one by one — inheritance resolved against the presets installed before
them and the currently loaded filament library, configs flattened onto the collection
defaults, validated and registered — by the same function the JSON path calls straight
after parsing a sub-file. The two paths share everything below the parse, which is what
makes a cache-loaded bundle indistinguishable from a JSON-loaded one by construction
rather than by test coverage. Installation also rebuilds each preset's file path from
the local data directory, so a shipped cache never carries the generating machine's
paths.
App upgrades work because a cache normally survives one. Only a deliberate
`CACHE_VERSION` bump makes an installed cache unreadable, and that is handled at
install time rather than at load: a vendor whose cache this build cannot read counts
as **not installed**, so the updater lays down a working copy on the next launch (see
below). A vendor that still has its profile JSONs beside the cache is simply parsed
and re-cached.
If a parse does happen and the vendor's profile carries a version, the app writes the
cache back beside where it looked for the vendor. That is how a developer build warms
itself up on second launch, and how a vendor delivered by a profile update becomes
cached without waiting for the next release.
## The wizard's profile-data cache
The setup wizard's printer and filament pages want every vendor in one bundle — the
installed ones *and* the shipped ones the user has not installed yet, because the
wizard is where installing is chosen. Its set therefore spans two directories:
`<data_dir>/system/` for installed vendors (shadowing resources on a name collision),
`resources/profiles` for the rest, each vendor loaded from its own directory.
What the wizard actually consumes from that bundle is one derived JSON — the model /
machine / filament / process catalog its web pages render — and that JSON is a pure
function of the vendor set: each vendor's name and version, in load order. A profile
change requires a version bump, so name and version determine a vendor's content
wherever its copy sits; which directory served it is deliberately **not** stamped,
and installing or removing a copy at an unchanged version leaves the cache valid. So
the wizard caches the *derived JSON*, not another form of the inputs:
`<data_dir>/cache/wizard_profile_data.json` holds the stamp list and the catalog. On
open, the wizard computes the current stamps (one version peek per vendor) and, when
they match, serves the catalog from the file — no bundle built, no preset installed.
Caching bundle inputs instead was tried and measured: rebuilding the bundle from
per-vendor caches costs ~2 s of preset installation whatever feeds it, so only
skipping the rebuild entirely wins.
Any change to the set — a vendor added, removed or updated, or its cache-only
`.opc` replaced by a newer one — changes the stamps and retires the whole file;
the wizard then rebuilds the bundle vendor by vendor (per-vendor caches serving where
they cover) and writes the catalog back. Selections, region and per-open decorations
are applied downstream of the cache either way, so a served catalog is
indistinguishable from a rebuilt one. Nothing ships this file and the updater never
touches it; it is a locally written artifact, re-derived whenever stale, written
through a temp file and rename so half a cache is never readable.
The cache lives under `<data_dir>/cache/`, not beside the vendors: everything that
scans `<data_dir>/system/` treats any `.opc` there as a vendor, so a non-vendor
cache file must not sit in that directory. Relatedly, the stamp reader is hardened:
`read_cache_stamps` validates the cache version before reading anything
variable-length and bounds the stamp strings' lengths, so a reader pointed at a
foreign or damaged `.opc` rejects it cleanly instead of aborting on a garbage
64-bit allocation.
## How a vendor is installed
Installing copies from `resources/profiles/` into `<data_dir>/system/`. A shipped build
offers only a cache and a source tree only JSONs, but a partially-generated tree can
have both, at different versions, so the installer picks the form that ships at the
**newer version** and installs only that one:
- Cache newer or equal, and readable → copy the `.opc`, verify the *copy* is one this
build can read, and only then delete any profile and vendor directory a previous
install left behind, so nothing can shadow it.
- Profile newer, or the cache unreadable or absent → copy the profile and the vendor's
preset JSONs exactly as the app did before caches existed, and delete any stale `.opc`
once the profile is safely in place.
One vendor that cannot be installed is one vendor missing, not a reason to leave the
rest uninstalled: the installer skips it, records the failure, and carries on with the
batch. A vendor whose cache arrives unreadable falls back to installing its profile,
which is decided by reading the copy rather than by the kilobyte peek that chose the
form.
**"Installed" means present and usable.** Where the cache is the whole of a vendor's
installation, a `.opc` this build cannot read is not an installation — counted as one,
the vendor would be stranded with nothing to load and the updater would never repair
it. The installed version is likewise whichever form a load would actually serve: the
cache's stamp while it covers the profile beside it, the profile's own version once it
does not.
The result is that only one form of a vendor is ever present, and it is the newest one
the build has. This matters most for the update check, which compares what is installed
against what installing *would* lay down: if those two disagreed about which form
counts, a vendor could reinstall on every launch forever, or silently never update.
Profile updates delivered over the air always arrive as JSONs, and they win — an
updated vendor's real profile lands in the data directory, the installed cache beside it
is older and gets rejected, and the vendor is parsed and re-cached. An update that touches only
the filament library needs nothing more: every other vendor's cache stays valid and
simply resolves against the new library on its next load.
## How the caches are produced
Cache generation is a build step, not something a user ever runs.
One script per platform does the whole job, and CI calls it once on each. It builds a
small dev-utility that loads a profiles directory exactly as the app would, with cache
writing enabled, dropping a `<vendor>.opc` beside every vendor profile it parses; then
it copies those caches into each packaged application it was pointed at and deletes
every preset JSON they replace — the vendor's own profile included. Only a vendor that
actually has a cache is pruned, so a vendor the generator skipped keeps its JSONs and is
simply parsed at startup.
Caches are generated into the checkout's own `resources/profiles`, because that is what
cpack re-installs from when it builds the NSIS installer — so that directory is also a
prune target in CI. Pruning it deletes the checkout's preset JSONs, which is a packaging
step, not something a build should do to a working tree by surprise: the Windows script
refuses that target unless given `--prune-source`, and CI passes it.
Generation runs after the build, in the same job, so the caches ship with a build that
can read them.
The flatpak differs only in where the script is called from. Nothing outside
flatpak-builder ever builds it, so there is no packaged tree for the workflow to point
the script at afterwards: the manifest runs it as a build step instead, against the
profiles the install has already copied into `/app`.
## Behavior when things go wrong
The system is designed so that no cache problem is fatal:
- **Corrupt, truncated or foreign file** — rejected at the header, vendor parsed. A
cache is written to a temp file beside its target and moved into place, so a write
that dies partway leaves the previous cache intact rather than a truncated one.
- **An option this build no longer has, or now types differently** — that option alone
is dropped, exactly as a JSON profile's would be. The preset and the file load.
- **Cache from a build with a different cache layout** — rejected on `CACHE_VERSION`.
A vendor with JSONs beside it is parsed and re-cached; a cache-only vendor reads as
not installed and the updater reinstalls it.
- **Stale cache** — rejected on the vendor version stamp, vendor parsed and re-cached.
- **Failure part-way through loading** — a deserialization error, or any entry that
fails to install — rejects the whole cache, and the bundle is reset to a clean state
before falling back, so a half-loaded cache can never leak into the parsed result.
- **A vendor that can be neither read nor parsed** — logged, and left out. The setup
wizard drops that vendor from its list and opens with the rest; startup records the
error alongside the vendors that did load. One broken vendor never takes the app down.
The one genuine limit: on a shipped build a vendor is its cache and nothing else, so a
rejected cache has nothing to fall back to for that vendor. This is by design — the
alternative is shipping every preset twice — and it is why the acceptance gates are
conservative and why CI generates the caches with the same build that ships them. The
recovery path is a profile update, which delivers real JSONs.
It also means nothing may quietly assume a `<vendor>.json` exists. Discovery, version
checks and the update decision all read whichever form is present, and a code path that
enumerates only `*.json` will find no vendors at all in a packaged build.
## Maintenance rules
- **Adding, removing, retyping or reordering a config option** needs nothing. The
payload names its keys and its enum values, so an option a cache carries and this
build does not is dropped; one this build has and the cache does not is simply
absent, as it would be from a JSON that predates it.
- **Changing a hand-written `serialize()`** — `VendorProfile` or its nested types — or
the `CachedPreset` field list — written and read by `visit_entry` in
`PresetCacheFormat.cpp`, one list for the save, the load and the name peek alike — or
the cache's own layout or stamps, requires bumping `CACHE_VERSION` by hand.
- **The dictionary indexes with a `uint16`**, so `print_config_def` may hold at most
65535 options and one cache at most 65535 distinct enum value names.
`CacheDictionary::save` throws past that, which surfaces when CI generates the
caches rather than on a user's machine.
- **Bumping `CACHE_VERSION` is safe without a resources fallback** because
`is_vendor_installed` means *present and usable*: cache-only vendors read as not
installed after a bump, and the updater reinstalls them from resources.
- **Bumping a vendor profile's version** invalidates that vendor's cache and nothing
else — the filament library's included. Other vendors' caches resolve against the
new library the next time they load.
- **Caches are never committed.** They are build artifacts, generated per build,
ignored by git.
## Where this lives in the tree
| Area | Files |
|---|---|
| Everything about the bytes on disk — the dictionary, one config's wire format, the file framing and stamps, entry serialization, `VendorCacheFile` save/load/peeks | `src/libslic3r/PresetCacheFormat.{hpp,cpp}` |
| Serve-or-parse decision, installing cache entries into a bundle, cache write-back | `src/libslic3r/PresetBundle.{hpp,cpp}` |
| Vendor profile serialization | `src/libslic3r/Preset.hpp` |
| Vendor discovery, installed/shipped versions, installation | `src/libslic3r/utils.cpp` (declared in `Utils.hpp`) |
| Update and reinstall decisions | `src/slic3r/Utils/PresetUpdater.cpp` |
| Setup wizard and printer-selection dialog | `src/slic3r/GUI/ConfigWizard.cpp`, `src/slic3r/GUI/WebGuideDialog.cpp` |
| Generator tool | `src/dev-utils/generate_system_cache.cpp` |
| Build and packaging script | `scripts/build_preset_cache.{sh,bat}` |
| Tests | `tests/libslic3r/test_vendor_cache.cpp` |
+109 -35
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-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"
@@ -4452,6 +4452,20 @@ msgstr ""
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr ""
#, possible-c-format, possible-boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr ""
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr ""
#, possible-c-format, possible-boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr ""
msgid "Adjust"
msgstr ""
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4533,6 +4547,12 @@ msgid ""
"No - Disable Arachne Wall Generator and set [Displacement] mode of the Fuzzy Skin"
msgstr ""
msgid "Brim ear radius"
msgstr ""
msgid "Brim width"
msgstr ""
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 ""
@@ -4784,6 +4804,12 @@ msgstr ""
msgid "Calibration error"
msgstr ""
msgid "This printer is not configured with the hardware this control needs."
msgstr ""
msgid "This control is not supported on this printer."
msgstr ""
msgid "Network unavailable"
msgstr ""
@@ -5615,7 +5641,7 @@ msgstr ""
msgid "Size:"
msgstr ""
#, possible-c-format, possible-boost-format
#, possible-boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr ""
@@ -5790,6 +5816,9 @@ msgstr ""
msgid "Project"
msgstr ""
msgid "Device (Web)"
msgstr ""
msgid "Yes"
msgstr ""
@@ -7780,19 +7809,19 @@ msgstr ""
msgid "Replaced with 3D files from directory:\n"
msgstr ""
#, possible-boost-format
#, possible-c-format, possible-boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr ""
#, possible-boost-format
#, possible-c-format, possible-boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr ""
#, possible-boost-format
#, possible-c-format, possible-boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr ""
#, possible-boost-format
#, possible-c-format, possible-boost-format
msgid "✔ Replaced %s.\n"
msgstr ""
@@ -8472,6 +8501,15 @@ msgstr ""
msgid "Pop up to select filament grouping mode"
msgstr ""
msgid "Visible plugin pages"
msgstr ""
msgid "pages"
msgstr ""
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr ""
msgid "Behaviour"
msgstr ""
@@ -8797,6 +8835,14 @@ msgstr ""
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr ""
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr ""
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
msgid "Experimental Features"
msgstr ""
@@ -9052,9 +9098,21 @@ msgstr ""
msgid "Preset Inside Project"
msgstr ""
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr ""
msgid "Detach from parent"
msgstr ""
msgid "Unique preset"
msgstr ""
msgid "Parent preset"
msgstr ""
msgid "This preset does not inherit from another preset."
msgstr ""
msgid "Name is unavailable."
msgstr ""
@@ -9732,20 +9790,6 @@ msgstr ""
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 ""
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr ""
msgid "Adjust to the set range automatically?\n"
msgstr ""
msgid "Adjust"
msgstr ""
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 ""
@@ -9931,6 +9975,9 @@ msgstr ""
msgid "Setting Overrides"
msgstr ""
msgid "Retraction when switching material"
msgstr ""
msgid "Basic information"
msgstr ""
@@ -10057,6 +10104,12 @@ msgstr ""
msgid "Printable space"
msgstr ""
msgid "Printer Agent"
msgstr ""
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr ""
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, possible-boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10179,9 +10232,6 @@ msgstr ""
msgid "Z-Hop"
msgstr ""
msgid "Retraction when switching material"
msgstr ""
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
"\n"
@@ -11445,6 +11495,9 @@ msgstr ""
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr ""
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr ""
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."
msgstr ""
@@ -11740,9 +11793,6 @@ msgstr ""
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 ""
msgid "Printer Agent"
msgstr ""
msgid "Select the network agent implementation for printer communication."
msgstr ""
@@ -12279,9 +12329,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr ""
msgid "Brim width"
msgstr ""
msgid "This is the distance from the model to the outermost brim line."
msgstr ""
@@ -12347,6 +12394,12 @@ msgid ""
"0 to deactivate."
msgstr ""
msgid "Brim ears outer only"
msgstr ""
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr ""
msgid "upward compatible machine"
msgstr ""
@@ -13359,6 +13412,12 @@ msgstr ""
msgid "Gyroid"
msgstr ""
msgid "Sparse infill smooth factor"
msgstr ""
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr ""
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr ""
@@ -13839,6 +13898,12 @@ msgstr ""
msgid "Klipper"
msgstr ""
msgid "Skip G-code config block"
msgstr ""
msgid "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."
msgstr ""
msgid "Pellet Modded Printer"
msgstr ""
@@ -14800,6 +14865,12 @@ msgstr ""
msgid "Retraction distance when extruder change"
msgstr ""
msgid "Retraction Length (Toolchange)"
msgstr ""
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 ""
msgid "Z-hop height"
msgstr ""
@@ -14893,6 +14964,9 @@ msgstr ""
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 ""
msgid "Extra length on restart (Toolchange)"
msgstr ""
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr ""
@@ -15278,6 +15352,12 @@ msgstr ""
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 ""
msgid "Wait for temperature on wipe tower"
msgstr ""
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 ""
msgid "No sparse layers (beta)"
msgstr ""
@@ -18253,9 +18333,6 @@ msgstr ""
msgid "Print Host upload"
msgstr ""
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr ""
msgid "Select a Flashforge printer"
msgstr ""
@@ -19087,9 +19164,6 @@ msgstr ""
msgid "User canceled."
msgstr ""
msgid "Head diameter"
msgstr ""
msgid "Max angle"
msgstr ""
+155 -37
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: 2025-03-15 10:55+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
@@ -4828,6 +4828,23 @@ msgstr "La temperatura actual de la cambra és superior a la temperatura segura
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "La temperatura mínima de la cambra (%d℃) és superior a la temperatura objectiu de la cambra (%d℃). El valor mínim és el llindar a partir del qual comença la impressió mentre la cambra continua escalfant-se cap a l'objectiu, de manera que no l'hauria de superar. Es limitarà al valor objectiu."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "L'alçada de capa és massa petita. S'establirà al mínim (%g mm)."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "L'alçada de capa està fora dels límits establerts a Configuració de la Impressora -> Extrusora -> Límits d'alçada de la capa, això pot causar problemes de qualitat d'impressió."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "Voleu ajustar-la automàticament al límit (%g mm)?"
msgid "Adjust"
msgstr "Ajustar"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4948,6 +4965,13 @@ msgstr ""
"Sí - Activa el generador de parets Arachne\n"
"No - Desactiva el generador de parets Arachne i estableix el mode [Desplaçament] de la pell difusa"
# AI Translated
msgid "Brim ear radius"
msgstr "Radi de l'orella de la Vora d'Adherència"
msgid "Brim width"
msgstr "Ample de la Vora d'Adherència"
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 "El mode espiral només funciona quan els bucles de paret són 1, el suport està desactivat, la detecció d'acumulació per sondeig està desactivada, les capes de la coberta superior són 0, la densitat de farciment dispers és 0 i el tipus de timelapse és tradicional."
@@ -5202,6 +5226,14 @@ msgstr "No s'ha pogut generar el gcode cali"
msgid "Calibration error"
msgstr "Error de calibratge"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "Aquesta impressora no està configurada amb el maquinari que necessita aquest control."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Aquest control no és compatible amb aquesta impressora."
# AI Translated
msgid "Network unavailable"
msgstr "Xarxa no disponible"
@@ -6067,7 +6099,7 @@ msgstr "Volum:"
msgid "Size:"
msgstr "Mida:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "S'han trobat conflictes de rutes gcode a la capa %d, Z = %.2lfmm. Si us plau, separeu els objectes conflictius més lluny ( %s <-> %s )."
@@ -6248,6 +6280,10 @@ msgstr "Multidispositiu"
msgid "Project"
msgstr "Projecte"
# AI Translated
msgid "Device (Web)"
msgstr "Dispositiu (Web)"
msgid "Yes"
msgstr "Sí"
@@ -8361,19 +8397,19 @@ 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"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ Omès %s: mateix fitxer.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ Omès %s: el fitxer no existeix.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ Omès %s: la substitució ha fallat.\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ Substituït %s.\n"
@@ -9116,6 +9152,18 @@ msgstr "Amb aquesta opció habilitada, podeu enviar una tasca a diversos disposi
msgid "Pop up to select filament grouping mode"
msgstr "Finestra emergent per seleccionar el mode d'agrupació de filaments"
# AI Translated
msgid "Visible plugin pages"
msgstr "Pàgines de connectors visibles"
# AI Translated
msgid "pages"
msgstr "pàgines"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "Nombre de pàgines de connectors que es mostren com a pestanyes fixes abans que la resta de pàgines es replegui en un desplegable a l'última pestanya."
msgid "Behaviour"
msgstr "Comportament"
@@ -9506,6 +9554,18 @@ msgstr "Mostrar els perfils no compatibles"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "Mostra els perfils incompatibles o no compatibles a les llistes desplegables d'impressora i de filament. Aquests perfils no es poden seleccionar."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Experimental) Utilitza agents d'impressora en lloc d'amfitrions d'impressió"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Envia els treballs d'impressió de les impressores que no són Bambu a través dels agents de connector d'impressora en lloc del flux clàssic de pujada a l'amfitrió d'impressió.\n"
"Quan està desactivat, OrcaSlicer utilitza el comportament antic de l'amfitrió d'impressió."
# AI Translated
msgid "Experimental Features"
msgstr "Funcions experimentals"
@@ -9776,9 +9836,25 @@ msgstr "Perfil d'usuari"
msgid "Preset Inside Project"
msgstr "Perfil intern del Projecte"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Copia en aquest perfil tots els valors heretats del perfil pare i elimina la relació d'herència. Els perfils compatibles només amb el perfil pare poden deixar de ser compatibles."
msgid "Detach from parent"
msgstr "Desvincula del pare"
# AI Translated
msgid "Unique preset"
msgstr "Perfil únic"
# AI Translated
msgid "Parent preset"
msgstr "Perfil pare"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Aquest perfil no hereta de cap altre perfil."
msgid "Name is unavailable."
msgstr "El nom no està disponible."
@@ -10521,22 +10597,6 @@ msgstr "Estàs segur que vols activar aquesta opció?"
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 "Els patrons de farciment estan dissenyats normalment per gestionar la rotació automàticament per garantir una impressió correcta i aconseguir els efectes desitjats (p. ex., Gyroid, Cúbic). Rotar el patró de farciment dispers actual pot portar a un suport insuficient. Procediu amb precaució i comproveu minuciosament qualsevol problema d'impressió potencial. Esteu segur que voleu activar aquesta opció?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"L'alçada de la capa és massa petita.\n"
"Es posarà a min_layer_height\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "L'alçada de la capa supera el límit a Configuració de la Impressora -> Extrusora -> Límits d'alçada de la capa, això pot causar problemes de qualitat d'impressió."
msgid "Adjust to the set range automatically?\n"
msgstr "Voleu ajustar el rang automàticament?\n"
msgid "Adjust"
msgstr "Ajustar"
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 "Característica experimental: Retreure i tallar el filament a major distància durant els canvis de filaments per minimitzar el flux. Tot i que pot reduir notablement el flux, també pot elevar el risc d'esclops de broquets o altres complicacions d'impressió."
@@ -10735,6 +10795,9 @@ msgstr "Trobades paraules clau reservades"
msgid "Setting Overrides"
msgstr "Anul·lacions de configuració"
msgid "Retraction when switching material"
msgstr "Retracció en canviar de material"
msgid "Basic information"
msgstr "Informació bàsica"
@@ -10867,6 +10930,12 @@ msgstr "Perfils de processos compatibles"
msgid "Printable space"
msgstr "Espai imprimible"
msgid "Printer Agent"
msgstr "Agent de la impressora"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Seleccioneu la implementació de l'agent de xarxa per a la comunicació amb la impressora. Els agents disponibles es registren a l'inici."
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10997,9 +11066,6 @@ msgstr "Límits d'alçada de capa"
msgid "Z-Hop"
msgstr "Z-Hop"
msgid "Retraction when switching material"
msgstr "Retracció en canviar de material"
# AI Translated
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
@@ -12380,6 +12446,10 @@ msgstr " està massa a prop de la zona d'exclusió, i es provocaran col·lisions
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " és massa a prop de l'àrea de detecció d'acumulació i es causaran col·lisions.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " està parcialment fora de l'àrea imprimible, i no es pot imprimir.\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."
msgstr "Les temperatures de broquet seleccionades són incompatibles. La temperatura de broquet de cada filament ha d'estar dins del rang de temperatura de broquet recomanat dels altres filaments. Altrament, es pot produir una obturació del broquet o danys a la impressora."
@@ -12714,9 +12784,6 @@ msgstr "Utilitzar 3MF en lloc de G-code"
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 "Activeu-ho si la impressora accepta un fitxer 3MF com a treball d'impressió. Quan està activat, Orca Slicer envia el fitxer laminat com a .gcode.3mf, en lloc d'un fitxer .gcode simple."
msgid "Printer Agent"
msgstr "Agent de la impressora"
msgid "Select the network agent implementation for printer communication."
msgstr "Seleccioneu la implementació de l'agent de xarxa per a la comunicació amb la impressora."
@@ -13402,9 +13469,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "Velocitat dels ponts interns. Si el valor s'expressa com un percentatge, es calcularà en funció de la velocitat del pont (bridge_speed). El valor per defecte és del 150%."
msgid "Brim width"
msgstr "Ample de la Vora d'Adherència"
msgid "This is the distance from the model to the outermost brim line."
msgstr "Distància del model a la línia de la Vora d'Adherència més exterior"
@@ -13488,6 +13552,14 @@ msgstr ""
"La geometria es simplificarà abans de detectar angles pronunciats. Aquest paràmetre indica la longitud mínima de la desviació per a la simplificació.\n"
"0 per desactivar"
# AI Translated
msgid "Brim ears outer only"
msgstr "Orelles de la Vora d'Adherència només a l'exterior"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Genera orelles de ratolí només al contorn exterior del model, excloent-ne els forats i les seccions tancades."
msgid "upward compatible machine"
msgstr "màquina compatible ascendent"
@@ -14679,6 +14751,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "Giroide"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Factor de suavitzat del farciment poc dens"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Controla com s'arrodoneixen les cantonades del farciment poc dens. 0% manté el traçat original amb cantonades vives, mentre que 100% produeix les corbes més amples possibles entre línies de farciment adjacents."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "Acceleració del farciment superficial superior. L'ús d'un valor inferior pot millorar la qualitat de la superfície superior"
@@ -15232,6 +15312,14 @@ msgstr "Amb quin tipus de Codi-G és compatible la impressora."
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "Omet el bloc de configuració del G-code"
# AI Translated
msgid "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."
msgstr "No escriu el CONFIG_BLOCK (els parells clau/valor de la configuració del laminador) al fitxer G-code. Això pot ajudar amb impressores el microprogramari de les quals falla en analitzar aquestes línies de comentari (p. ex. Anycubic go-klipper). Nota: el fitxer G-code ja no contindrà la configuració del laminador, de manera que en tornar-lo a importar a OrcaSlicer no es restaurarà la configuració."
msgid "Pellet Modded Printer"
msgstr "Impressora modificada de pellets"
@@ -16321,6 +16409,14 @@ msgstr "Retracció llarga al canviar d'extrusor"
msgid "Retraction distance when extruder change"
msgstr "Distància de retracció al canviar d'extrusor"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "Longitud de retracció (Canvi d'eina)"
# 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 "Quan s'activa la retracció abans d'un canvi d'eina, el filament es retira la quantitat especificada (la longitud es mesura sobre el filament en brut, abans d'entrar a l'extrusor)."
msgid "Z-hop height"
msgstr "Alçada Z-hop"
@@ -16419,6 +16515,10 @@ msgstr "Longitud addicional en reiniciar"
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 "Quan la retracció es compensa després d'un desplaçament, l'extrusor introduirà una quantitat addicional de filament. Aquest ajustament rarament es necessita."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "Longitud addicional en reiniciar (Canvi d'eina)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "Quan la retracció es compensa després d'un canvi d'eina, l'extrusor introduirà una quantitat addicional de filament."
@@ -16835,6 +16935,14 @@ msgstr "Canvi d'eina a la 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 el capçal a desplaçar-se a la Torre de Purga abans d'emetre l'ordre de canvi d'eina (Tx). Només és rellevant per a impressores multiextrusor (multicapçal) que utilitzen una Torre de Purga de tipus 2. Per defecte, Orca omet aquest desplaçament en màquines multicapçal perquè el firmware gestiona el canvi de capçal, cosa que pot fer que l'ordre Tx s'emeti sobre la peça impresa. Activeu aquesta opció si voleu que el canvi d'eina s'emeti sempre sobre la Torre de Purga."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "Espera la temperatura a la 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 "Recull la nova eina sense esperar que arribi a la temperatura d'impressió, es desplaça a la Torre de Purga i hi espera la temperatura, just abans de purgar. El degoteig de l'escalfament cau sobre la torre en lloc del model, i el desplaçament se solapa amb l'escalfament. Només és rellevant per a impressores multiextrusor (multicapçal) que utilitzen una Torre de Purga de tipus 2. El microprogramari o la macro de canvi d'eina no han d'esperar la temperatura pel seu compte. Quan està desactivat, l'espera de temperatura s'emet just després de l'ordre de canvi d'eina."
msgid "No sparse layers (beta)"
msgstr "Sense capes poc denses( beta )"
@@ -20121,9 +20229,6 @@ msgstr "Impressora Física"
msgid "Print Host upload"
msgstr "Pujada al amfitrió( host ) d'impressió"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Seleccioneu la implementació de l'agent de xarxa per a la comunicació amb la impressora. Els agents disponibles es registren a l'inici."
# AI Translated
msgid "Select a Flashforge printer"
msgstr "Seleccioneu una impressora Flashforge"
@@ -21066,9 +21171,6 @@ msgstr "Alguna cosa inesperada ha passat en intentar iniciar sessió, torneu-ho
msgid "User canceled."
msgstr "Usuari cancel·lat."
msgid "Head diameter"
msgstr "Diàmetre del cap"
msgid "Max angle"
msgstr "Angle màxim"
@@ -21887,6 +21989,22 @@ 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 ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "L'alçada de la capa és massa petita.\n"
#~ "Es posarà a min_layer_height\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "L'alçada de la capa supera el límit a Configuració de la Impressora -> Extrusora -> Límits d'alçada de la capa, això pot causar problemes de qualitat d'impressió."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "Voleu ajustar el rang automàticament?\n"
#~ msgid "Head diameter"
#~ msgstr "Diàmetre del cap"
#~ msgid "Print order within a single layer."
#~ msgstr "Ordre d'impressió dins d'una sola capa"
+156 -38
View File
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: Jakub Hencl\n"
"Language-Team: \n"
@@ -4786,6 +4786,23 @@ msgstr "Aktuální teplota komory je vyšší než bezpečná teplota materiálu
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "Minimální teplota komory (%d℃) je vyšší než cílová teplota komory (%d℃). Minimální hodnota je práh, při kterém tisk začíná, zatímco se komora dále ohřívá k cílové teplotě, takže by ji neměla překročit. Bude omezena na cílovou hodnotu."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "Výška vrstvy je příliš malá. Bude nastavena na minimum (%g mm)."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Výška vrstvy je mimo limity nastavené v Nastavení tiskárny -> Extruder -> Omezení výšky vrstvy, což může způsobit problémy s kvalitou tisku."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "Upravit ji automaticky na limit (%g mm)?"
msgid "Adjust"
msgstr "Upravit"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4906,6 +4923,13 @@ msgstr ""
"Ano povolit Arachne Wall Generator\n"
"Ne zakázat Arachne Wall Generator a nastavit režim [Displacement] pro Fuzzy Skin"
# AI Translated
msgid "Brim ear radius"
msgstr "Poloměr ouška límce"
msgid "Brim width"
msgstr "Šířka límce"
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 "Spirálový režim funguje pouze tehdy, když je počet smyček stěny 1, podpěry jsou vypnuté, detekce usazenin sondováním je vypnutá, počet horních plných vrstev je 0, hustota řídké výplně je 0 a typ časosběru je tradiční."
@@ -5160,6 +5184,14 @@ msgstr "Nepodařilo se vygenerovat kalibrační G-code."
msgid "Calibration error"
msgstr "Chyba kalibrace"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "Tato tiskárna nemá nakonfigurovaný hardware, který tento ovládací prvek vyžaduje."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Tento ovládací prvek není na této tiskárně podporován."
# AI Translated
msgid "Network unavailable"
msgstr "Síť není dostupná"
@@ -6029,7 +6061,7 @@ msgstr "Objem:"
msgid "Size:"
msgstr "Velikost:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "Byly nalezeny konflikty drah G-kódu ve vrstvě %d, Z = %.2lf mm. Oddělte prosím konfliktní objekty více od sebe (%s <-> %s)."
@@ -6210,6 +6242,10 @@ msgstr "Více zařízení"
msgid "Project"
msgstr "Projekt"
# AI Translated
msgid "Device (Web)"
msgstr "Zařízení (Web)"
msgid "Yes"
msgstr "Ano"
@@ -8320,19 +8356,19 @@ msgstr "Nebyla vybrána složka pro nahrazení"
msgid "Replaced with 3D files from directory:\n"
msgstr "Nahrazeno 3D soubory ze složky:\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ Přeskočeno %s: stejný soubor.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ Přeskočeno %s: soubor neexistuje.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ Přeskočeno %s: nahrazení se nezdařilo.\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ Nahrazeno %s.\n"
@@ -9070,6 +9106,18 @@ msgstr "Pokud je tato volba povolena, můžete odeslat úlohu na více zařízen
msgid "Pop up to select filament grouping mode"
msgstr "Zobrazit dialog pro výběr režimu seskupení filamentů"
# AI Translated
msgid "Visible plugin pages"
msgstr "Viditelné stránky pluginů"
# AI Translated
msgid "pages"
msgstr "stránek"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "Počet stránek pluginů zobrazených jako pevné karty, než se zbývající stránky sbalí do rozbalovací nabídky na poslední kartě."
msgid "Behaviour"
msgstr "Chování"
@@ -9457,6 +9505,18 @@ msgstr "Zobrazit nepodporované předvolby"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "Zobrazovat nekompatibilní/nepodporované předvolby v rozevíracích seznamech tiskáren a filamentů. Tyto předvolby nelze vybrat."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Experimentální) Používat agenty tiskárny místo tiskových hostů"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Směruje tiskové úlohy pro tiskárny jiné než Bambu přes agenty pluginů tiskárny místo klasického nahrávání na tiskový host.\n"
"Pokud je vypnuto, OrcaSlicer používá původní chování tiskového hosta."
# AI Translated
msgid "Experimental Features"
msgstr "Experimentální funkce"
@@ -9724,10 +9784,26 @@ msgstr "Uživatelská předvolba"
msgid "Preset Inside Project"
msgstr "Předvolba v projektu"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Zkopíruje do této předvolby všechny hodnoty zděděné z nadřazené předvolby a odstraní vztah dědičnosti. Předvolby kompatibilní pouze s nadřazenou předvolbou mohou přestat být podporovány."
# AI Translated
msgid "Detach from parent"
msgstr "Oddělit od nadřazeného"
# AI Translated
msgid "Unique preset"
msgstr "Samostatná předvolba"
# AI Translated
msgid "Parent preset"
msgstr "Nadřazená předvolba"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Tato předvolba nedědí z jiné předvolby."
msgid "Name is unavailable."
msgstr "Název není k dispozici."
@@ -10469,22 +10545,6 @@ msgstr "Opravdu chcete tuto možnost povolit?"
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 "Vzory výplně jsou obvykle navrženy tak, aby automaticky pracovaly s rotací a zajistily správný tisk i zamýšlený efekt (např. Gyroid, Cubic). Otočení aktuální řídké výplně může vést k nedostatečné opoře. Postupujte opatrně a pečlivě zkontrolujte možné problémy při tisku. Opravdu chcete tuto možnost povolit?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"Výška vrstvy je příliš malá.\n"
"Bude nastavena na min_layer_height\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Výška vrstvy přesahuje limit v Nastavení tiskárny -> Extruder -> Omezení výšky vrstvy, což může způsobit problémy s kvalitou tisku."
msgid "Adjust to the set range automatically?\n"
msgstr "Automaticky upravit do nastaveného rozsahu?\n"
msgid "Adjust"
msgstr "Upravit"
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 "Experimentální funkce: Stažení a odstřižení filamentu na větší vzdálenost během výměny filamentu pro minimalizaci purge. Ačkoliv to může výrazně snížit purge, může to také zvýšit riziko ucpání trysky nebo jiných komplikací při tisku."
@@ -10684,6 +10744,9 @@ msgstr "Byla nalezena rezervovaná klíčová slova"
msgid "Setting Overrides"
msgstr "Přepisování nastavení"
msgid "Retraction when switching material"
msgstr "Retrakce při změně materiálu"
msgid "Basic information"
msgstr "Základní informace"
@@ -10816,6 +10879,13 @@ msgstr "Kompatibilní procesní profily"
msgid "Printable space"
msgstr "Tisknutelný prostor"
# AI Translated
msgid "Printer Agent"
msgstr "Agent tiskárny"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Vyberte implementaci síťového agenta pro komunikaci s tiskárnou. Dostupní agenti jsou registrováni při spuštění."
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10943,9 +11013,6 @@ msgstr "Omezení výšky vrstvy"
msgid "Z-Hop"
msgstr "Z-Hop"
msgid "Retraction when switching material"
msgstr "Retrakce při změně materiálu"
# AI Translated
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
@@ -12363,6 +12430,10 @@ msgstr " je příliš blízko oblasti vyloučení a může způsobit kolize.\n"
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " je příliš blízko oblasti detekce shlukování a dojde ke kolizi.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " je částečně mimo tisknutelnou oblast a nelze jej vytisknout.\n"
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."
msgstr "Vybrané teploty trysky nejsou kompatibilní. Teplota trysky každého filamentu musí spadat do doporučeného rozsahu teplot ostatních filamentů. Jinak může dojít k ucpání trysky nebo poškození tiskárny."
@@ -12696,10 +12767,6 @@ msgstr "Použít 3MF místo G-code"
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 "Zapněte, pokud tiskárna přijímá jako tiskovou úlohu soubor 3MF. Je-li zapnuto, odešle Orca Slicer slicovaný soubor jako .gcode.3mf místo prostého souboru .gcode."
# AI Translated
msgid "Printer Agent"
msgstr "Agent tiskárny"
# AI Translated
msgid "Select the network agent implementation for printer communication."
msgstr "Vyberte implementaci síťového agenta pro komunikaci s tiskárnou."
@@ -13387,9 +13454,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "Rychlost vnitřních mostů. Pokud je hodnota zadána v procentech, vypočítá se podle bridge_speed. Výchozí hodnota je 150 %."
msgid "Brim width"
msgstr "Šířka límce"
msgid "This is the distance from the model to the outermost brim line."
msgstr "Vzdálenost od modelu k nejvzdálenější brim linii."
@@ -13470,6 +13534,14 @@ msgstr ""
"Geometrie bude decimována před detekcí ostrých úhlů. Tento parametr určuje minimální délku odchylky pro decimaci.\n"
"0 pro deaktivaci."
# AI Translated
msgid "Brim ears outer only"
msgstr "Ouška límce pouze na vnějším obrysu"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Vytvoří myší ouška pouze na vnějším obrysu modelu, bez otvorů a uzavřených částí."
msgid "upward compatible machine"
msgstr "stroj zpětně kompatibilní"
@@ -14646,6 +14718,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "Gyroid"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Faktor vyhlazení řídké výplně"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Určuje, jak silně se zaoblují rohy řídké výplně. 0% zachová původní ostrou dráhu, zatímco 100% vytvoří největší možné křivky mezi sousedními liniemi výplně."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "Akcelerace výplně horní plochy. Použití nižší hodnoty může zlepšit kvalitu horní plochy."
@@ -15198,6 +15278,14 @@ msgstr "Jaký typ G-code je s tiskárnou kompatibilní."
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "Vynechat konfigurační blok G-code"
# AI Translated
msgid "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."
msgstr "Nezapisuje CONFIG_BLOCK (dvojice klíč/hodnota s konfigurací sliceru) do souboru G-code. Může to pomoci u tiskáren, jejichž firmware při zpracování těchto řádků s komentáři havaruje (např. Anycubic go-klipper). Poznámka: soubor G-code již nebude obsahovat nastavení sliceru, takže jeho opětovný import do OrcaSlicer konfiguraci neobnoví."
msgid "Pellet Modded Printer"
msgstr "Tiskárna na pelety"
@@ -16265,6 +16353,14 @@ msgstr "Dlouhá retrakce při změně extruderu"
msgid "Retraction distance when extruder change"
msgstr "Délka retrakce při změně extruderu"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "Délka retrakce (Změna nástroje)"
# 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 "Když je retrakce spuštěna před změnou nástroje, filament se zatáhne o zadanou hodnotu (délka se měří na nezpracovaném filamentu, než vstoupí do extruderu)."
msgid "Z-hop height"
msgstr "Výška Z-hopu"
@@ -16362,6 +16458,10 @@ msgstr "Dodatečná délka při restartu"
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 "Při kompenzaci retrakce po pohybu přesunu extruder posune toto přídavné množství filamentu. Toto nastavení je potřeba jen zřídka."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "Dodatečná délka při restartu (Změna nástroje)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "Při kompenzaci retrakce po výměně nástroje extruder posune toto přídavné množství filamentu."
@@ -16780,6 +16880,14 @@ msgstr "Výměna nástroje na věži na očištění trysky"
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 "Vynutí přejezd tiskové hlavy k věži na očištění trysky před vydáním příkazu k výměně nástroje (Tx). Týká se pouze tiskáren s více extrudery (více tiskovými hlavami), které používají věž na očištění trysky typu 2. Ve výchozím nastavení Orca na strojích s více tiskovými hlavami tento přejezd vynechává, protože výměnu hlavy řeší firmware, což může vést k vydání příkazu Tx nad tištěným dílem. Zapněte tuto volbu, chcete-li, aby byla výměna nástroje vždy vydána nad věží na očištění trysky."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "Čekat na teplotu na věži na očištění trysky"
# 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 "Vyzvedne nový nástroj, aniž by čekal na dosažení tiskové teploty, přejede na věž na očištění trysky a počká na teplotu tam, těsně před čištěním. Materiál vytékající při ohřevu skončí na věži místo na modelu a přejezd se překrývá s ohřevem. Relevantní pouze pro tiskárny s více extrudery (více tiskovými hlavami) používající věž na očištění trysky typu 2. Firmware ani makro pro změnu nástroje nesmí na teplotu čekat samo. Pokud je vypnuto, čekání na teplotu se vloží hned po příkazu ke změně nástroje."
msgid "No sparse layers (beta)"
msgstr "Žádné řídké vrstvy (beta)"
@@ -20043,9 +20151,6 @@ msgstr "Fyzická tiskárna"
msgid "Print Host upload"
msgstr "Nahrání na tiskový server"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Vyberte implementaci síťového agenta pro komunikaci s tiskárnou. Dostupní agenti jsou registrováni při spuštění."
# AI Translated
msgid "Select a Flashforge printer"
msgstr "Vyberte tiskárnu Flashforge"
@@ -21002,9 +21107,6 @@ msgstr "Při pokusu o přihlášení došlo k neočekávané chybě, zkuste to p
msgid "User canceled."
msgstr "Zrušeno uživatelem."
msgid "Head diameter"
msgstr "Průměr hlavy"
msgid "Max angle"
msgstr "Maximální úhel"
@@ -21873,6 +21975,22 @@ 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 ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "Výška vrstvy je příliš malá.\n"
#~ "Bude nastavena na min_layer_height\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "Výška vrstvy přesahuje limit v Nastavení tiskárny -> Extruder -> Omezení výšky vrstvy, což může způsobit problémy s kvalitou tisku."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "Automaticky upravit do nastaveného rozsahu?\n"
#~ msgid "Head diameter"
#~ msgstr "Průměr hlavy"
#~ msgid "Print order within a single layer."
#~ msgstr "Pořadí tisku v rámci jedné vrstvy."
+155 -37
View File
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: Heiko Liebscher <hliebschergmail.com>\n"
"Language-Team: \n"
@@ -4692,6 +4692,23 @@ msgstr "Die aktuelle Kammer-Temperatur ist höher als die sichere Temperatur des
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "Die minimale Druckraumtemperatur (%d℃) ist höher als die Ziel-Druckraumtemperatur (%d℃). Der Minimalwert ist der Schwellenwert, bei dem der Druck beginnt, während der Druckraum weiter auf die Zieltemperatur heizt; er sollte diese daher nicht überschreiten. Er wird auf die Zieltemperatur begrenzt."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "Die Schichthöhe ist zu klein. Sie wird auf den Mindestwert (%g mm) gesetzt."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Die Schichthöhe liegt außerhalb der in Druckereinstellungen -> Extruder -> Schichthöhenlimits festgelegten Grenzen. Dies kann zu Problemen mit der Druckqualität führen."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "Automatisch an den Grenzwert (%g mm) anpassen?"
msgid "Adjust"
msgstr "Anpassen"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4812,6 +4829,13 @@ msgstr ""
"Ja - Arachne Wall Generator aktivieren\n"
"Nein - Arachne Wall Generator deaktivieren und den Modus [Verschiebung] des Fuzzy Skin setzen"
# AI Translated
msgid "Brim ear radius"
msgstr "Radius der Brim-Ohren"
msgid "Brim width"
msgstr "Randbreite"
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 "Der Spiralmodus funktioniert nur, wenn die Wandschleifen 1 sind, die Stütze deaktiviert ist, die Klumpenerkennung durch Abtasten deaktiviert ist, die oberen Schichtlagen 0 sind, die Dichte der spärlichen Füllung 0 ist und der Zeitraffertyp traditionell ist."
@@ -5066,6 +5090,14 @@ msgstr "Fehler beim Generieren des Kalibrierungs-G-Codes"
msgid "Calibration error"
msgstr "Kalibrierungsfehler"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "Dieser Drucker ist nicht mit der Hardware ausgestattet, die dieses Bedienelement benötigt."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Dieses Bedienelement wird von diesem Drucker nicht unterstützt."
# AI Translated
msgid "Network unavailable"
msgstr "Netzwerk nicht verfügbar"
@@ -5923,7 +5955,7 @@ msgstr "Volumen:"
msgid "Size:"
msgstr "Größe:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "Konflikte von G-Code-Pfaden wurden bei Layer %d, Z = %.2lf mm gefunden.Bitte trennen Sie die konfliktbehafteten Objekte weiter voneinander (%s <-> %s)."
@@ -6103,6 +6135,10 @@ msgstr "Multi-Gerät"
msgid "Project"
msgstr "Projekt"
# AI Translated
msgid "Device (Web)"
msgstr "Gerät (Web)"
msgid "Yes"
msgstr "Ja"
@@ -8191,19 +8227,19 @@ 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"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ Übersprungen %s: gleiche Datei.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ Übersprungen %s: Datei existiert nicht.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ Übersprungen %s: Ersetzen fehlgeschlagen.\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ Ersetzt %s.\n"
@@ -8941,6 +8977,18 @@ msgstr "Wenn diese Option aktiviert ist, können Sie eine Aufgabe gleichzeitig a
msgid "Pop up to select filament grouping mode"
msgstr "Popup zum Auswählen des Filament-Gruppierungsmodus"
# AI Translated
msgid "Visible plugin pages"
msgstr "Sichtbare Plugin-Seiten"
# AI Translated
msgid "pages"
msgstr "Seiten"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "Anzahl der Plugin-Seiten, die als feste Tabs angezeigt werden, bevor die übrigen Seiten im letzten Tab zu einem Dropdown zusammengefasst werden."
msgid "Behaviour"
msgstr "Verhalten"
@@ -9296,6 +9344,18 @@ msgstr "Nicht unterstützte Profile anzeigen"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "Zeigt inkompatible/nicht unterstützte Profile in den Dropdown-Listen für Drucker und Filament an. Diese Profile können nicht ausgewählt werden."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Experimentell) Drucker-Agenten anstelle von Druck-Hosts verwenden"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Leitet Druckaufträge für Nicht-Bambu-Drucker über Drucker-Plugin-Agenten statt über den klassischen Druck-Host-Upload.\n"
"Wenn deaktiviert, verwendet OrcaSlicer das bisherige Druck-Host-Verhalten."
msgid "Experimental Features"
msgstr "Experimentelle Funktionen"
@@ -9558,9 +9618,25 @@ msgstr "Benutzerprofil"
msgid "Preset Inside Project"
msgstr "Projektbasiertes Profil"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Kopiert alle vom übergeordneten Profil geerbten Werte in dieses Profil und entfernt die Vererbungsbeziehung. Profile, die nur mit dem übergeordneten Profil kompatibel sind, können dadurch nicht mehr unterstützt werden."
msgid "Detach from parent"
msgstr "Vom übergeordneten Element trennen"
# AI Translated
msgid "Unique preset"
msgstr "Eigenständiges Profil"
# AI Translated
msgid "Parent preset"
msgstr "Übergeordnetes Profil"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Dieses Profil erbt nicht von einem anderen Profil."
msgid "Name is unavailable."
msgstr "Der Name ist nicht verfügbar."
@@ -10296,22 +10372,6 @@ msgstr "Sind Sie sicher, dass Sie diese Option aktivieren möchten?"
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 "Infill-Muster sind in der Regel so konzipiert, dass sie eine automatische Drehung ermöglichen, um einen ordnungsgemäßen Druck zu gewährleisten und die beabsichtigten Effekte zu erzielen (z. B. Gyroid, Cubic). Das Drehen des aktuellen spärlichen Infill-Musters kann zu unzureichender Unterstützung führen. Bitte gehen Sie vorsichtig vor und überprüfen Sie gründlich auf mögliche Druckprobleme. Sind Sie sicher, dass Sie diese Option aktivieren möchten?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"Die Schichthöhe ist zu klein.\n"
"Sie wird auf min_layer_height gesetzt\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Die Schichthöhe überschreitet das Limit in Druckereinstellungen -> Extruder -> Schichthöhenlimits. Dies kann zu Problemen mit der Druckqualität führen."
msgid "Adjust to the set range automatically?\n"
msgstr "Automatisch an den eingestellten Bereich anpassen?\n"
msgid "Adjust"
msgstr "Anpassen"
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 "Experimentelle Funktion: Filament beim Filamentwechsel weiter zurückziehen und abschneiden, um den Flush zu minimieren. Obwohl dies den Flush deutlich reduzieren kann, kann es auch das Risiko von Düsenverstopfungen oder anderen Druckkomplikationen erhöhen."
@@ -10505,6 +10565,9 @@ msgstr "Reservierte Schlüsselwörter gefunden"
msgid "Setting Overrides"
msgstr "Überschreiben der Einstellungen"
msgid "Retraction when switching material"
msgstr "Rückzug bei Materialwechsel"
msgid "Basic information"
msgstr "Grundlegende Informationen"
@@ -10634,6 +10697,12 @@ msgstr "Kompatible Prozessprofile"
msgid "Printable space"
msgstr "Druckbarer Raum"
msgid "Printer Agent"
msgstr "Drucker-Agent"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Wählen Sie die Implementierung des Netzwerkagenten für die Druckerkommunikation. Verfügbare Agenten werden beim Start registriert."
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10759,9 +10828,6 @@ msgstr "Höhenbegrenzungen für Schichten"
msgid "Z-Hop"
msgstr "Z-Hop"
msgid "Retraction when switching material"
msgstr "Rückzug bei Materialwechsel"
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
"\n"
@@ -12103,6 +12169,10 @@ msgstr " ist zu nahe am Sperrbereich und es werden Kollisionen verursacht.\n"
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " ist zu nahe am Klumpenerkennungsbereich und es werden Kollisionen verursacht.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " liegt teilweise außerhalb des druckbaren Bereichs und kann nicht gedruckt werden.\n"
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."
msgstr "Die ausgewählten Düsentemperaturen sind nicht kompatibel. Die Düsentemperatur jedes Filaments muss innerhalb des empfohlenen Düsentemperaturbereichs der anderen Filamente liegen. Andernfalls kann es zu Düsenverstopfungen oder Druckerschäden kommen."
@@ -12418,9 +12488,6 @@ msgstr "Benutze 3MF statt G-Code"
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 "Aktivieren Sie diese Option, wenn der Drucker eine 3MF-Datei als Druckauftrag akzeptiert. Wenn aktiviert, sendet Orca Slicer die geslicete Datei als .gcode.3mf, anstatt als einfache .gcode-Datei."
msgid "Printer Agent"
msgstr "Drucker-Agent"
msgid "Select the network agent implementation for printer communication."
msgstr "Wählen Sie die Netzwerk-Agent-Implementierung für die Druckerkommunikation aus."
@@ -13091,9 +13158,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "Geschwindigkeit der internen Brücken. Wenn der Wert als Prozentsatz angegeben wird, wird er auf der Grundlage der Brückengeschwindigkeit berechnet. Der Standardwert beträgt 150 %."
msgid "Brim width"
msgstr "Randbreite"
msgid "This is the distance from the model to the outermost brim line."
msgstr "Abstand vom Modell zur äußersten Randlinie"
@@ -13174,6 +13238,14 @@ msgstr ""
"Die Geometrie wird vor der Erkennung scharfer Winkel reduziert. Dieser Parameter ist ein Indikator für die minimale Länge der Abweichung für die Reduzierung.\n"
"0 zum Deaktivieren."
# AI Translated
msgid "Brim ears outer only"
msgstr "Brim-Ohren nur außen"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Erzeugt Mausohren nur an der Außenkontur des Modells, ohne Löcher und geschlossene Bereiche."
msgid "upward compatible machine"
msgstr "Aufwärtskompatible Maschine"
@@ -14341,6 +14413,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "Gyroid"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Glättungsfaktor der Füllung"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Legt fest, wie stark die Ecken der Füllung abgerundet werden. 0% behält den ursprünglichen scharfkantigen Pfad bei, während 100% die größtmöglichen Kurven zwischen benachbarten Fülllinien erzeugt."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "Dies ist die Beschleunigung der Füllung von der obersten Schicht. Die Verwendung eines niedrigeren Werts kann die Qualität der Oberfläche verbessern."
@@ -14874,6 +14954,14 @@ msgstr "Mit welcher Art von G-Code ist der Drucker kompatibel."
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "G-code-Konfigurationsblock auslassen"
# AI Translated
msgid "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."
msgstr "Schreibt den CONFIG_BLOCK (die Schlüssel-Wert-Paare der Slicer-Konfiguration) nicht in die G-code-Datei. Das kann bei Druckern helfen, deren Firmware beim Verarbeiten dieser Kommentarzeilen abstürzt (z. B. Anycubic go-klipper). Hinweis: Die G-code-Datei enthält dann keine Slicer-Einstellungen mehr, sodass beim erneuten Importieren in OrcaSlicer die Konfiguration nicht wiederhergestellt wird."
msgid "Pellet Modded Printer"
msgstr "Pellet-Modifizierter Drucker"
@@ -15920,6 +16008,14 @@ msgstr "Langer Rückzug beim Extruderwechsel"
msgid "Retraction distance when extruder change"
msgstr "Rückzugslänge beim Extruderwechsel"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "Rückzugslänge (Werkzeugwechsel)"
# 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 "Wenn vor einem Werkzeugwechsel ein Rückzug ausgelöst wird, wird das Filament um den angegebenen Betrag zurückgezogen (die Länge wird am rohen Filament gemessen, bevor es in den Extruder gelangt)."
msgid "Z-hop height"
msgstr "Z-Hub-Höhe"
@@ -16014,6 +16110,10 @@ msgstr "Zusätzliche Länge beim Neustart"
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 "Wenn die Rückzugskompensation nach dem Reisemove durchgeführt wird, wird der Extruder diese zusätzliche Menge an Filament schieben. Diese Einstellung wird nur selten benötigt."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "Zusätzliche Länge beim Neustart (Werkzeugwechsel)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "Wenn die Rückzugskompensation nach dem Wechsel des Werkzeugs durchgeführt wird, wird der Extruder diese zusätzliche Menge an Filament schieben."
@@ -16431,6 +16531,14 @@ msgstr "Werkzeugwechsel auf dem Reinigungsturm"
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 "Erzwinge, dass der Werkzeugkopf zum Reinigungsturm fährt, bevor der Werkzeugwechselbefehl (Tx) ausgegeben wird. Nur relevant für Mehrfach-Extruder (Mehrfach-Werkzeugkopf) Drucker, die einen Typ-2-Reinigungsturm verwenden. Standardmäßig überspringt Orca die Fahrt auf Mehrfach-Werkzeugkopf-Maschinen, da die Firmware den Kopfwechsel übernimmt, was dazu führen kann, dass der Tx-Befehl über dem gedruckten Teil ausgegeben wird. Aktivieren Sie diese Option, wenn Sie möchten, dass der Werkzeugwechsel immer über dem Reinigungsturm ausgegeben wird."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "Auf Temperatur am Reinigungsturm warten"
# 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 "Nimmt das neue Werkzeug auf, ohne auf das Erreichen der Drucktemperatur zu warten, fährt zum Reinigungsturm und wartet dort unmittelbar vor dem Spülen auf die Temperatur. Das beim Aufheizen austretende Material landet auf dem Turm statt auf dem Modell, und die Fahrt überlappt sich mit dem Aufheizen. Nur relevant für Multi-Extruder-Drucker (mehrere Werkzeugköpfe) mit einem Reinigungsturm vom Typ 2. Die Firmware bzw. das Werkzeugwechsel-Makro darf nicht selbst auf die Temperatur warten. Wenn deaktiviert, wird das Warten auf die Temperatur direkt nach dem Werkzeugwechselbefehl ausgegeben."
msgid "No sparse layers (beta)"
msgstr "Keine dünnen Schichten (Beta)"
@@ -19650,9 +19758,6 @@ msgstr "Drucker"
msgid "Print Host upload"
msgstr "Hochladen zum Druck-Host"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Wählen Sie die Implementierung des Netzwerkagenten für die Druckerkommunikation. Verfügbare Agenten werden beim Start registriert."
msgid "Select a Flashforge printer"
msgstr "Wählen Sie einen Flashforge-Drucker aus"
@@ -20500,9 +20605,6 @@ msgstr "Es ist etwas Unerwartetes passiert, als Sie versucht haben, sich anzumel
msgid "User canceled."
msgstr "Benutzer abgebrochen."
msgid "Head diameter"
msgstr "Kopfdurchmesser"
msgid "Max angle"
msgstr "Maximaler Winkel"
@@ -21286,6 +21388,22 @@ 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 ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "Die Schichthöhe ist zu klein.\n"
#~ "Sie wird auf min_layer_height gesetzt\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "Die Schichthöhe überschreitet das Limit in Druckereinstellungen -> Extruder -> Schichthöhenlimits. Dies kann zu Problemen mit der Druckqualität führen."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "Automatisch an den eingestellten Bereich anpassen?\n"
#~ msgid "Head diameter"
#~ msgstr "Kopfdurchmesser"
#~ msgid "Print order within a single layer."
#~ msgstr "Druckreihenfolge innerhalb einer einzelnen Schicht"
+109 -35
View File
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: 2026-06-17 15:44-0300\n"
"Last-Translator: Alexandre Folle de Menezes\n"
"Language-Team: \n"
@@ -4448,6 +4448,20 @@ msgstr ""
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr ""
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr ""
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr ""
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr ""
msgid "Adjust"
msgstr ""
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4529,6 +4543,12 @@ msgid ""
"No - Disable Arachne Wall Generator and set [Displacement] mode of the Fuzzy Skin"
msgstr ""
msgid "Brim ear radius"
msgstr ""
msgid "Brim width"
msgstr ""
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 ""
@@ -4780,6 +4800,12 @@ msgstr ""
msgid "Calibration error"
msgstr ""
msgid "This printer is not configured with the hardware this control needs."
msgstr ""
msgid "This control is not supported on this printer."
msgstr ""
msgid "Network unavailable"
msgstr ""
@@ -5611,7 +5637,7 @@ msgstr ""
msgid "Size:"
msgstr ""
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr ""
@@ -5786,6 +5812,9 @@ msgstr ""
msgid "Project"
msgstr ""
msgid "Device (Web)"
msgstr ""
msgid "Yes"
msgstr ""
@@ -7776,19 +7805,19 @@ msgstr ""
msgid "Replaced with 3D files from directory:\n"
msgstr ""
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr ""
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr ""
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr ""
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr ""
@@ -8468,6 +8497,15 @@ msgstr ""
msgid "Pop up to select filament grouping mode"
msgstr ""
msgid "Visible plugin pages"
msgstr ""
msgid "pages"
msgstr ""
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr ""
msgid "Behaviour"
msgstr ""
@@ -8793,6 +8831,14 @@ msgstr ""
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr ""
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr ""
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
msgid "Experimental Features"
msgstr ""
@@ -9048,9 +9094,21 @@ msgstr ""
msgid "Preset Inside Project"
msgstr ""
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr ""
msgid "Detach from parent"
msgstr ""
msgid "Unique preset"
msgstr ""
msgid "Parent preset"
msgstr ""
msgid "This preset does not inherit from another preset."
msgstr ""
msgid "Name is unavailable."
msgstr ""
@@ -9728,20 +9786,6 @@ msgstr ""
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 ""
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr ""
msgid "Adjust to the set range automatically?\n"
msgstr ""
msgid "Adjust"
msgstr ""
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 ""
@@ -9927,6 +9971,9 @@ msgstr ""
msgid "Setting Overrides"
msgstr ""
msgid "Retraction when switching material"
msgstr ""
msgid "Basic information"
msgstr ""
@@ -10053,6 +10100,12 @@ msgstr ""
msgid "Printable space"
msgstr ""
msgid "Printer Agent"
msgstr ""
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr ""
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10175,9 +10228,6 @@ msgstr ""
msgid "Z-Hop"
msgstr ""
msgid "Retraction when switching material"
msgstr ""
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
"\n"
@@ -11441,6 +11491,9 @@ msgstr ""
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr ""
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr ""
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."
msgstr ""
@@ -11736,9 +11789,6 @@ msgstr ""
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 ""
msgid "Printer Agent"
msgstr ""
msgid "Select the network agent implementation for printer communication."
msgstr ""
@@ -12275,9 +12325,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr ""
msgid "Brim width"
msgstr ""
msgid "This is the distance from the model to the outermost brim line."
msgstr ""
@@ -12343,6 +12390,12 @@ msgid ""
"0 to deactivate."
msgstr ""
msgid "Brim ears outer only"
msgstr ""
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr ""
msgid "upward compatible machine"
msgstr ""
@@ -13355,6 +13408,12 @@ msgstr ""
msgid "Gyroid"
msgstr ""
msgid "Sparse infill smooth factor"
msgstr ""
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr ""
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr ""
@@ -13835,6 +13894,12 @@ msgstr ""
msgid "Klipper"
msgstr ""
msgid "Skip G-code config block"
msgstr ""
msgid "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."
msgstr ""
msgid "Pellet Modded Printer"
msgstr ""
@@ -14796,6 +14861,12 @@ msgstr ""
msgid "Retraction distance when extruder change"
msgstr ""
msgid "Retraction Length (Toolchange)"
msgstr ""
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 ""
msgid "Z-hop height"
msgstr ""
@@ -14889,6 +14960,9 @@ msgstr ""
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 ""
msgid "Extra length on restart (Toolchange)"
msgstr ""
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr ""
@@ -15274,6 +15348,12 @@ msgstr ""
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 ""
msgid "Wait for temperature on wipe tower"
msgstr ""
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 ""
msgid "No sparse layers (beta)"
msgstr ""
@@ -18249,9 +18329,6 @@ msgstr ""
msgid "Print Host upload"
msgstr ""
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr ""
msgid "Select a Flashforge printer"
msgstr ""
@@ -19083,9 +19160,6 @@ msgstr ""
msgid "User canceled."
msgstr ""
msgid "Head diameter"
msgstr ""
msgid "Max angle"
msgstr ""
+155 -37
View File
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: Ian A. Bassi <>\n"
"Language-Team: \n"
@@ -4564,6 +4564,23 @@ msgstr "La temperatura actual de la recámara es superior a la temperatura de se
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "La temperatura mínima de la recámara (%d℃) es superior a la temperatura objetivo de la recámara (%d℃). El valor mínimo es el umbral en el que comienza la impresión mientras la recámara continúa calentándose hacia el objetivo, por lo que no debería superarlo. Se ajustará al valor objetivo."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "La altura de capa es demasiado pequeña. Se establecerá en el mínimo (%g mm)."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "La altura de capa está fuera de los límites establecidos en Ajustes de la Impresora -> Extrusor -> Limite de Altura de Capa, esto puede causar problemas de calidad de impresión."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "¿Ajustarla automáticamente al límite (%g mm)?"
msgid "Adjust"
msgstr "Ajustar"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4684,6 +4701,13 @@ msgstr ""
"Sí: habilitar el generador de muros Arachne\n"
"No: deshabilitar el generador de paredes Arachne y establecer el modo [Desplazamiento] de la piel rugosa"
# AI Translated
msgid "Brim ear radius"
msgstr "Radio de las orejas de borde"
msgid "Brim width"
msgstr "Ancho del borde de adherencia"
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 "El modo espiral solo funciona cuando los bucles de perímetro son 1, el soporte está desactivado, la detección de agrupamientos mediante sondeo está desactivada, las capas superiores de la carcasa son 0, la densidad de relleno es 0 y el tipo de lapso de tiempo es tradicional."
@@ -4938,6 +4962,14 @@ msgstr "Fallo al generar el G-Code de calibración"
msgid "Calibration error"
msgstr "Error de calibración"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "Esta impresora no está configurada con el hardware que necesita este control."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Este control no es compatible con esta impresora."
msgid "Network unavailable"
msgstr "Red no disponible"
@@ -5779,7 +5811,7 @@ msgstr "Volumen:"
msgid "Size:"
msgstr "Tamaño:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "Se han encontrado conflictos de rutas G-Code en la capa %d, Z = %.2lfmm. Por favor, separe más los objetos en conflicto (%s <-> %s)."
@@ -5960,6 +5992,10 @@ msgstr "Multi-dispositivo"
msgid "Project"
msgstr "Proyecto"
# AI Translated
msgid "Device (Web)"
msgstr "Dispositivo (Web)"
msgid "Yes"
msgstr "Sí"
@@ -7997,19 +8033,19 @@ 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"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ Omitido %s: mismo archivo.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ Omitido %s: el archivo no existe.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ Omitido %s: fallo al reemplazar.\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ Reemplazado %s.\n"
@@ -8725,6 +8761,18 @@ msgstr "Con esta opción activada, puede enviar una tarea a varios dispositivos
msgid "Pop up to select filament grouping mode"
msgstr "Ventana emergente para seleccionar el modo de agrupación de filamentos"
# AI Translated
msgid "Visible plugin pages"
msgstr "Páginas de plugins visibles"
# AI Translated
msgid "pages"
msgstr "páginas"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "Número de páginas de plugins que se muestran como pestañas fijas antes de que el resto de páginas se agrupe en un desplegable en la última pestaña."
msgid "Behaviour"
msgstr "Comportamiento"
@@ -9074,6 +9122,18 @@ msgstr "Mostrar ajustes preestablecidos no compatibles"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "Mostrar los ajustes preestablecidos incompatibles o no compatibles en los menús desplegables de impresoras y filamentos. Estos ajustes preestablecidos no se pueden seleccionar."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Experimental) Usar agentes de impresora en lugar de hosts de impresión"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Envía los trabajos de impresión de impresoras que no son Bambu a través de los agentes de plugin de impresora en lugar del flujo clásico de subida al host de impresión.\n"
"Cuando está desactivado, OrcaSlicer utiliza el comportamiento heredado del host de impresión."
msgid "Experimental Features"
msgstr "Funciones experimentales"
@@ -9333,9 +9393,25 @@ msgstr "Perfil de usuario"
msgid "Preset Inside Project"
msgstr "Perfil interno del proyecto"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Copia en este perfil todos los valores heredados del perfil padre y elimina la relación de herencia. Los perfiles compatibles solo con el perfil padre pueden dejar de ser compatibles."
msgid "Detach from parent"
msgstr "Separar del elemento padre"
# AI Translated
msgid "Unique preset"
msgstr "Perfil único"
# AI Translated
msgid "Parent preset"
msgstr "Perfil padre"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Este perfil no hereda de otro perfil."
msgid "Name is unavailable."
msgstr "El nombre no está disponible."
@@ -10031,22 +10107,6 @@ msgstr "¿Está seguro de que desea activar esta opción?"
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 "Los patrones de relleno suelen diseñarse para gestionar la rotación automáticamente y asegurar una impresión adecuada y lograr sus efectos previstos (p. ej., Giroide, Cúbico). Rotar el patrón de relleno actual puede provocar soporte insuficiente. Proceda con precaución y compruebe detenidamente posibles problemas de impresión. ¿Está seguro de que desea activar esta opción?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"La altura de la capa es demasiado pequeña.\n"
"Se establecerá en min_layer_height\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "La altura de la capa excede el límite en Ajustes de la Impresora -> Extrusor -> Limite de Altura de Capa, esto puede causar problemas de calidad de impresión."
msgid "Adjust to the set range automatically?\n"
msgstr "¿Desea ajustar el rango automáticamente?\n"
msgid "Adjust"
msgstr "Ajustar"
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 "Función experimental: retraer y cortar el filamento a una mayor distancia durante los cambios de filamento para minimizar el purgado. Aunque puede reducir notablemente el purgado, también puede aumentar el riesgo de atascos de boquilla u otras complicaciones de impresión.Característica experimental: Retraer y cortar el filamento a mayor distancia durante los cambios de filamento para minimizar el descarte. Aunque puede reducir notablemente el descarte, también puede elevar el riesgo de atascos de boquillas u otros problemas en la impresión."
@@ -10238,6 +10298,9 @@ msgstr "Palabras clave utilizadas y encontradas"
msgid "Setting Overrides"
msgstr "Sobreescribir Ajustes de impresora"
msgid "Retraction when switching material"
msgstr "Retracción al cambiar de material"
msgid "Basic information"
msgstr "Información básica"
@@ -10364,6 +10427,12 @@ msgstr "Perfiles de proceso compatibles"
msgid "Printable space"
msgstr "Espacio imprimible"
msgid "Printer Agent"
msgstr "Agente de impresora"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Seleccione la implementación del agente de red para la comunicación con la impresora. Los agentes disponibles se registran al iniciar el sistema."
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10489,9 +10558,6 @@ msgstr "Límites de altura de la capa"
msgid "Z-Hop"
msgstr "Salto en Z"
msgid "Retraction when switching material"
msgstr "Retracción al cambiar de material"
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
"\n"
@@ -11809,6 +11875,10 @@ msgstr " está demasiado cerca de una zona de exclusión, lo que provocará coli
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " está demasiado cerca del área de detección de aglomeraciones, y se producirán colisiones.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " está parcialmente fuera del área imprimible, y no se puede imprimir.\n"
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."
msgstr "Las temperaturas de boquilla seleccionadas son incompatibles. La temperatura de boquilla de cada filamento debe estar dentro del rango de temperaturas recomendado para los demás filamentos. De lo contrario, podrían producirse atascos en la boquilla o daños en la impresora."
@@ -12116,9 +12186,6 @@ msgstr "Utiliza 3MF en lugar de G-code"
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 "Activa esta opción si la impresora admite un archivo 3MF como trabajo de impresión. Cuando está activada, Orca Slicer envía el archivo cortado como un archivo .gcode.3mf, en lugar de como un archivo .gcode convencional."
msgid "Printer Agent"
msgstr "Agente de impresora"
msgid "Select the network agent implementation for printer communication."
msgstr "Seleccione la implementación del agente de red para la comunicación con la impresora."
@@ -12794,9 +12861,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "Velocidad de los puntes internos. Si se expresa como un porcentaje, será Calculado en base a la velocidad de puente. El valor por defecto es 150%."
msgid "Brim width"
msgstr "Ancho del borde de adherencia"
msgid "This is the distance from the model to the outermost brim line."
msgstr "Distancia del modelo a la línea más externa del borde de adherencia."
@@ -12876,6 +12940,14 @@ msgstr ""
"La geometría se verá diezmada antes de detectar angulos agudos. Este parámetro indica la longitud mínima de desviación para el diezmado\n"
"0 para desactivar."
# AI Translated
msgid "Brim ears outer only"
msgstr "Orejas de borde solo en el exterior"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Genera orejas de ratón únicamente en el contorno exterior del modelo, excluyendo agujeros y secciones cerradas."
msgid "upward compatible machine"
msgstr "máquina compatible ascendente"
@@ -14011,6 +14083,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "Giroide"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Factor de suavizado del relleno poco denso"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Controla cuánto se redondean las esquinas del relleno poco denso. 0% mantiene el trazado original con esquinas vivas, mientras que 100% produce las curvas más amplias posibles entre líneas de relleno adyacentes."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "Aceleración del relleno de la superficie superior. El uso de un valor más bajo puede mejorar la calidad de la superficie superior."
@@ -14544,6 +14624,14 @@ msgstr "Con qué tipo de G-Code es compatible la impresora."
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "Omitir el bloque de configuración del G-code"
# AI Translated
msgid "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."
msgstr "No escribe el CONFIG_BLOCK (los pares clave/valor de la configuración del laminador) en el archivo G-code. Esto puede ayudar con impresoras cuyo firmware falla al analizar esas líneas de comentario (p. ej. Anycubic go-klipper). Nota: el archivo G-code ya no contendrá los ajustes del laminador, por lo que al importarlo de nuevo en OrcaSlicer no se restaurará la configuración."
msgid "Pellet Modded Printer"
msgstr "Impresora Modificada para Pellets"
@@ -15583,6 +15671,14 @@ msgstr "Retracción larga al cambiar de extrusor"
msgid "Retraction distance when extruder change"
msgstr "Distancia de retracción al cambiar de extrusor"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "Longitud de retracción (Cambio de herramienta)"
# 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 "Cuando se activa la retracción antes de un cambio de herramienta, el filamento se retrae la cantidad especificada (la longitud se mide sobre el filamento en bruto, antes de entrar en el extrusor)."
msgid "Z-hop height"
msgstr "Altura de Salto en Z"
@@ -15676,6 +15772,10 @@ msgstr "Longitud extra de reinicio"
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 "Cuando la retracción se compensa después de un desplazamiento, el extrusor expulsará esta cantidad adicional de filamento. Esta función no suele ser necesaria."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "Longitud extra de reinicio (Cambio de herramienta)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "Cuando se compensa la retracción después de cambiar de cabezal, el extrusor expulsará esta cantidad adicional de filamento."
@@ -16082,6 +16182,14 @@ msgstr "Cambio de herramienta en la 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 "Obliga al cabezal a desplazarse hasta la torre de purga antes de emitir el comando de cambio de herramienta (Tx). Solo es relevante para impresoras con múltiples extrusores (múltiples cabezales) que utilicen una torre de limpieza de tipo 2. Por defecto, Orca omite el desplazamiento en máquinas con múltiples cabezales porque el firmware se encarga del cambio de cabezal, lo que puede provocar que el comando Tx se emita por encima de la pieza impresa. Habilita esta opción si deseas que el cambio de herramienta se emita siempre por encima de la torre de purga."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "Esperar la temperatura en la 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 "Recoge la nueva herramienta sin esperar a que alcance la temperatura de impresión, se desplaza a la torre de purga y espera allí la temperatura, justo antes de purgar. El rezumado del calentamiento cae sobre la torre en lugar de sobre el modelo, y el desplazamiento se solapa con el calentamiento. Solo es relevante para impresoras multiextrusor (multicabezal) que usan una torre de purga de tipo 2. El firmware o la macro de cambio de herramienta no deben esperar la temperatura por su cuenta. Cuando está desactivado, la espera de temperatura se emite justo después del comando de cambio de herramienta."
msgid "No sparse layers (beta)"
msgstr "Sin capas de baja densidad (beta)"
@@ -19281,9 +19389,6 @@ msgstr "Impresora física"
msgid "Print Host upload"
msgstr "Mandar al servidor de impresión"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Seleccione la implementación del agente de red para la comunicación con la impresora. Los agentes disponibles se registran al iniciar el sistema."
msgid "Select a Flashforge printer"
msgstr "Selecciona una impresora Flashforge"
@@ -20125,9 +20230,6 @@ msgstr "Ha ocurrido algo inesperado al intentar iniciar sesión, inténtelo de n
msgid "User canceled."
msgstr "Cancelado por el usuario."
msgid "Head diameter"
msgstr "Diámetro de la cabeza"
msgid "Max angle"
msgstr "Ángulo máximo"
@@ -20861,6 +20963,22 @@ 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 ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "La altura de la capa es demasiado pequeña.\n"
#~ "Se establecerá en min_layer_height\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "La altura de la capa excede el límite en Ajustes de la Impresora -> Extrusor -> Limite de Altura de Capa, esto puede causar problemas de calidad de impresión."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "¿Desea ajustar el rango automáticamente?\n"
#~ msgid "Head diameter"
#~ msgstr "Diámetro de la cabeza"
#~ msgid "Print order within a single layer."
#~ msgstr "Orden de impresión dentro de cada capa."
+155 -37
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: 2026-07-20 13:33+0200\n"
"Last-Translator: Manu Goiogana <mgoiogana@gmail.com>\n"
"Language-Team: \n"
@@ -4606,6 +4606,23 @@ msgstr "Uneko ganberako tenperatura materialaren tenperatura segurua baino handi
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "Ganberako gutxieneko tenperatura (%d ℃) helburuko ganbera-tenperatura (%d ℃) baino altuagoa da. Gutxieneko balioa inprimaketa hasten den atalasea da, ganberak helbururantz berotzen jarraitzen duen bitartean; beraz, ez luke helburua gainditu behar. Helburuko baliora mugatuko da."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "Geruza-altuera txikiegia da. Gutxienekora ezarriko da (%g mm)."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Geruza-altuera Inprimagailuaren ezarpenak -> Estrusorea -> Geruza-altueraren mugak atalean ezarritako mugetatik kanpo dago; horrek inprimatze-kalitateko arazoak sor ditzake."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "Automatikoki mugara (%g mm) doitu nahi duzu?"
msgid "Adjust"
msgstr "Doitu"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4725,6 +4742,13 @@ msgstr ""
"Bai - Gaitu Arachne horma-sorgailua\n"
"Ez - Desgaitu Arachne horma-sorgailua eta ezarri gainazal zimurraren [Desplazamendua] modua"
# AI Translated
msgid "Brim ear radius"
msgstr "Ertz-belarriaren erradioa"
msgid "Brim width"
msgstr "Itsaspen ertzaren zabalera"
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 "Espiral moduak baldintza hauetan bakarrik funtzionatzen du: horma-begiztak 1 izatea, euskarriak desgaituta egotea, haztatze bidezko material-metaketa detektatzea desgaituta egotea, goiko estalki-geruzak 0 izatea, dentsitate baxuko betegarriaren dentsitatea 0 izatea eta timelapse mota tradizionala izatea."
@@ -4979,6 +5003,14 @@ msgstr "Hutsegitea gertatu da kalibrazioko G-Code-a sortzean"
msgid "Calibration error"
msgstr "Kalibrazio akatsa"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "Inprimagailu honek ez dauka kontrol honek behar duen hardwarea konfiguratuta."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Kontrol hau ez da bateragarria inprimagailu honekin."
# AI Translated
msgid "Network unavailable"
msgstr "Sarea ez dago erabilgarri"
@@ -5828,7 +5860,7 @@ msgstr "Bolumena:"
msgid "Size:"
msgstr "Tamaina:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "G-code ibilbideen gatazkak aurkitu dira %d geruzan, Z = %.2lf mm. Urrundu gehiago gatazkan dauden objektuak (%s <-> %s)."
@@ -6005,6 +6037,10 @@ msgstr "Gailu anitz"
msgid "Project"
msgstr "Proiektua"
# AI Translated
msgid "Device (Web)"
msgstr "Gailua (Web)"
msgid "Yes"
msgstr "Bai"
@@ -8064,19 +8100,19 @@ msgstr "Ez da ordezkatzeko direktoriorik hautatu"
msgid "Replaced with 3D files from directory:\n"
msgstr "Direktorio honetako 3D fitxategiekin ordeztuta:\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ %s saltatu da: fitxategi bera.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ %s saltatu da: fitxategia ez da existitzen.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ %s saltatu da: ezin izan da ordeztu.\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ %s ordezkatu da.\n"
@@ -8790,6 +8826,18 @@ msgstr "Aukera hau gaituta, zeregin bat hainbat gailutara bidali eta hainbat gai
msgid "Pop up to select filament grouping mode"
msgstr "Erakutsi filamentuak taldekatzeko modua hautatzeko leihoa"
# AI Translated
msgid "Visible plugin pages"
msgstr "Ikusgai dauden plugin-orriak"
# AI Translated
msgid "pages"
msgstr "orri"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "Fitxa finko gisa erakusten diren plugin-orrien kopurua; gainerako orriak azken fitxako goitibeherako zerrendan bilduko dira."
msgid "Behaviour"
msgstr "Jokabidea"
@@ -9142,6 +9190,18 @@ msgstr "Erakutsi onartzen ez diren aurrezarpenak"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "Erakutsi bateraezinak edo onartu gabeak diren aurrezarpenak inprimagailuaren eta filamentuaren goitibeherako zerrendetan. Aurrezarpen hauek ezin dira hautatu."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Esperimentala) Erabili inprimagailu-agenteak inprimatze-hostenen ordez"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Bideratu Bambu ez diren inprimagailuen inprimatze-lanak inprimagailuaren plugin-agenteen bidez, inprimatze-hostera igotzeko fluxu klasikoaren ordez.\n"
"Desgaituta dagoenean, OrcaSlicer-ek inprimatze-hostaren aurreko portaera erabiltzen du."
msgid "Experimental Features"
msgstr "Ezaugarri esperimentalak"
@@ -9402,9 +9462,25 @@ msgstr "Erabiltzailearen aurrezarpena"
msgid "Preset Inside Project"
msgstr "Proiektu barruko aurrezarpena"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Aurrezarpen honetara gurasoaren balio heredatu guztiak kopiatzen ditu eta gurasoarekiko lotura kentzen du. Gurasoarekin soilik bateragarriak diren aurrezarpenak bateraezin gera daitezke."
msgid "Detach from parent"
msgstr "Bereizi gurasotik"
# AI Translated
msgid "Unique preset"
msgstr "Aurrezarpen bakarra"
# AI Translated
msgid "Parent preset"
msgstr "Guraso-aurrezarpena"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Aurrezarpen honek ez du beste aurrezarpen batetik heredatzen."
msgid "Name is unavailable."
msgstr "Izena ez dago erabilgarri."
@@ -10124,22 +10200,6 @@ msgstr "Ziur aukera hau gaitu nahi duzula?"
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 "Betegarri-patroiak normalean biraketa automatikoki kudeatzeko diseinatuta daude, behar bezala inprimatzeko eta nahi den efektua lortzeko (adibidez, Giroidea edo Kubikoa). Uneko dentsitate baxuko betegarri-patroia biratzeak euskarri eskasa eragin dezake. Kontuz jarraitu eta egiaztatu arretaz inprimatze-arazorik sor daitekeen. Ziur zaude aukera hau gaitu nahi duzula?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"Geruza-altuera txikiegia da.\n"
"min_layer_height baliora ezarriko da\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Geruza-altuerak Inprimagailuaren ezarpenak -> Estrusorea -> Geruza-altueraren mugak ataleko muga gainditzen du; horrek inprimatze-kalitateko arazoak sor ditzake."
msgid "Adjust to the set range automatically?\n"
msgstr "Doitu automatikoki ezarritako barrutira?\n"
msgid "Adjust"
msgstr "Doitu"
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 "Funtzio esperimentala: filamentu aldaketetan distantzia handiagoan atzera egitea eta moztea, purgatzea minimizatzeko. Purgatzea nabarmen murriztu dezakeen arren, pitaren buxadurak edo bestelako inprimatze-arazoak izateko arriskua ere handitu dezake."
@@ -10333,6 +10393,9 @@ msgstr "Erreserbatutako gako-hitzak aurkitu dira"
msgid "Setting Overrides"
msgstr "Ezarpenen gainidazketak"
msgid "Retraction when switching material"
msgstr "Atzera-egitea materiala aldatzean"
msgid "Basic information"
msgstr "Oinarrizko informazioa"
@@ -10459,6 +10522,12 @@ msgstr "Prozesu-profil bateragarriak"
msgid "Printable space"
msgstr "Inprimatzeko espazioa"
msgid "Printer Agent"
msgstr "Inprimagailu-agentea"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Hautatu sare-agentearen inplementazioa inprimagailuarekin komunikatzeko. Erabilgarri dauden agenteak abioan erregistratzen dira."
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10584,9 +10653,6 @@ msgstr "Geruza-altueraren mugak"
msgid "Z-Hop"
msgstr "Z jauzia"
msgid "Retraction when switching material"
msgstr "Atzera-egitea materiala aldatzean"
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
"\n"
@@ -11912,6 +11978,10 @@ msgstr " bazterketa-eremu batetik gertuegi dago, eta talkak eragingo ditu.\n"
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " material-metaketa detektatzeko eremutik gertuegi dago, eta talkak eragingo ditu.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " inprimagarri den eremutik kanpo dago partzialki, eta ezin da inprimatu.\n"
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."
msgstr "Hautatutako pita-tenperaturak ez dira bateragarriak. Filamentu bakoitzaren pita-tenperaturak gainerako filamentuen gomendatutako pita-tenperatura tartean egon behar du. Bestela, pita buxatu edo inprimagailua kaltetu daiteke."
@@ -12228,9 +12298,6 @@ msgstr "Erabili 3MF G-codearen ordez"
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 "Gaitu aukera hau inprimagailuak 3MF fitxategi bat inprimatze-lan gisa onartzen badu. Gaituta dagoenean, OrcaSlicerrek xerratutako fitxategia .gcode.3mf gisa bidaltzen du, .gcode fitxategi arrunt baten ordez."
msgid "Printer Agent"
msgstr "Inprimagailu-agentea"
msgid "Select the network agent implementation for printer communication."
msgstr "Hautatu inprimagailuarekin komunikatzeko sare-agentearen inplementazioa."
@@ -12905,9 +12972,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "Barru-zubien abiadura. Balioa ehuneko gisa adierazten bada, Zubien abiadura-ren arabera kalkulatuko da. Lehenetsitako balioa % 150ekoa da."
msgid "Brim width"
msgstr "Itsaspen ertzaren zabalera"
msgid "This is the distance from the model to the outermost brim line."
msgstr "Hau da modelotik itsaspen ertzaren kanporen lerrora dagoen distantzia."
@@ -12987,6 +13051,14 @@ msgstr ""
"Geometria sinplifikatu egingo da angelu zorrotzak detektatu aurretik. Parametro honek sinplifikaziorako desbideratzearen gutxieneko luzera adierazten du.\n"
"0, desaktibatzeko."
# AI Translated
msgid "Brim ears outer only"
msgstr "Ertz-belarriak kanpoaldean soilik"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Sortu saguaren belarriak modeloaren kanpoko ingeradan soilik, zuloak eta itxitako atalak baztertuta."
msgid "upward compatible machine"
msgstr "gorantz bateragarria den makina"
@@ -14137,6 +14209,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "Giroidea"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Dentsitate baxuko betegarriaren leuntze-faktorea"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Dentsitate baxuko betegarriaren izkinak zenbateraino biribiltzen diren kontrolatzen du. 0% balioak jatorrizko ibilbide zorrotza mantentzen du, eta 100% balioak ondoz ondoko betegarri-lerroen arteko kurbarik zabalenak sortzen ditu."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "Hau da goiko gainazaleko betegarriaren azelerazioa. Balio txikiago batek goiko gainazalaren kalitatea hobetu dezake."
@@ -14676,6 +14756,14 @@ msgstr "Inprimagailua zer G-code motarekin den bateragarria."
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "Saltatu G-code-aren konfigurazio-blokea"
# AI Translated
msgid "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."
msgstr "Ez idatzi CONFIG_BLOCK (xerragailuaren konfigurazioko gako/balio bikoteak) G-code fitxategian. Lagungarria izan daiteke firmwareak iruzkin-lerro horiek prozesatzean huts egiten duen inprimagailuetan (adib. Anycubic go-klipper). Oharra: G-code fitxategiak ez ditu jada xerragailuaren ezarpenak edukiko; beraz, OrcaSlicer-era berriro inportatzeak ez du konfigurazioa berreskuratuko."
msgid "Pellet Modded Printer"
msgstr "Pelletekin moldatutako inprimagailua"
@@ -15719,6 +15807,14 @@ msgstr "Atzera-egite luzea estrusorea aldatzean"
msgid "Retraction distance when extruder change"
msgstr "Atzera-egite distantzia estrusorea aldatzean"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "Atzera-egitearen luzera (Erreminta aldaketa)"
# 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 "Erreminta aldatu aurretik atzera-egitea abiarazten denean, filamentua zehaztutako kopurua atzeratzen da (luzera filamentu gordinean neurtzen da, estrusorean sartu aurretik)."
msgid "Z-hop height"
msgstr "Z jauziaren altuera"
@@ -15812,6 +15908,10 @@ msgstr "Berrabiaraztean luzera gehigarria"
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 "Mugimenduaren ondoren atzera-egitea konpentsatzen denean, estrusoreak filamentu kantitate gehigarri hau bultzatuko du. Ezarpen hau gutxitan behar da."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "Berrabiaraztean luzera gehigarria (Erreminta aldaketa)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "Tresna aldatu ondoren atzera-egitea konpentsatzen denean, estrusoreak filamentu kantitate gehigarri hau bultzatuko du."
@@ -16220,6 +16320,14 @@ msgstr "Tresna-aldaketa purgatze-dorrean"
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 "Behartu inprimatze-burua purgatze-dorrera joatera tresna aldatzeko agindua (Tx) eman aurretik. 2. motako purgatze-dorrea erabiltzen duten estrusore anitzeko (inprimatze-buru anitzeko) inprimagailuetarako bakarrik da garrantzitsua. Lehenespenez, Orcak ez du joan-etorria egiten inprimatze-buru anitzeko makinetan, firmwareak buruaren aldaketa kudeatzen duelako; horren ondorioz, Tx agindua inprimatutako piezaren gainean eman daiteke. Gaitu aukera hau tresna-aldaketa beti purgatze-dorrearen gainean egin dadin."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "Itxaron tenperatura purgatze-dorrean"
# 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 "Hartu erreminta berria inprimatze-tenperaturara iritsi arte itxaron gabe, joan purgatze-dorrera eta itxaron han tenperatura, purgatu aurretik. Berotzeak eragindako jarioa dorrean erortzen da modeloan beharrean, eta desplazamendua berotzearekin gainjartzen da. Estrusore anitzeko (inprimatze-buru anitzeko) inprimagailuetan soilik da baliagarria, 2. motako purgatze-dorrea erabiltzen dutenean. Firmwareak edo erreminta aldaketaren makroak ez du tenperaturaren zain egon behar. Desgaituta dagoenean, tenperaturaren zain egoteko agindua erreminta aldaketaren komandoaren ondoren bidaltzen da."
msgid "No sparse layers (beta)"
msgstr "Geruza bakandurik ez (beta)"
@@ -19429,9 +19537,6 @@ msgstr "Inprimagailu fisikoa"
msgid "Print Host upload"
msgstr "Inprimatze-ostalariaren karga"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Hautatu sare-agentearen inplementazioa inprimagailuarekin komunikatzeko. Erabilgarri dauden agenteak abioan erregistratzen dira."
msgid "Select a Flashforge printer"
msgstr "Hautatu Flashforge inprimagailu bat"
@@ -20278,9 +20383,6 @@ msgstr "Ustekabeko zerbait gertatu da saioa hasten saiatzean; saiatu berriro."
msgid "User canceled."
msgstr "Erabiltzaileak bertan behera utzi du."
msgid "Head diameter"
msgstr "Buruaren diametroa"
msgid "Max angle"
msgstr "Gehieneko angelua"
@@ -21016,6 +21118,22 @@ msgstr ""
"Saihestu okertzea\n"
"Ba al zenekien ABS bezalako okertzeko joera duten materialak inprimatzean ohe beroaren tenperatura egoki igotzeak okertzeko probabilitatea murriztu dezakeela?"
#~ msgid ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "Geruza-altuera txikiegia da.\n"
#~ "min_layer_height baliora ezarriko da\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "Geruza-altuerak Inprimagailuaren ezarpenak -> Estrusorea -> Geruza-altueraren mugak ataleko muga gainditzen du; horrek inprimatze-kalitateko arazoak sor ditzake."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "Doitu automatikoki ezarritako barrutira?\n"
#~ msgid "Head diameter"
#~ msgstr "Buruaren diametroa"
#~ msgid "Print order within a single layer."
#~ msgstr "Geruza bakarreko inprimatze-ordena."
+190 -72
View File
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: Guislain Cyril, Thomas Lété\n"
@@ -4643,6 +4643,23 @@ msgstr "La température actuelle du caisson est supérieure à la température d
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "La température minimale du caisson (%d℃) est supérieure à la température cible du caisson (%d℃). La valeur minimale est le seuil à partir duquel limpression démarre tandis que le caisson continue de chauffer vers la cible ; elle ne doit donc pas la dépasser. Elle sera limitée à la cible."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "La hauteur de couche est trop faible. Elle sera définie au minimum (%g mm)."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "La hauteur de couche est en dehors des limites définies dans Paramètres de limprimante -> Extrudeur -> Limites de la hauteur de la couche, ce qui peut entraîner des problèmes de qualité dimpression."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "Lajuster automatiquement à la limite (%g mm) ?"
msgid "Adjust"
msgstr "Ajuster"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4762,6 +4779,13 @@ msgstr ""
"Oui - Activer le générateur de parois Arachne\n"
"Non - Désactiver le générateur de parois Arachne et définir le mode [Déplacement] de la surface irrégulière"
# AI Translated
msgid "Brim ear radius"
msgstr "Rayon de la bordure à oreilles"
msgid "Brim width"
msgstr "Largeur de la bordure"
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 "Le mode spirale ne fonctionne que lorsque le nombre de parois est 1, le support est désactivé, la détection d'agglomération par sondage est désactivée, les couches supérieures sont à 0, la densité de remplissage clairsemé est à 0 et le type de timelapse est traditionnel."
@@ -4835,7 +4859,7 @@ msgid "Calibrating the micro lidar"
msgstr "Calibrage du micro-Lidar"
msgid "Calibrating flow ratio"
msgstr "Calibration du ratio de débit"
msgstr "Calibration du rapport de débit"
msgid "Pause (nozzle temperature malfunction)"
msgstr "Pause (dysfonctionnement de la température de la buse)"
@@ -5016,6 +5040,14 @@ msgstr "Échec de la génération du G-code de calibration"
msgid "Calibration error"
msgstr "Erreur de la calibration"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "Cette imprimante ne dispose pas du matériel requis par ce contrôle."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Ce contrôle nest pas pris en charge sur cette imprimante."
# AI Translated
msgid "Network unavailable"
msgstr "Réseau indisponible"
@@ -5871,7 +5903,7 @@ msgstr "Volume :"
msgid "Size:"
msgstr "Taille :"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "Des conflits de chemins G-code ont été trouvés au niveau de la couche %d, z = %.2lfmm. Veuillez séparer davantage les objets en conflit (%s <-> %s)."
@@ -6052,6 +6084,10 @@ msgstr "Multi-appareils"
msgid "Project"
msgstr "Projet"
# AI Translated
msgid "Device (Web)"
msgstr "Appareil (Web)"
msgid "Yes"
msgstr "Oui"
@@ -7434,11 +7470,11 @@ msgstr "Erreur lors du chargement des shaders"
msgctxt "Layers"
msgid "Top"
msgstr "Du haut"
msgstr "Supérieur"
msgctxt "Layers"
msgid "Bottom"
msgstr "Du bas"
msgstr "Inférieur"
# AI Translated
msgid "Plugin Selection"
@@ -8120,19 +8156,19 @@ 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"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ Ignoré %s : même fichier.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ Ignoré %s : le fichier n'existe pas.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ Ignoré %s : échec du remplacement.\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ Remplacé %s.\n"
@@ -8857,6 +8893,18 @@ msgstr "Si cette option est activée, vous pouvez envoyer une tâche à plusieur
msgid "Pop up to select filament grouping mode"
msgstr "Fenêtre contextuelle pour sélectionner le mode de regroupement des filaments"
# AI Translated
msgid "Visible plugin pages"
msgstr "Pages de plugins visibles"
# AI Translated
msgid "pages"
msgstr "pages"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "Nombre de pages de plugins affichées sous forme donglets fixes avant que les pages restantes ne soient regroupées dans un menu déroulant sur le dernier onglet."
msgid "Behaviour"
msgstr "Comportement"
@@ -9211,6 +9259,18 @@ msgstr "Afficher les préréglages non pris en charge"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "Affiche les préréglages incompatibles ou non pris en charge dans les listes déroulantes dimprimantes et de filaments. Ces préréglages ne peuvent pas être sélectionnés."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Expérimental) Utiliser les agents dimprimante au lieu des hôtes dimpression"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Achemine les tâches dimpression des imprimantes non Bambu via les agents de plugin dimprimante au lieu du flux classique denvoi vers lhôte dimpression.\n"
"Lorsque cette option est désactivée, OrcaSlicer utilise lancien comportement de lhôte dimpression."
msgid "Experimental Features"
msgstr "Fonctionnalités expérimentales"
@@ -9472,9 +9532,25 @@ msgstr "Préréglage utilisateur"
msgid "Preset Inside Project"
msgstr "Préréglage intégré au projet"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Copie dans ce préréglage toutes les valeurs héritées du préréglage parent et supprime le lien dhéritage. Les préréglages compatibles uniquement avec le parent peuvent devenir incompatibles."
msgid "Detach from parent"
msgstr "Détacher du parent"
# AI Translated
msgid "Unique preset"
msgstr "Préréglage unique"
# AI Translated
msgid "Parent preset"
msgstr "Préréglage parent"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Ce préréglage nhérite daucun autre préréglage."
msgid "Name is unavailable."
msgstr "Le nom n'est pas disponible."
@@ -10211,27 +10287,11 @@ msgstr "Voulez-vous vraiment activer cette option ?"
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 "Les motifs de remplissage sont généralement conçus pour gérer la rotation automatiquement afin d'assurer une impression correcte et d'atteindre les effets souhaités (ex. : Gyroïde, Cubique). La rotation du motif de remplissage clairsemé actuel peut entraîner un support insuffisant. Veuillez procéder avec précaution et vérifier soigneusement tout problème d'impression potentiel. Voulez-vous vraiment activer cette option ?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"La hauteur de couche est trop faible.\n"
"Elle sera définie à min_layer_height\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "La hauteur de la couche dépasse la limite fixée dans Paramètres de limprimante -> Extrudeur -> Limites de la hauteur de la couche, ce qui peut entraîner des problèmes de qualité dimpression."
msgid "Adjust to the set range automatically?\n"
msgstr "Sajuster automatiquement à la plage définie ?\n"
msgid "Adjust"
msgstr "Ajuster"
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 "Fonction expérimentale : Rétracter et couper le filament à une plus grande distance lors des changements de filament afin de minimiser le rinçage. Bien que cela puisse réduire considérablement le rinçage, cela peut également augmenter le risque de bouchage des buses ou dautres complications dimpression."
msgstr "Fonction expérimentale : Rétracter et couper le filament à une plus grande distance lors des changements de filament afin de minimiser la purge. Bien que cela puisse réduire considérablement la purge, cela peut également augmenter le risque de bouchage des buses ou dautres complications dimpression."
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 "Fonction expérimentale : Rétracter et couper le filament à une plus grande distance lors des changements de filament afin de minimiser laffleurement. Bien que cela puisse réduire sensiblement laffleurement, cela peut également augmenter le risque dobstruction des buses ou dautres complications dimpression. Veuillez utiliser le dernier micrologiciel de limprimante."
msgstr "Fonction expérimentale : Rétracter et couper le filament à une plus grande distance lors des changements de filament afin de minimiser la purge. Bien que cela puisse réduire sensiblement la purge, cela peut également augmenter le risque dobstruction des buses ou dautres complications dimpression. Veuillez utiliser le dernier micrologiciel de limprimante."
msgid ""
"When recording timelapse without toolhead, it is recommended to add a \"Timelapse Wipe Tower\" \n"
@@ -10422,6 +10482,9 @@ msgstr "Mots clés réservés trouvés"
msgid "Setting Overrides"
msgstr "Forçage des réglages"
msgid "Retraction when switching material"
msgstr "Rétraction lors du changement de matériau"
msgid "Basic information"
msgstr "Informations de base"
@@ -10548,6 +10611,12 @@ msgstr "Profils de traitement compatibles"
msgid "Printable space"
msgstr "Espace imprimable"
msgid "Printer Agent"
msgstr "Agent d'imprimante"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Sélectionner l'implémentation de l'agent réseau pour la communication avec l'imprimante. Les agents disponibles sont enregistrés au démarrage."
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10673,9 +10742,6 @@ msgstr "Limites de hauteur de couche"
msgid "Z-Hop"
msgstr "Saut en Z"
msgid "Retraction when switching material"
msgstr "Rétraction lors du changement de matériau"
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
"\n"
@@ -12010,6 +12076,10 @@ msgstr " est trop proche d'une zone d'exclusion. Cela va entraîner des collisio
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " est trop proche de la zone de détection d'agglomération, et des collisions seront causées.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " est partiellement en dehors de la zone imprimable et ne peut pas être imprimé.\n"
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."
msgstr "Les températures de buse sélectionnées sont incompatibles. La température de buse de chaque filament doit se situer dans la plage de température de buse recommandée des autres filaments. Sinon, un bouchage de la buse ou des dommages à limprimante peuvent survenir."
@@ -12323,9 +12393,6 @@ msgstr "Utiliser le 3MF au lieu du G-code"
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 "Activez ceci si limprimante accepte un fichier 3MF comme tâche dimpression. Lorsque cette option est activée, Orca Slicer envoie le fichier découpé au format .gcode.3mf au lieu dun simple fichier .gcode."
msgid "Printer Agent"
msgstr "Agent d'imprimante"
msgid "Select the network agent implementation for printer communication."
msgstr "Sélectionner l'implémentation de l'agent réseau pour la communication avec l'imprimante."
@@ -12689,7 +12756,7 @@ msgstr ""
"Si réglée à 0, la largeur de ligne correspond à celle du remplissage plein interne."
msgid "Internal bridge flow ratio"
msgstr "Ratio de débit du pont interne"
msgstr "Rapport de débit du pont interne"
msgid ""
"This value governs the thickness of the internal bridge layer. This is the first layer over sparse infill so increasing it may increase strength and upper layer quality.\n"
@@ -12729,13 +12796,13 @@ msgstr ""
"Le débit réel du remplissage solide inférieur utilisé est calculé en multipliant cette valeur par le rapport de débit du filament et, sil est défini, par le rapport de débit de lobjet."
msgid "Set other flow ratios"
msgstr "Définir d'autres ratios de débit"
msgstr "Définir d'autres rapports de débit"
msgid "Change flow ratios for other extrusion path types."
msgstr "Modifier les ratios de débit pour d'autres types de chemin d'extrusion."
msgstr "Modifier les rapports de débit pour d'autres types de chemin d'extrusion."
msgid "First layer flow ratio"
msgstr "Ratio de débit de la première couche"
msgstr "Rapport de débit de la première couche"
msgid ""
"This factor affects the amount of material on the first layer for the extrusion path roles listed in this section.\n"
@@ -12744,10 +12811,10 @@ msgid ""
msgstr ""
"Ce facteur affecte la quantité de matériau sur la première couche pour les rôles de chemin d'extrusion listés dans cette section.\n"
"\n"
"Pour la première couche, le ratio de débit réel pour chaque rôle de chemin (n'affecte pas les bordures et les jupes) sera multiplié par cette valeur."
"Pour la première couche, le rapport de débit réel pour chaque rôle de chemin (n'affecte pas les bordures et les jupes) sera multiplié par cette valeur."
msgid "Outer wall flow ratio"
msgstr "Ratio de débit de la paroi extérieure"
msgstr "Rapport de débit de la paroi extérieure"
msgid ""
"This factor affects the amount of material for outer walls.\n"
@@ -12756,10 +12823,10 @@ msgid ""
msgstr ""
"Ce facteur affecte la quantité de matériau pour les parois extérieures.\n"
"\n"
"Le débit réel de la paroi extérieure est calculé en multipliant cette valeur par le ratio de débit du filament, et si défini, le ratio de débit de l'objet."
"Le débit réel de la paroi extérieure est calculé en multipliant cette valeur par le rapport de débit du filament, et si défini, le rapport de débit de l'objet."
msgid "Inner wall flow ratio"
msgstr "Ratio de débit de la paroi intérieure"
msgstr "Rapport de débit de la paroi intérieure"
msgid ""
"This factor affects the amount of material for inner walls.\n"
@@ -12768,10 +12835,10 @@ msgid ""
msgstr ""
"Ce facteur affecte la quantité de matériau pour les parois intérieures.\n"
"\n"
"Le débit réel de la paroi intérieure est calculé en multipliant cette valeur par le ratio de débit du filament, et si défini, le ratio de débit de l'objet."
"Le débit réel de la paroi intérieure est calculé en multipliant cette valeur par le rapport de débit du filament, et si défini, le rapport de débit de l'objet."
msgid "Overhang flow ratio"
msgstr "Ratio de débit de surplomb"
msgstr "Rapport de débit de surplomb"
msgid ""
"This factor affects the amount of material for overhangs.\n"
@@ -12780,10 +12847,10 @@ msgid ""
msgstr ""
"Ce facteur affecte la quantité de matériau pour les surplombs.\n"
"\n"
"Le débit réel de surplomb est calculé en multipliant cette valeur par le ratio de débit du filament, et si défini, le ratio de débit de l'objet."
"Le débit réel de surplomb est calculé en multipliant cette valeur par le rapport de débit du filament, et si défini, le rapport de débit de l'objet."
msgid "Sparse infill flow ratio"
msgstr "Ratio de débit du remplissage clairsemé"
msgstr "Rapport de débit du remplissage clairsemé"
msgid ""
"This factor affects the amount of material for sparse infill.\n"
@@ -12792,10 +12859,10 @@ msgid ""
msgstr ""
"Ce facteur affecte la quantité de matériau pour le remplissage clairsemé.\n"
"\n"
"Le débit réel du remplissage clairsemé est calculé en multipliant cette valeur par le ratio de débit du filament, et si défini, le ratio de débit de l'objet."
"Le débit réel du remplissage clairsemé est calculé en multipliant cette valeur par le rapport de débit du filament, et si défini, le rapport de débit de l'objet."
msgid "Internal solid infill flow ratio"
msgstr "Ratio de débit du remplissage solide interne"
msgstr "Rapport de débit du remplissage solide interne"
msgid ""
"This factor affects the amount of material for internal solid infill.\n"
@@ -12804,10 +12871,10 @@ msgid ""
msgstr ""
"Ce facteur affecte la quantité de matériau pour le remplissage solide interne.\n"
"\n"
"Le débit réel du remplissage solide interne est calculé en multipliant cette valeur par le ratio de débit du filament, et si défini, le ratio de débit de l'objet."
"Le débit réel du remplissage solide interne est calculé en multipliant cette valeur par le rapport de débit du filament, et si défini, le rapport de débit de l'objet."
msgid "Gap fill flow ratio"
msgstr "Ratio de débit du remplissage des espaces"
msgstr "Rapport de débit du remplissage des espaces"
msgid ""
"This factor affects the amount of material for filling the gaps.\n"
@@ -12816,10 +12883,10 @@ msgid ""
msgstr ""
"Ce facteur affecte la quantité de matériau pour le remplissage des espaces.\n"
"\n"
"Le débit réel du remplissage des espaces est calculé en multipliant cette valeur par le ratio de débit du filament, et si défini, le ratio de débit de l'objet."
"Le débit réel du remplissage des espaces est calculé en multipliant cette valeur par le rapport de débit du filament, et si défini, le rapport de débit de l'objet."
msgid "Support flow ratio"
msgstr "Ratio de débit des supports"
msgstr "Rapport de débit des supports"
msgid ""
"This factor affects the amount of material for support.\n"
@@ -12828,10 +12895,10 @@ msgid ""
msgstr ""
"Ce facteur affecte la quantité de matériau pour les supports.\n"
"\n"
"Le débit réel des supports est calculé en multipliant cette valeur par le ratio de débit du filament, et si défini, le ratio de débit de l'objet."
"Le débit réel des supports est calculé en multipliant cette valeur par le rapport de débit du filament, et si défini, le rapport de débit de l'objet."
msgid "Support interface flow ratio"
msgstr "Ratio de débit de l'interface de support"
msgstr "Rapport de débit de l'interface de support"
msgid ""
"This factor affects the amount of material for the support interface.\n"
@@ -12840,7 +12907,7 @@ msgid ""
msgstr ""
"Ce facteur affecte la quantité de matériau pour l'interface de support.\n"
"\n"
"Le débit réel de l'interface de support est calculé en multipliant cette valeur par le ratio de débit du filament, et si défini, le ratio de débit de l'objet."
"Le débit réel de l'interface de support est calculé en multipliant cette valeur par le rapport de débit du filament, et si défini, le rapport de débit de l'objet."
msgid "Precise wall"
msgstr "Parois précises"
@@ -13000,9 +13067,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "Vitesse des ponts internes. Si la valeur est exprimée en pourcentage, elle sera calculée sur la base de la vitesse du pont. La valeur par défaut est 150%."
msgid "Brim width"
msgstr "Largeur de la bordure"
msgid "This is the distance from the model to the outermost brim line."
msgstr "Distance du modèle à la ligne de bord la plus externe"
@@ -13043,10 +13107,10 @@ 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 ""
"Lorsqu'il est activé, le bordure est aligné avec la géométrie du périmètre de la première couche après l'application de la compensation du pied d'éléphant.\n"
"Cette option est destinée aux cas où la compensation du pied d'éléphant modifie considérablement lempreinte de la première couche.\n"
"Lorsqu'il est activé, la bordure est alignée avec la géométrie du périmètre de la première couche après l'application de la compensation de la patte d'éléphant.\n"
"Cette option est destinée aux cas où la compensation de la patte d'éléphant modifie considérablement lempreinte de la première couche.\n"
"\n"
"Si votre configuration actuelle fonctionne déjà bien, son activation peut être inutile et peut provoquer la fusion du bordure avec les couches supérieures."
"Si votre configuration actuelle fonctionne déjà bien, son activation peut être inutile et peut provoquer la fusion de la bordure avec les couches supérieures."
msgid "Combine brims"
msgstr "Combiner les bordures"
@@ -13082,6 +13146,14 @@ msgstr ""
"La géométrie sera décimée avant de détecter les angles vifs. Ce paramètre indique la longueur minimale de l’écart pour la décimation.\n"
"0 pour désactiver"
# AI Translated
msgid "Brim ears outer only"
msgstr "Bordure à oreilles sur le contour extérieur uniquement"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Génère des oreilles de souris uniquement sur le contour extérieur du modèle, en excluant les trous et les sections fermées."
msgid "upward compatible machine"
msgstr "machine à compatibilité ascendante"
@@ -13643,7 +13715,7 @@ msgid ""
msgstr ""
"Le matériau peut présenter un changement volumétrique après le passage de l’état fondu à l’état cristallin. Ce paramètre modifie proportionnellement tous les débits dextrusion de ce filament dans le G-code. La valeur recommandée est comprise entre 0,95 et 1,05. Vous pouvez peut-être ajuster cette valeur pour obtenir une belle surface plate lorsquil y a un léger débordement ou un sous-débordement.\n"
"\n"
"Le ratio de débit de lobjet final est cette valeur multipliée par le ratio de débit du filament."
"Le rapport de débit de lobjet final est cette valeur multipliée par le rapport de débit du filament."
msgid "Enable pressure advance"
msgstr "Activer la Pressure Advance"
@@ -14236,6 +14308,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "Gyroïde"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Facteur de lissage du remplissage"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Contrôle le degré darrondi des angles du remplissage. 0% conserve le tracé anguleux dorigine, tandis que 100% produit les courbes les plus amples possibles entre les lignes de remplissage adjacentes."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "Il s'agit de l'accélération de la surface supérieure du remplissage. Utiliser une valeur plus petite pourrait améliorer la qualité de la surface supérieure"
@@ -14774,6 +14854,14 @@ msgstr "Avec quel type de G-code l'imprimante est-elle compatible."
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "Omettre le bloc de configuration du G-code"
# AI Translated
msgid "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."
msgstr "N’écrit pas le CONFIG_BLOCK (les paires clé/valeur de la configuration du logiciel de découpe) dans le fichier G-code. Cela peut aider avec les imprimantes dont le firmware plante lors de lanalyse de ces lignes de commentaire (par ex. Anycubic go-klipper). Remarque : le fichier G-code ne contiendra plus les réglages du logiciel de découpe, sa réimportation dans OrcaSlicer ne restaurera donc pas la configuration."
msgid "Pellet Modded Printer"
msgstr "Imprimante à pellets"
@@ -15821,6 +15909,14 @@ msgstr "Rétraction longue lors du changement d'extrudeur"
msgid "Retraction distance when extruder change"
msgstr "Distance de rétraction lors du changement d'extrudeur"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "Longueur de rétraction (Changement doutil)"
# 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 "Lorsque la rétraction est déclenchée avant un changement doutil, le filament est rétracté de la quantité spécifiée (la longueur est mesurée sur le filament brut, avant son entrée dans lextrudeur)."
msgid "Z-hop height"
msgstr "Hauteur du saut en Z"
@@ -15914,6 +16010,10 @@ msgstr "Longueur supplémentaire"
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 "Lorsque la rétraction est compensée après le mouvement de déplacement, lextrudeuse poussera cette quantité supplémentaire de filament. Ce paramètre est rarement nécessaire."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "Longueur supplémentaire à la reprise (Changement doutil)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "Lorsque la rétraction est compensée après le changement doutil, lextrudeur poussera cette quantité supplémentaire de filament."
@@ -16012,11 +16112,11 @@ msgstr ""
"Si langle maximal à lintérieur de la boucle périmétrique dépasse cette valeur (indiquant labsence dangles vifs), une couture en biseau sera utilisée. La valeur par défaut est de 155°."
msgid "Conditional overhang threshold"
msgstr "Seuil de dépassement conditionnel"
msgstr "Seuil de surplomb conditionnel"
#, 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 "Cette option détermine le seuil de surplomb pour lapplication des coutures en écharpe. Si la partie non soutenue du périmètre est inférieure à ce seuil, des coutures en biseau seront appliquées. Le seuil par défaut est fixé à 40 % de la largeur de la paroi extérieure. Pour des raisons de performance, le degré de surplomb est estimé."
msgstr "Cette option détermine le seuil de surplomb pour lapplication des coutures en biseau. Si la partie non soutenue du périmètre est inférieure à ce seuil, des coutures en biseau seront appliquées. Le seuil par défaut est fixé à 40 % de la largeur de la paroi extérieure. Pour des raisons de performance, le degré de surplomb est estimé."
msgid "Scarf joint speed"
msgstr "Vitesse de la couture en biseau"
@@ -16025,7 +16125,7 @@ msgid "This option sets the printing speed for scarf joints. It is recommended t
msgstr "Cette option définit la vitesse dimpression des coutures en biseau. Il est recommandé dimprimer les coutures en biseau à une vitesse lente (moins de 100 mm/s). Il est également conseillé dactiver loption « Lissage de la vitesse dextrusion » si la vitesse définie varie de manière significative par rapport à la vitesse des parois extérieures ou intérieures. Si la vitesse spécifiée ici est supérieure à la vitesse des parois extérieures ou intérieures, limprimante prendra par défaut la plus lente des deux vitesses. Lorsquelle est spécifiée sous forme de pourcentage (par exemple, 80 %), la vitesse est calculée sur la base de la vitesse de la paroi extérieure ou intérieure. La valeur par défaut est fixée à 100 %."
msgid "Scarf joint flow ratio"
msgstr "Ratio de débit de la couture en biseau"
msgstr "Rapport de débit de la couture en biseau"
msgid "This factor affects the amount of material for scarf joints."
msgstr "Ce facteur influe sur la quantité de matériau pour les coutures en biseau."
@@ -16234,7 +16334,7 @@ msgstr "Taux de débit de la finition en spirale"
#, 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 "Définit le ratio de débit de finition lors de la fin de la spirale. Normalement, la transition de la spirale fait passer le taux de débit de 100% à 0% au cours de la dernière boucle, ce qui peut dans certains cas entraîner une sous-extrusion à la fin de la spirale."
msgstr "Définit le rapport de débit de finition lors de la fin de la spirale. Normalement, la transition de la spirale fait passer le taux de débit de 100% à 0% au cours de la dernière boucle, ce qui peut dans certains cas entraîner une sous-extrusion à la fin de la spirale."
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 "Si le mode fluide ou traditionnel est sélectionné, une vidéo en timelapse sera générée pour chaque impression. À chaque couche imprimée, un instantané est pris avec la caméra intégrée. Tous ces instantanés seront assemblés dans une vidéo timelapse une fois l'impression terminée. Si le mode lisse est sélectionné, l'extrudeur se déplace vers la goulotte d'évacuation à chaque couche imprimée, puis prend un cliché. Étant donné que le filament fondu peut s'échapper de la buse pendant la prise de vue, une tour damorçage est requise en mode lisse pour essuyer la buse."
@@ -16326,6 +16426,14 @@ msgstr "Changement doutil sur la tour dessuyage"
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 "Force la tête doutil à se déplacer vers la tour dessuyage avant d’émettre la commande de changement doutil (Tx). Pertinent uniquement pour les imprimantes multi-extrudeurs (à têtes doutil multiples) utilisant une tour dessuyage de type 2. Par défaut, Orca omet ce déplacement sur les machines à têtes doutil multiples car le firmware gère le changement de tête, ce qui peut entraîner l’émission de la commande Tx au-dessus de la pièce imprimée. Activez cette option si vous préférez que le changement doutil soit toujours émis au-dessus de la tour dessuyage."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "Attendre la température sur la tour dessuyage"
# 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 "Prend le nouvel outil sans attendre quil atteigne la température dimpression, se déplace vers la tour dessuyage et y attend la température, juste avant la purge. Le suintement dû à la chauffe se dépose sur la tour plutôt que sur le modèle, et le déplacement se superpose à la chauffe. Uniquement pertinent pour les imprimantes multi-extrudeurs (multi-têtes) utilisant une tour dessuyage de type 2. Le firmware ou la macro de changement doutil ne doivent pas attendre la température eux-mêmes. Lorsque cette option est désactivée, lattente de température est émise juste après la commande de changement doutil."
msgid "No sparse layers (beta)"
msgstr "Pas de couches éparses (beta)"
@@ -18217,7 +18325,7 @@ msgid "Record Factor"
msgstr "Enregistrer le facteur"
msgid "We found the best flow ratio for you"
msgstr "Nous avons trouvé le meilleur ratio de débit pour vous"
msgstr "Nous avons trouvé le meilleur rapport de débit pour vous"
msgid "Flow Ratio"
msgstr "Rapport de débit"
@@ -19542,9 +19650,6 @@ msgstr "Imprimante Physique"
msgid "Print Host upload"
msgstr "Envoi vers limprimante hôte"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Sélectionner l'implémentation de l'agent réseau pour la communication avec l'imprimante. Les agents disponibles sont enregistrés au démarrage."
msgid "Select a Flashforge printer"
msgstr "Sélectionner une imprimante Flashforge"
@@ -20392,9 +20497,6 @@ msgstr "Un événement inattendu sest produit lors de la connexion, veuillez
msgid "User canceled."
msgstr "Lutilisateur a annulé."
msgid "Head diameter"
msgstr "Diamètre de la tête"
msgid "Max angle"
msgstr "Angle maximal"
@@ -21176,6 +21278,22 @@ msgstr ""
"Éviter la déformation\n"
"Saviez-vous que lors de limpression de matériaux susceptibles de se déformer, tels que lABS, une augmentation appropriée de la température du plateau chauffant peut réduire la probabilité de déformation?"
#~ msgid ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "La hauteur de couche est trop faible.\n"
#~ "Elle sera définie à min_layer_height\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "La hauteur de la couche dépasse la limite fixée dans Paramètres de limprimante -> Extrudeur -> Limites de la hauteur de la couche, ce qui peut entraîner des problèmes de qualité dimpression."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "Sajuster automatiquement à la plage définie ?\n"
#~ msgid "Head diameter"
#~ msgstr "Diamètre de la tête"
#~ msgid "Print order within a single layer."
#~ msgstr "Ordre dimpression au sein dune même couche"
+155 -37
View File
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"Language: hu\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -4739,6 +4739,23 @@ msgstr "A kamra aktuális hőmérséklete magasabb az anyag biztonságos hőmér
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "A minimális kamrahőmérséklet (%d℃) magasabb a cél kamrahőmérsékletnél (%d℃). A minimális érték az a küszöb, amelynél a nyomtatás elindul, miközben a kamra tovább melegszik a célérték felé, ezért nem haladhatja meg azt. Az érték a célértékre lesz korlátozva."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "A rétegmagasság túl kicsi. A minimumra lesz állítva (%g mm)."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "A rétegmagasság a Nyomtatóbeállítások -> Extruder -> Rétegmagasság limitek menüpontban megadott határértékeken kívül esik, ez minőségbeli problémákat okozhat a nyomtatás során."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "Szeretnéd automatikusan a határértékre (%g mm) igazítani?"
msgid "Adjust"
msgstr "Módosítás"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4858,6 +4875,13 @@ msgstr ""
"Igen - Engedélyezd az Arachne falgenerátort\n"
"Nem - Tiltsd le az Arachne falgenerátort, majd állítsd a barázdált felületet [Eltolás] módra"
# AI Translated
msgid "Brim ear radius"
msgstr "Peremfül sugara"
msgid "Brim width"
msgstr "Perem szélessége"
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 é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."
@@ -5112,6 +5136,14 @@ msgstr "Nem sikerült létrehozni a kalibrációs G-kódot"
msgid "Calibration error"
msgstr "Kalibrációs hiba"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "Ez a nyomtató nincs felszerelve a vezérlőelemhez szükséges hardverrel."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Ez a vezérlőelem nem támogatott ezen a nyomtatón."
# AI Translated
msgid "Network unavailable"
msgstr "A hálózat nem érhető el"
@@ -5971,7 +6003,7 @@ msgstr "Térfogat:"
msgid "Size:"
msgstr "Méret:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "G-kód útvonalütközés található a(z) %d. rétegen, Z = %.2lfmm. Helyezd távolabb egymástól az ütköző objektumokat (%s <-> %s)."
@@ -6153,6 +6185,10 @@ msgstr "Több eszköz"
msgid "Project"
msgstr "Projekt"
# AI Translated
msgid "Device (Web)"
msgstr "Nyomtató (Web)"
msgid "Yes"
msgstr "Igen"
@@ -8244,19 +8280,19 @@ 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"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ %s kihagyva: azonos fájl.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ %s kihagyva: a fájl nem létezik.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ %s kihagyva: a csere sikertelen.\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔%s lecserélve.\n"
@@ -8993,6 +9029,18 @@ msgstr "Ezzel az opcióval egyszerre több eszközre küldhetsz feladatot és t
msgid "Pop up to select filament grouping mode"
msgstr "Felugró ablak a filamentcsoportosítási mód kiválasztásához"
# AI Translated
msgid "Visible plugin pages"
msgstr "Látható bővítményoldalak"
# AI Translated
msgid "pages"
msgstr "oldal"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "A rögzített fülként megjelenő bővítményoldalak száma; a fennmaradó oldalak az utolsó fülön lenyíló listába kerülnek."
msgid "Behaviour"
msgstr "Viselkedés"
@@ -9362,6 +9410,18 @@ msgstr "Nem támogatott beállítások megjelenítése"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "Megjeleníti a nem kompatibilis vagy nem támogatott beállításokat a nyomtató- és filamentlegördülő listákban. Ezek a beállítások nem választhatók ki."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Kísérleti) Nyomtatóügynökök használata nyomtatókiszolgálók helyett"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"A nem Bambu nyomtatók nyomtatási feladatait a nyomtató bővítményügynökein keresztül továbbítja a klasszikus nyomtatókiszolgálóra való feltöltés helyett.\n"
"Ha ki van kapcsolva, az OrcaSlicer a régi nyomtatókiszolgáló-viselkedést használja."
# AI Translated
msgid "Experimental Features"
msgstr "Kísérleti funkciók"
@@ -9632,9 +9692,25 @@ msgstr "Felhasználói beállítás"
msgid "Preset Inside Project"
msgstr "Projekt a beállításon belül"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Az összes örökölt értéket átmásolja a szülő előbeállításból ebbe az előbeállításba, és megszünteti az öröklési kapcsolatot. A csak a szülővel kompatibilis előbeállítások támogatása megszűnhet."
msgid "Detach from parent"
msgstr "Leválasztás a szülőről"
# AI Translated
msgid "Unique preset"
msgstr "Önálló előbeállítás"
# AI Translated
msgid "Parent preset"
msgstr "Szülő előbeállítás"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Ez az előbeállítás nem örököl másik előbeállításból."
msgid "Name is unavailable."
msgstr "A név nem elérhető."
@@ -10376,22 +10452,6 @@ 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 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"
"It will set to min_layer_height\n"
msgstr ""
"A rétegmagasság túl kicsi.\n"
"A rendszer a min_layer_height értékre állítja.\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "A rétegmagasság meghaladja a Nyomtatóbeállítások -> Extruder -> Rétegmagasság limitek menüpontban megadott értéket, ez minőségbeli problémákat okozhat a nyomtatás során."
msgid "Adjust to the set range automatically?\n"
msgstr "Szeretnéd az értéket automatikusan a beállított tartományhoz igazítani?\n"
msgid "Adjust"
msgstr "Módosítás"
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 "Kísérleti funkció: Filamentcsere közben nagyobb távolságon történő visszahúzás és elvágás az öblítés minimalizálása érdekében. Bár ez jelentősen csökkentheti az öblítés mértékét, növelheti a fúvóka eltömődésének vagy más nyomtatási problémák kockázatát."
@@ -10587,6 +10647,9 @@ msgstr "Foglalt kulcsszavakat találtunk"
msgid "Setting Overrides"
msgstr "Beállítások felülbírálása"
msgid "Retraction when switching material"
msgstr "Visszahúzás anyagváltáskor"
msgid "Basic information"
msgstr "Alapinformációk"
@@ -10720,6 +10783,12 @@ msgstr "Kompatibilis folyamatprofilok"
msgid "Printable space"
msgstr "Nyomtatási terület"
msgid "Printer Agent"
msgstr "Nyomtatóügynök"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
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."
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10845,9 +10914,6 @@ msgstr "Rétegmagasság limitek"
msgid "Z-Hop"
msgstr "Z-emelés"
msgid "Retraction when switching material"
msgstr "Visszahúzás anyagváltáskor"
# AI Translated
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
@@ -12200,6 +12266,10 @@ msgstr " túl közel van a tiltott területhez, a nyomtatás során előfordulha
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " túl közel van a csomósodásészlelési területhez, és ez ütközést fog okozni.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " részben a nyomtatható területen kívül esik, ezért nem nyomtatható ki.\n"
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."
msgstr "A kiválasztott fúvóka hőmérsékletek nem kompatibilisek. Mindegyik filament fúvóka hőmérsékletének a többi filament ajánlott fúvóka hőmérsékleti tartományába kell esnie. Ellenkező esetben a fúvóka eltömődhet vagy a nyomtató megsérülhet."
@@ -12530,9 +12600,6 @@ msgstr "3MF használata G-kód helyett"
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 "Kapcsold be, ha a nyomtató 3MF fájlt fogad el nyomtatási feladatként. Bekapcsolva az Orca Slicer a szeletelt fájlt .gcode.3mf formátumban küldi el egyszerű .gcode fájl helyett."
msgid "Printer Agent"
msgstr "Nyomtatóügynök"
msgid "Select the network agent implementation for printer communication."
msgstr "Válaszd ki a nyomtató kommunikációjához használt hálózati ügynök implementációját."
@@ -13220,9 +13287,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "A belső hidak sebessége. Ha az érték százalékban van megadva, a bridge_speed alapján lesz kiszámítva. Az alapértelmezett érték 150%."
msgid "Brim width"
msgstr "Perem szélessége"
msgid "This is the distance from the model to the outermost brim line."
msgstr "A modell és a legkülső peremvonal közötti távolság"
@@ -13302,6 +13366,14 @@ msgstr ""
"Az éles szögek észlelése előtt a geometria egyszerűsítve lesz. Ez a paraméter a leegyszerűsítésnél figyelembe vett eltérés minimális hosszát adja meg.\n"
"0 értékkel kikapcsolható."
# AI Translated
msgid "Brim ears outer only"
msgstr "Peremfülek csak kívül"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Egérfüleket csak a modell külső kontúrján hoz létre, a furatokat és a zárt szakaszokat kihagyva."
msgid "upward compatible machine"
msgstr "felfelé kompatibilis gép"
@@ -14475,6 +14547,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "Gyroid"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Kitöltés simítási tényezője"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Azt szabályozza, hogy a kitöltés sarkai mennyire legyenek lekerekítve. A 0% megtartja az eredeti éles útvonalat, a 100% pedig a lehető legnagyobb íveket hozza létre a szomszédos kitöltővonalak között."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "A felső felületi kitöltés gyorsulása. Alacsonyabb érték használata javíthatja a felső felület minőségét"
@@ -15017,6 +15097,14 @@ msgstr "Milyen G-kóddal kompatibilis a nyomtató."
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "G-code konfigurációs blokk kihagyása"
# AI Translated
msgid "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."
msgstr "Nem írja a CONFIG_BLOCK blokkot (a szeletelő beállításainak kulcs/érték párjait) a G-code fájlba. Ez segíthet azoknál a nyomtatóknál, amelyek firmware-e összeomlik ezeknek a megjegyzéssoroknak a feldolgozásakor (pl. Anycubic go-klipper). Megjegyzés: a G-code fájl így már nem tartalmazza a szeletelő beállításait, ezért az OrcaSlicerbe való visszaimportálás nem állítja vissza a konfigurációt."
msgid "Pellet Modded Printer"
msgstr "Granulátumos módosított nyomtató"
@@ -16079,6 +16167,14 @@ msgstr "Hosszú visszahúzás extruderváltáskor"
msgid "Retraction distance when extruder change"
msgstr "Visszahúzási távolság extruderváltáskor"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "Visszahúzás hossza (Eszközváltás)"
# 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 "Amikor a visszahúzás eszközváltás előtt aktiválódik, a filament a megadott értékkel húzódik vissza (a hossz a nyers filamenten mérve, mielőtt az az extruderbe kerülne)."
msgid "Z-hop height"
msgstr "Z-emelés magassága"
@@ -16172,6 +16268,10 @@ msgstr "Extra hossz újraindításkor"
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 "Amikor a visszahúzás kompenzálásra kerül utazási mozgás után, az extruder ezt a további szálmennyiséget nyomja előre. Erre a beállításra ritkán van szükség."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "Extra hossz újraindításkor (Eszközváltás)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "Amikor a visszahúzás kompenzálásra kerül szerszámváltás után, az extruder ezt a további szálmennyiséget nyomja előre."
@@ -16588,6 +16688,14 @@ 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 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."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "Várakozás a hőmérsékletre a törlőtornyon"
# 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 "Felveszi az új szerszámot anélkül, hogy megvárná a nyomtatási hőmérséklet elérését, a törlőtoronyhoz áll, és ott várja meg a hőmérsékletet, közvetlenül az öblítés előtt. A felfűtés közben kiszivárgó anyag a toronyra kerül a modell helyett, a mozgás pedig átfedésben van a fűtéssel. Csak több extruderes (több szerszámfejes) nyomtatóknál releváns, amelyek 2-es típusú törlőtornyot használnak. A firmware vagy a szerszámváltó makró nem várhat magától a hőmérsékletre. Ha ki van kapcsolva, a hőmérsékletre várakozás közvetlenül a szerszámváltó parancs után kerül kiadásra."
msgid "No sparse layers (beta)"
msgstr "Nincsenek ritka rétegek (béta)"
@@ -19847,9 +19955,6 @@ msgstr "Fizikai nyomtató"
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ó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"
msgstr "Válassz egy Flashforge nyomtatót"
@@ -20791,9 +20896,6 @@ msgstr "Bejelentkezés közben váratlan hiba történt, próbáld újra."
msgid "User canceled."
msgstr "Felhasználó által megszakítva."
msgid "Head diameter"
msgstr "Fej átmérő"
msgid "Max angle"
msgstr "Maximális szög"
@@ -21607,6 +21709,22 @@ 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 ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "A rétegmagasság túl kicsi.\n"
#~ "A rendszer a min_layer_height értékre állítja.\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "A rétegmagasság meghaladja a Nyomtatóbeállítások -> Extruder -> Rétegmagasság limitek menüpontban megadott értéket, ez minőségbeli problémákat okozhat a nyomtatás során."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "Szeretnéd az értéket automatikusan a beállított tartományhoz igazítani?\n"
#~ msgid "Head diameter"
#~ msgstr "Fej átmérő"
#~ msgid "Print order within a single layer."
#~ msgstr "Nyomtatási sorrend egyetlen rétegen belül."
+155 -37
View File
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
@@ -4741,6 +4741,23 @@ msgstr "L'attuale temperatura della camera è superiore alla temperatura di sicu
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "La temperatura minima della camera (%d℃) è superiore alla temperatura target della camera (%d℃). Il valore minimo è la soglia alla quale inizia la stampa mentre la camera continua a riscaldarsi verso il target, quindi non dovrebbe superarlo. Verrà limitato al valore target."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "L'altezza dello strato è troppo piccola. Sarà impostata al valore minimo (%g mm)."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "L'altezza dello strato è fuori dai limiti impostati in Impostazioni stampante -> Estrusore -> Limiti Altezza Strato, ciò potrebbe causare problemi di qualità di stampa."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "Regolarla automaticamente al limite (%g mm)?"
msgid "Adjust"
msgstr "Regola"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4860,6 +4877,13 @@ msgstr ""
"Sì - Abilita generatore di pareti Arachne\n"
"No - Disabilita generatore di pareti Arachne e imposta la modalità [Spostamento] della Superficie ruvida"
# AI Translated
msgid "Brim ear radius"
msgstr "Raggio della tesa ad orecchio"
msgid "Brim width"
msgstr "Larghezza tesa"
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 "La modalità spirale funziona solo quando i perimetri sono 1, il supporto è disabilitato, il rilevamento degli ammassi tramite sondaggio è disabilitato, gli strati superiori della shell sono 0, la densità del riempimento sparso è 0 e il tipo di timelapse è tradizionale."
@@ -5114,6 +5138,14 @@ msgstr "Impossibile generare G-code di calibrazione"
msgid "Calibration error"
msgstr "Errore di calibrazione"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "Questa stampante non dispone dell'hardware richiesto da questo controllo."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Questo controllo non è supportato su questa stampante."
# AI Translated
msgid "Network unavailable"
msgstr "Rete non disponibile"
@@ -5973,7 +6005,7 @@ msgstr "Volume:"
msgid "Size:"
msgstr "Dimensione:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "Sono stati trovati conflitti di percorsi nel G-code sullo strato %d, Z = %.2lfmm. Si prega di separare gli oggetti in conflitto (%s <-> %s)."
@@ -6154,6 +6186,10 @@ msgstr "Multi-dispositivo"
msgid "Project"
msgstr "Progetto"
# AI Translated
msgid "Device (Web)"
msgstr "Dispositivo (Web)"
msgid "Yes"
msgstr "Sì"
@@ -8244,19 +8280,19 @@ 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"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ Saltato %s: stesso file.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ Saltato %s: il file non esiste.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ Saltato %s: sostituzione fallita.\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ Sostituito %s.\n"
@@ -8995,6 +9031,18 @@ msgstr "Abilitando questa opzione, puoi inviare un'attività a più dispositivi
msgid "Pop up to select filament grouping mode"
msgstr "Popup per selezionare la modalità di raggruppamento filamenti"
# AI Translated
msgid "Visible plugin pages"
msgstr "Pagine dei plugin visibili"
# AI Translated
msgid "pages"
msgstr "pagine"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "Numero di pagine dei plugin mostrate come schede fisse prima che le pagine rimanenti vengano raccolte in un menu a discesa nell'ultima scheda."
msgid "Behaviour"
msgstr "Comportamento"
@@ -9381,6 +9429,18 @@ msgstr "Mostra i profili non supportati"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "Mostra i profili incompatibili/non supportati negli elenchi a discesa di stampante e filamento. Questi profili non possono essere selezionati."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Sperimentale) Usa gli agenti stampante invece degli host di stampa"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Instrada i lavori di stampa delle stampanti non Bambu attraverso gli agenti plugin della stampante invece del classico flusso di caricamento sull'host di stampa.\n"
"Quando è disattivato, OrcaSlicer usa il comportamento legacy dell'host di stampa."
# AI Translated
msgid "Experimental Features"
msgstr "Funzionalità sperimentali"
@@ -9650,9 +9710,25 @@ msgstr "Profilo utente"
msgid "Preset Inside Project"
msgstr "Profilo interno al progetto"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Copia in questo profilo tutti i valori ereditati dal profilo padre e rimuove la relazione di ereditarietà. I profili compatibili solo con il profilo padre potrebbero non essere più supportati."
msgid "Detach from parent"
msgstr "Scollega dal genitore"
# AI Translated
msgid "Unique preset"
msgstr "Profilo unico"
# AI Translated
msgid "Parent preset"
msgstr "Profilo padre"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Questo profilo non eredita da un altro profilo."
msgid "Name is unavailable."
msgstr "Nome non disponibile."
@@ -10392,22 +10468,6 @@ msgstr "Sei sicuro di voler abilitare questa opzione?"
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 "I pattern di riempimento sono generalmente progettati per gestire automaticamente la rotazione per garantire una stampa corretta e ottenere gli effetti desiderati (ad es. Gyroid, Cubico). La rotazione del pattern di riempimento sparso corrente potrebbe portare a un supporto insufficiente. Procedere con cautela e verificare accuratamente eventuali problemi di stampa. Sei sicuro di voler abilitare questa opzione?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"L'altezza dello strato è troppo piccola.\n"
"Sarà impostato su min_layer_height\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "L'altezza dello strato supera il limite in Impostazioni stampante -> Estrusore -> Limiti Altezza Strato. Ciò potrebbe causare problemi di qualità di stampa."
msgid "Adjust to the set range automatically?\n"
msgstr "Regolare automaticamente l'intervallo impostato?\n"
msgid "Adjust"
msgstr "Regola"
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 "Funzionalità sperimentale: ritrazione e taglio del filamento a una distanza maggiore durante i cambi di filamento per ridurre al minimo lo spurgo. Sebbene possa ridurre notevolmente lo spurgo, può anche aumentare il rischio di intasamento degli ugelli o di altre complicazioni di stampa."
@@ -10603,6 +10663,9 @@ msgstr "Parole chiave riservate trovate"
msgid "Setting Overrides"
msgstr "Sovrascrivi impostazioni"
msgid "Retraction when switching material"
msgstr "Retrazione quando si cambia materiale"
msgid "Basic information"
msgstr "Informazioni di base"
@@ -10734,6 +10797,12 @@ msgstr "Profili di processo compatibili"
msgid "Printable space"
msgstr "Spazio di stampa"
msgid "Printer Agent"
msgstr "Agente stampante"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Selezionare l'implementazione dell'agente di rete per la comunicazione con la stampante. Gli agenti disponibili vengono registrati all'avvio."
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10859,9 +10928,6 @@ msgstr "Limiti altezza strati"
msgid "Z-Hop"
msgstr "Sollevamento Z"
msgid "Retraction when switching material"
msgstr "Retrazione quando si cambia materiale"
# AI Translated
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
@@ -12221,6 +12287,10 @@ msgstr " è troppo vicino all'area di esclusione e si verificheranno collisioni.
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " è troppo vicino all'area di rilevamento ammassi e verranno causate collisioni.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " è parzialmente fuori dall'area stampabile e non può essere stampato.\n"
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."
msgstr "Le temperature degli ugelli selezionate sono incompatibili. La temperatura dell'ugello per ciascun filamento deve rientrare nell'intervallo di temperatura consigliato per gli altri filamenti. In caso contrario, potrebbero verificarsi ostruzioni degli ugelli o danni alla stampante."
@@ -12550,9 +12620,6 @@ msgstr "Usa 3MF invece di G-code"
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 "Abilita questa opzione se la stampante accetta un file 3MF come processo di stampa. Quando è abilitata, Orca Slicer invia il file elaborato come .gcode.3mf, invece di un semplice file .gcode."
msgid "Printer Agent"
msgstr "Agente stampante"
msgid "Select the network agent implementation for printer communication."
msgstr "Selezionare l'implementazione dell'agente di rete per la comunicazione con la stampante."
@@ -13239,9 +13306,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "Velocità dei ponti interni. Se il valore è espresso in percentuale, verrà calcolato in base a bridge_speed. Il valore predefinito è 150%."
msgid "Brim width"
msgstr "Larghezza tesa"
msgid "This is the distance from the model to the outermost brim line."
msgstr "Questa è la distanza tra il modello e la linea più esterna della tesa."
@@ -13321,6 +13385,14 @@ msgstr ""
"La geometria verrà decimata prima di rilevare gli spigoli vivi. Questo parametro indica la lunghezza minima dello scostamento per la decimazione.\n"
"0 per disattivare."
# AI Translated
msgid "Brim ears outer only"
msgstr "Tesa ad orecchio solo sul contorno esterno"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Genera gli orecchi di topo solo sul contorno esterno del modello, escludendo fori e sezioni chiuse."
msgid "upward compatible machine"
msgstr "macchina compatibile con versioni successive"
@@ -14495,6 +14567,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "Giroide"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Fattore di arrotondamento del riempimento sparso"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Controlla quanto vengono arrotondati gli angoli del riempimento sparso. 0% mantiene il percorso originale con angoli vivi, mentre 100% produce le curve più ampie possibili tra linee di riempimento adiacenti."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "Accelerazione del riempimento della superficie superiore. L'utilizzo di un valore inferiore può migliorare la qualità della superficie superiore."
@@ -15039,6 +15119,14 @@ msgstr "Con quale tipo di G-code la stampante è compatibile."
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "Ometti il blocco di configurazione del G-code"
# AI Translated
msgid "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."
msgstr "Non scrive il CONFIG_BLOCK (le coppie chiave/valore della configurazione dello slicer) nel file G-code. Può essere utile con stampanti il cui firmware va in crash durante l'analisi di queste righe di commento (ad es. Anycubic go-klipper). Nota: il file G-code non conterrà più le impostazioni dello slicer, quindi reimportandolo in OrcaSlicer la configurazione non verrà ripristinata."
msgid "Pellet Modded Printer"
msgstr "Stampante modificata per granuli"
@@ -16098,6 +16186,14 @@ msgstr "Retrazione lunga al cambio estrusore"
msgid "Retraction distance when extruder change"
msgstr "Distanza di retrazione al cambio estrusore"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "Lunghezza di retrazione (Cambio testina)"
# 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 la retrazione viene attivata prima di un cambio testina, il filamento viene ritirato della quantità specificata (la lunghezza è misurata sul filamento grezzo, prima che entri nell'estrusore)."
msgid "Z-hop height"
msgstr "Altezza sollevamento Z"
@@ -16195,6 +16291,10 @@ msgstr "Lunghezza aggiuntiva in ripresa"
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 la retrazione è compensata dopo uno spostamento, l'estrusore espelle questa quantità aggiuntiva di filamento. Questa impostazione è raramente necessaria."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "Lunghezza aggiuntiva in ripresa (Cambio testina)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "Quando la retrazione è compensata dopo un cambio di testina, l'estrusore espelle questa quantità aggiuntiva di filamento."
@@ -16612,6 +16712,14 @@ msgstr "Cambio utensile sulla torre di spurgo"
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 "Forza la testa di stampa a spostarsi sulla torre di spurgo prima di emettere il comando di cambio utensile (Tx). Rilevante solo per le stampanti multi-estrusore (multi-testa) che utilizzano una torre di spurgo di Tipo 2. Per impostazione predefinita Orca salta lo spostamento sulle macchine multi-testa perché il firmware gestisce il cambio della testa, il che può far sì che il comando Tx venga emesso sopra la parte stampata. Abilita questa opzione se desideri che il cambio utensile venga sempre emesso sopra la torre di spurgo."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "Attendi la temperatura sulla torre di spurgo"
# 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 "Preleva la nuova testina senza attendere che raggiunga la temperatura di stampa, si sposta sulla torre di spurgo e attende lì la temperatura, subito prima dello spurgo. Il trasudo dovuto al riscaldamento finisce sulla torre invece che sul modello, e lo spostamento si sovrappone al riscaldamento. Rilevante solo per stampanti multi-estrusore (multi-testina) che usano una torre di spurgo di tipo 2. Il firmware o la macro di cambio testina non devono attendere la temperatura autonomamente. Quando è disattivato, l'attesa della temperatura viene emessa subito dopo il comando di cambio testina."
msgid "No sparse layers (beta)"
msgstr "Nessuno strato sparso (beta)"
@@ -19865,9 +19973,6 @@ msgstr "Stampante fisica"
msgid "Print Host upload"
msgstr "Caricamento host di stampa"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Selezionare l'implementazione dell'agente di rete per la comunicazione con la stampante. Gli agenti disponibili vengono registrati all'avvio."
# AI Translated
msgid "Select a Flashforge printer"
msgstr "Seleziona una stampante Flashforge"
@@ -20810,9 +20915,6 @@ msgstr "Si è verificato un problema imprevisto durante il tentativo di accesso.
msgid "User canceled."
msgstr "Utente rimosso."
msgid "Head diameter"
msgstr "Diametro testa"
msgid "Max angle"
msgstr "Angolo massimo"
@@ -21631,6 +21733,22 @@ 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 ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "L'altezza dello strato è troppo piccola.\n"
#~ "Sarà impostato su min_layer_height\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "L'altezza dello strato supera il limite in Impostazioni stampante -> Estrusore -> Limiti Altezza Strato. Ciò potrebbe causare problemi di qualità di stampa."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "Regolare automaticamente l'intervallo impostato?\n"
#~ msgid "Head diameter"
#~ msgstr "Diametro testa"
#~ msgid "Print order within a single layer."
#~ msgstr "Ordine di stampa all'interno di un singolo strato."
+155 -37
View File
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
@@ -4750,6 +4750,23 @@ msgstr "現在のチャンバー温度が材料の安全温度を超えていま
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "最低庫内温度 (%d℃) が目標庫内温度 (%d℃) を上回っています。最低値は、チャンバーが目標に向けて加熱を続けながら印刷を開始するしきい値であるため、目標値を超えてはいけません。値は目標値に制限されます。"
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "積層ピッチが小さすぎます。最小値 (%g mm) に設定されます。"
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "積層ピッチが、プリンター設定 -> 押出機 -> 積層ピッチの制限 で設定された範囲を外れています。印刷品質の問題が発生する可能性があります。"
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "自動的に制限値 (%g mm) に調整しますか?"
msgid "Adjust"
msgstr "調整"
# AI Translated
msgid ""
"Layer height too small\n"
@@ -4873,6 +4890,13 @@ msgstr ""
"はい - Arachneウォールジェネレーターを有効にする\n"
"いいえ - Arachneウォールジェネレーターを無効にし、ファジースキンを[変位]モードに設定する"
# AI Translated
msgid "Brim ear radius"
msgstr "ブリムイヤー半径"
msgid "Brim width"
msgstr "ブリム幅"
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 "スパイラルモードは壁ループが1、サポートが無効、プロービングによるクランピング検出が無効、上部シェルレイヤーが0、スパースインフィル密度が0、タイムラプスタイプがトラディショナルの場合のみ機能します。"
@@ -5127,6 +5151,14 @@ msgstr "キャリブレーションG-codeの生成に失敗しました"
msgid "Calibration error"
msgstr "キャリブレーションエラー"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "このプリンターには、このコントロールに必要なハードウェアが設定されていません。"
# AI Translated
msgid "This control is not supported on this printer."
msgstr "このコントロールはこのプリンターではサポートされていません。"
# AI Translated
msgid "Network unavailable"
msgstr "ネットワークが利用できません"
@@ -5988,7 +6020,7 @@ msgstr "ボリューム"
msgid "Size:"
msgstr "サイズ:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "レイヤー%d、Z = %.2lfmmでG-codeパスの衝突が検出されました。衝突するオブジェクトをもっと離してください(%s <-> %s)。"
@@ -6164,6 +6196,10 @@ msgstr "マルチデバイス"
msgid "Project"
msgstr "プロジェクト"
# AI Translated
msgid "Device (Web)"
msgstr "デバイス (Web)"
msgid "Yes"
msgstr "はい"
@@ -8262,19 +8298,19 @@ msgstr "置換用のディレクトリが選択されていません"
msgid "Replaced with 3D files from directory:\n"
msgstr "ディレクトリの3Dファイルで置換しました:\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ スキップ %s: 同一ファイル。\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ スキップ %s: ファイルが存在しません。\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ スキップ %s: 置換に失敗しました。\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ 置換しました %s。\n"
@@ -9015,6 +9051,18 @@ msgstr "このオプションを有効にすると、複数のデバイスに同
msgid "Pop up to select filament grouping mode"
msgstr "フィラメントグルーピングモード選択のポップアップ"
# AI Translated
msgid "Visible plugin pages"
msgstr "表示するプラグインページ数"
# AI Translated
msgid "pages"
msgstr "ページ"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "固定タブとして表示するプラグインページの数です。残りのページは最後のタブのドロップダウンにまとめられます。"
msgid "Behaviour"
msgstr "動作"
@@ -9404,6 +9452,18 @@ msgstr "非対応のプリセットを表示"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "プリンターとフィラメントのドロップダウンリストに、互換性のない/非対応のプリセットを表示します。これらのプリセットは選択できません。"
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(実験的) プリントホストの代わりにプリンターエージェントを使用"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Bambu 以外のプリンターの印刷ジョブを、従来のプリントホストへのアップロードではなく、プリンターのプラグインエージェント経由で送信します。\n"
"無効の場合、OrcaSlicer は従来のプリントホストの動作を使用します。"
# AI Translated
msgid "Experimental Features"
msgstr "実験的機能"
@@ -9672,9 +9732,25 @@ msgstr "ユーザープリセット"
msgid "Preset Inside Project"
msgstr "プロジェクト プリセット"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "親プリセットから継承したすべての値をこのプリセットにコピーし、親との継承関係を解除します。親プリセットとのみ互換性のあるプリセットは、サポートされなくなる場合があります。"
msgid "Detach from parent"
msgstr "親から分離"
# AI Translated
msgid "Unique preset"
msgstr "独立したプリセット"
# AI Translated
msgid "Parent preset"
msgstr "親プリセット"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "このプリセットは他のプリセットを継承していません。"
msgid "Name is unavailable."
msgstr "名称は使用できません"
@@ -10416,22 +10492,6 @@ msgstr "このオプションを有効にしてもよろしいですか?"
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 "インフィルパターンは通常、適切な印刷と意図した効果を確保するために回転を自動的に処理するように設計されています(例: ジャイロイド、キュービック)。現在のスパースインフィルパターンを回転させると、サポートが不十分になる可能性があります。慎重に進め、潜在的な印刷問題を十分に確認してください。このオプションを有効にしてもよろしいですか?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"レイヤー高さが小さすぎます。\n"
"min_layer_heightに設定されます\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "レイヤー高さがプリンター設定 -> エクストルーダー -> レイヤー高さ制限の上限を超えています。印刷品質の問題が発生する可能性があります。"
msgid "Adjust to the set range automatically?\n"
msgstr "設定範囲に自動調整しますか?\n"
msgid "Adjust"
msgstr "調整"
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 "実験的機能: フィラメント交換時により長い距離でフィラメントをリトラクト・カットしてフラッシュを最小化します。フラッシュを大幅に削減できますが、ノズル詰まりやその他の印刷問題のリスクが高まる可能性もあります。"
@@ -10621,6 +10681,9 @@ msgstr "保留キーワードが見つかりました"
msgid "Setting Overrides"
msgstr "上書き設定"
msgid "Retraction when switching material"
msgstr "素材変更時のリトラクション"
msgid "Basic information"
msgstr "基本情報"
@@ -10751,6 +10814,12 @@ msgstr "互換性のあるプロセスプロファイル"
msgid "Printable space"
msgstr "造形可能領域"
msgid "Printer Agent"
msgstr "プリンターエージェント"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "プリンター通信用のネットワークエージェント実装を選択します。使用可能なエージェントは起動時に登録されます。"
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10877,9 +10946,6 @@ msgstr "積層ピッチの制限"
msgid "Z-Hop"
msgstr "Z-ホップ"
msgid "Retraction when switching material"
msgstr "素材変更時のリトラクション"
# AI Translated
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
@@ -12258,6 +12324,10 @@ msgstr " は除外エリアに近すぎるため、衝突が発生します。\n
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " がクランピング検出エリアに近すぎ、衝突が発生します。\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " は造形可能領域から一部はみ出しているため、印刷できません。\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."
msgstr "選択したノズル温度に互換性がありません。各フィラメントのノズル温度は、他のフィラメントの推奨ノズル温度範囲内に収まる必要があります。そうでない場合、ノズル詰まりやプリンターの損傷が発生する可能性があります。"
@@ -12599,9 +12669,6 @@ msgstr "G-codeの代わりに3MFを使用"
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ファイルを受け付ける場合に有効にします。有効にすると、Orca Slicerはスライス済みファイルを通常の.gcodeファイルではなく.gcode.3mfとして送信します。"
msgid "Printer Agent"
msgstr "プリンターエージェント"
msgid "Select the network agent implementation for printer communication."
msgstr "プリンター通信用のネットワークエージェント実装を選択します。"
@@ -13320,9 +13387,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "内部ブリッジの速度です。値を%で指定した場合、bridge_speedを基準に計算されます。デフォルト値は150%です。"
msgid "Brim width"
msgstr "ブリム幅"
msgid "This is the distance from the model to the outermost brim line."
msgstr "一番外側のブリム線がモデルと距離です。"
@@ -13411,6 +13475,14 @@ msgstr ""
"鋭角を検出する前にジオメトリが間引かれます。このパラメータは、間引きにおける偏差の最小長さを指定します。\n"
"0で無効になります。"
# AI Translated
msgid "Brim ears outer only"
msgstr "ブリムイヤーを外側の輪郭のみ"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "穴や閉じた部分を除き、モデルの外側の輪郭にのみマウスイヤーを生成します。"
msgid "upward compatible machine"
msgstr "互換性のあるデバイス"
@@ -14634,6 +14706,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "ジャイロイド"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "スパース インフィルの平滑化係数"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "スパース インフィルの角をどの程度丸めるかを設定します。0% では元の鋭い経路のまま、100% では隣接するインフィル線の間で可能な限り大きな曲線になります。"
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "トップ面のインフィル加速度です。遅くすると表面の仕上がりが向上させることができます"
@@ -15233,6 +15313,14 @@ msgstr "プリンターが対応するG-code"
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "G-code の設定ブロックを省略"
# AI Translated
msgid "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."
msgstr "CONFIG_BLOCK (スライサー設定のキーと値のペア) を G-code ファイルに書き込みません。これらのコメント行の解析でファームウェアがクラッシュするプリンター (例: Anycubic go-klipper) で役立ちます。注意: G-code ファイルにスライサー設定が含まれなくなるため、OrcaSlicer に読み込み直しても設定は復元されません。"
# AI Translated
msgid "Pellet Modded Printer"
msgstr "ペレット改造プリンター"
@@ -16374,6 +16462,14 @@ msgstr "押出機切り替え時のロングリトラクション"
msgid "Retraction distance when extruder change"
msgstr "押出機切替時のリトラクション距離"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "リトラクション量 (ツール交換)"
# 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 "ツール交換の前にリトラクションが行われるとき、指定した量だけフィラメントが引き戻されます (長さは押出機に入る前の未加工のフィラメントで測定されます)。"
# AI Translated
msgid "Z-hop height"
msgstr "Zホップの高さ"
@@ -16488,6 +16584,10 @@ msgstr "再開時の追加長さ"
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 "移動後に引込みが補償されると、エクストルーダーはこの追加量のフィラメントを押し出します。 この設定はほとんど必要ありません。"
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "再開時の追加長さ (ツール交換)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "ツールの交換後に吸込み分が補正されると、エクストルーダーはこの追加量のフィラメントを押し出します。"
@@ -16963,6 +17063,14 @@ msgstr "ワイプタワー上でツール交換"
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) を発行する前に、ツールヘッドを強制的にワイプタワーへ移動させます。タイプ2のワイプタワーを使用するマルチ押出機 (マルチツールヘッド) プリンターにのみ関係します。デフォルトでは、マルチツールヘッド機ではファームウェアがヘッドの交換を処理するためOrcaは移動をスキップしますが、その結果Txコマンドが造形物の上で発行される場合があります。ツール交換を常にワイプタワーの上で発行したい場合は、このオプションを有効にしてください。"
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "ワイプタワーで温度待機"
# 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 "印刷温度に達するのを待たずに新しいツールを取り付け、ワイプタワーへ移動し、パージ直前にそこで温度を待ちます。加熱中の垂れ出しはモデルではなくタワーに落ち、移動時間が加熱と重なります。タイプ 2 のワイプタワーを使用するマルチ押出機 (マルチツールヘッド) プリンターでのみ有効です。ファームウェアやツール交換マクロ側で温度待機を行わないようにしてください。無効の場合、温度待機はツール交換コマンドの直後に出力されます。"
# AI Translated
msgid "No sparse layers (beta)"
msgstr "スパース層なし (ベータ)"
@@ -20389,9 +20497,6 @@ msgstr "実物プリンター"
msgid "Print Host upload"
msgstr "プリントホストのアップロード"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "プリンター通信用のネットワークエージェント実装を選択します。使用可能なエージェントは起動時に登録されます。"
# AI Translated
msgid "Select a Flashforge printer"
msgstr "Flashforgeプリンターを選択"
@@ -21363,9 +21468,6 @@ msgstr "ログイン中に予期しない問題が発生しました。再試行
msgid "User canceled."
msgstr "ユーザーがキャンセルしました。"
msgid "Head diameter"
msgstr "直径"
msgid "Max angle"
msgstr "最大角度"
@@ -22194,6 +22296,22 @@ msgstr ""
"反りを避ける\n"
"ABSのような反りやすい素材を印刷する場合、ヒートベッドの温度を適切に上げることで、反りが発生する確率を下げることができることをご存知ですか?"
#~ msgid ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "レイヤー高さが小さすぎます。\n"
#~ "min_layer_heightに設定されます\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "レイヤー高さがプリンター設定 -> エクストルーダー -> レイヤー高さ制限の上限を超えています。印刷品質の問題が発生する可能性があります。"
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "設定範囲に自動調整しますか?\n"
#~ msgid "Head diameter"
#~ msgstr "直径"
#~ msgid "Print order within a single layer."
#~ msgstr "単一レイヤー内の印刷順序。"
+157 -39
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: 2025-06-02 17:12+0900\n"
"Last-Translator: crwusiz <crwusiz@gmail.com>\n"
"Language-Team: \n"
@@ -4763,6 +4763,23 @@ msgstr "현재 챔버 온도가 재료의 안전 온도보다 높으므로 재
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "최소 챔버 온도(%d℃)가 목표 챔버 온도(%d℃)보다 높습니다. 최소값은 챔버가 목표 온도까지 계속 가열되는 동안 출력을 시작하는 기준값이므로 목표값을 초과해서는 안 됩니다. 이 값은 목표값으로 제한됩니다."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "레이어 높이가 너무 작습니다. 최솟값(%g mm)으로 설정됩니다."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "레이어 높이가 프린터 설정 -> 압출기 -> 레이어 높이 한도에서 설정한 범위를 벗어났습니다. 출력 품질 문제가 발생할 수 있습니다."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "한도(%g mm)에 맞게 자동으로 조정할까요?"
msgid "Adjust"
msgstr "조정"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4884,6 +4901,13 @@ msgstr ""
"예 - 아라크네 벽 생성기 활성화\n"
"아니오 - 아라크네 벽 생성기 비활성화 및 퍼지 스킨 [변위] 모드 설정"
# AI Translated
msgid "Brim ear radius"
msgstr "브림 귀 반경"
msgid "Brim width"
msgstr "브림 너비"
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 "나선형 모드는 벽 루프가 1이고, 서포트가 비활성화되고, 프로빙에 의한 클럼핑 감지가 비활성화되고, 상단 셸 레이어가 0이고, 희소 인필 밀도가 0이고 타임랩스 유형이 전통적인 경우에만 작동합니다."
@@ -5138,6 +5162,14 @@ msgstr "교정 Gcode를 생성하지 못했습니다"
msgid "Calibration error"
msgstr "교정 오류"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "이 프린터에는 이 컨트롤에 필요한 하드웨어가 구성되어 있지 않습니다."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "이 컨트롤은 이 프린터에서 지원되지 않습니다."
# AI Translated
msgid "Network unavailable"
msgstr "네트워크를 사용할 수 없음"
@@ -6001,7 +6033,7 @@ msgstr "용량:"
msgid "Size:"
msgstr "크기:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "레이어 %d, Z = %.2lf mm에서 Gcode 경로 충돌이 발견되었습니다. 충돌하는 객체를 더 멀리 분리하세요 (%s <-> %s)."
@@ -6178,6 +6210,10 @@ msgstr "멀티 디바이스"
msgid "Project"
msgstr "프로젝트"
# AI Translated
msgid "Device (Web)"
msgstr "장치 (웹)"
msgid "Yes"
msgstr "예"
@@ -8288,22 +8324,22 @@ msgid "Replaced with 3D files from directory:\n"
msgstr "다음 디렉터리의 3D 파일로 교체했습니다:\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ 건너뜀 %s: 동일한 파일입니다.\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ 건너뜀 %s: 파일이 존재하지 않습니다.\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ 건너뜀 %s: 교체하지 못했습니다.\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ %s을(를) 교체했습니다.\n"
@@ -9077,6 +9113,18 @@ msgstr "활성화하면 여러 장치에 동시에 작업을 보내고 여러
msgid "Pop up to select filament grouping mode"
msgstr "필라멘트 그룹화 모드를 선택하기 위한 팝업"
# AI Translated
msgid "Visible plugin pages"
msgstr "표시할 플러그인 페이지"
# AI Translated
msgid "pages"
msgstr "페이지"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "고정 탭으로 표시되는 플러그인 페이지 수입니다. 나머지 페이지는 마지막 탭의 드롭다운으로 묶입니다."
# AI Translated
msgid "Behaviour"
msgstr "동작"
@@ -9491,6 +9539,18 @@ msgstr "지원되지 않는 사전 설정 표시"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "프린터 및 필라멘트 드롭다운 목록에 호환되지 않거나 지원되지 않는 사전 설정을 표시합니다. 이러한 사전 설정은 선택할 수 없습니다."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(실험적) 출력 호스트 대신 프린터 에이전트 사용"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Bambu 이외의 프린터 출력 작업을 기존 출력 호스트 업로드 방식 대신 프린터 플러그인 에이전트를 통해 전달합니다.\n"
"비활성화하면 OrcaSlicer는 기존 출력 호스트 동작을 사용합니다."
# AI Translated
msgid "Experimental Features"
msgstr "실험적 기능"
@@ -9762,10 +9822,26 @@ msgstr "사용자 사전 설정"
msgid "Preset Inside Project"
msgstr "프로젝트 내부 사전 설정"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "상위 사전 설정에서 상속한 모든 값을 이 사전 설정으로 복사하고 상속 관계를 제거합니다. 상위 사전 설정에서만 호환되는 사전 설정은 지원되지 않을 수 있습니다."
# AI Translated
msgid "Detach from parent"
msgstr "상위 항목에서 분리"
# AI Translated
msgid "Unique preset"
msgstr "독립 사전 설정"
# AI Translated
msgid "Parent preset"
msgstr "상위 사전 설정"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "이 사전 설정은 다른 사전 설정을 상속하지 않습니다."
msgid "Name is unavailable."
msgstr "이름을 사용할 수 없습니다."
@@ -10519,22 +10595,6 @@ msgstr "이 옵션을 사용하시겠습니까?"
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 "채우기 패턴은 일반적으로 올바른 출력과 의도한 효과를 위해 회전을 자동으로 처리하도록 설계되어 있습니다(예: 자이로이드, 큐빅). 현재 드문 채우기 패턴을 회전시키면 지지력이 부족해질 수 있습니다. 신중하게 진행하고 출력 문제가 발생하지 않는지 충분히 확인하십시오. 이 옵션을 활성화하시겠습니까?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"레이어 높이가 너무 작습니다.\n"
"min_layer_height로 설정됩니다.\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "레이어 높이가 프린터 설정 -> 압출기 -> 레이어의 제한을 초과합니다.높이 제한으로 인해 출력 품질 문제가 발생할 수 있습니다."
msgid "Adjust to the set range automatically?\n"
msgstr "설정 범위에 자동으로 맞춰지나요?\n"
msgid "Adjust"
msgstr "조정"
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 "실험적 기능: 플러시를 최소화하기 위해 필라멘트 교체 중에 더 먼 거리에서 필라멘트를 집어넣고 절단합니다. 플러시를 눈에 띄게 줄일 수 있지만 노즐 막힘이나 기타 출력 문제의 위험이 높아질 수도 있습니다."
@@ -10728,6 +10788,9 @@ msgstr "예약어를 찾았습니다"
msgid "Setting Overrides"
msgstr "설정 덮어쓰기"
msgid "Retraction when switching material"
msgstr "재료 전환 시 후퇴"
msgid "Basic information"
msgstr "기본 정보"
@@ -10861,6 +10924,14 @@ msgstr "호환 프로세스 사전설정"
msgid "Printable space"
msgstr "출력 가능 공간"
# AI Translated
msgid "Printer Agent"
msgstr "프린터 에이전트"
# AI Translated
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "프린터 통신에 사용할 네트워크 에이전트 구현을 선택합니다. 사용 가능한 에이전트는 시작 시 등록됩니다."
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10993,9 +11064,6 @@ msgstr "레이어 높이 한도"
msgid "Z-Hop"
msgstr "Z올리기"
msgid "Retraction when switching material"
msgstr "재료 전환 시 후퇴"
# AI Translated
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
@@ -12388,6 +12456,10 @@ msgstr " 이(가) 제외 영역에 너무 가깝습니다. 출력 시 충돌이
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " 뭉침 감지 영역에 너무 가까워 충돌이 발생할 수 있습니다.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " 이(가) 출력 가능 영역을 일부 벗어나 출력할 수 없습니다.\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."
msgstr "선택한 노즐 온도가 서로 호환되지 않습니다. 각 필라멘트의 노즐 온도는 다른 필라멘트의 권장 노즐 온도 범위 안에 있어야 합니다. 그렇지 않으면 노즐 막힘이나 프린터 손상이 발생할 수 있습니다."
@@ -12732,10 +12804,6 @@ msgstr "G-code 대신 3MF 사용"
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 파일을 허용하는 경우 이 옵션을 활성화하십시오. 활성화하면 Orca Slicer가 슬라이스된 파일을 일반 .gcode 파일 대신 .gcode.3mf로 전송합니다."
# AI Translated
msgid "Printer Agent"
msgstr "프린터 에이전트"
# AI Translated
msgid "Select the network agent implementation for printer communication."
msgstr "프린터 통신에 사용할 네트워크 에이전트 구현을 선택합니다."
@@ -13446,9 +13514,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "내부 브릿지의 속도. 값을 백분율로 표현하면 bridge_speed를 기준으로 계산됩니다. 기본값은 150%입니다."
msgid "Brim width"
msgstr "브림 너비"
msgid "This is the distance from the model to the outermost brim line."
msgstr "모델과 가장 바깥쪽 브림 선까지의 거리"
@@ -13533,6 +13598,14 @@ msgstr ""
"날카로운 각도를 감지하기 전에 형상이 무시됩니다. 이 매개변수는 무시하는 형상의 최소 길이를 나타냅니다.\n"
"0으로 비활성화합니다"
# AI Translated
msgid "Brim ears outer only"
msgstr "브림 귀를 바깥쪽에만"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "구멍과 닫힌 영역을 제외하고 모델의 바깥쪽 윤곽에만 생쥐 귀를 생성합니다."
msgid "upward compatible machine"
msgstr "상향 호환 장치"
@@ -14729,6 +14802,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "자이로이드"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "드문 채우기 부드러움 계수"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "드문 채우기의 모서리를 얼마나 둥글게 할지 조절합니다. 0%는 원래의 날카로운 경로를 유지하고, 100%는 인접한 채우기 선 사이에 가능한 가장 큰 곡선을 만듭니다."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "상단 표면 가속도. 낮은 값을 사용하면 상단 표면 품질이 향상될 수 있습니다"
@@ -15291,6 +15372,14 @@ msgstr "프린터와 호환되는 Gcode 종류"
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "G-code 설정 블록 생략"
# AI Translated
msgid "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."
msgstr "CONFIG_BLOCK(슬라이서 설정의 키/값 쌍)을 G-code 파일에 기록하지 않습니다. 이 주석 줄을 해석할 때 펌웨어가 중단되는 프린터(예: Anycubic go-klipper)에 도움이 될 수 있습니다. 참고: G-code 파일에 슬라이서 설정이 더 이상 포함되지 않으므로, 이 파일을 OrcaSlicer로 다시 가져와도 설정이 복원되지 않습니다."
msgid "Pellet Modded Printer"
msgstr "펠릿 프린터"
@@ -16400,6 +16489,14 @@ msgstr "압출기 교체 시 긴 수축"
msgid "Retraction distance when extruder change"
msgstr "압출기 교체 시 수축 거리"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "후퇴 길이 (툴 체인지)"
# 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 "툴 체인지 전에 후퇴가 실행되면 지정한 양만큼 필라멘트가 뒤로 당겨집니다 (길이는 압출기에 들어가기 전의 원래 필라멘트를 기준으로 측정됩니다)."
msgid "Z-hop height"
msgstr "Z올리기 높이"
@@ -16498,6 +16595,10 @@ msgstr "재 시작 시 추가 길이"
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 "이동 후 후퇴가 보상되면 압출기는 이 추가 양의 필라멘트를 밀어냅니다. 이 설정은 거의 필요하지 않습니다."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "재 시작 시 추가 길이 (툴 체인지)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "툴 체인지 후 후퇴가 보상되면 압출기는 이 추가 양의 필라멘트를 밀어냅니다."
@@ -16922,6 +17023,14 @@ msgstr "프라임 타워에서 툴 체인지"
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)을 실행하기 전에 툴헤드가 반드시 프라임 타워로 이동하도록 합니다. 유형 2 프라임 타워를 사용하는 다중 압출기(멀티 툴헤드) 프린터에만 해당됩니다. 기본적으로 Orca는 멀티 툴헤드 장비에서 펌웨어가 헤드 교체를 처리하므로 이동을 생략하는데, 이 때문에 Tx 명령이 출력물 위에서 실행될 수 있습니다. 툴 체인지가 항상 프라임 타워 위에서 실행되도록 하려면 이 옵션을 활성화하십시오."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "프라임 타워에서 온도 대기"
# 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 "출력 온도에 도달할 때까지 기다리지 않고 새 툴을 집은 뒤 프라임 타워로 이동하여, 퍼지 직전에 그곳에서 온도를 기다립니다. 가열 중 흘러나온 재료는 모델이 아닌 타워에 떨어지고, 이동 시간이 가열 시간과 겹칩니다. 타입 2 프라임 타워를 사용하는 다중 압출기(다중 툴헤드) 프린터에만 해당합니다. 펌웨어나 툴 체인지 매크로가 직접 온도를 기다려서는 안 됩니다. 비활성화하면 툴 체인지 명령 직후에 온도 대기가 실행됩니다."
msgid "No sparse layers (beta)"
msgstr "희소 레이어 없음(베타)"
@@ -20261,10 +20370,6 @@ msgstr "물리 프린터"
msgid "Print Host upload"
msgstr "출력 호스트 업로드"
# AI Translated
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "프린터 통신에 사용할 네트워크 에이전트 구현을 선택합니다. 사용 가능한 에이전트는 시작 시 등록됩니다."
# AI Translated
msgid "Select a Flashforge printer"
msgstr "Flashforge 프린터 선택"
@@ -21217,9 +21322,6 @@ msgstr "로그인을 시도하는 동안 예기치 않은 문제가 발생했습
msgid "User canceled."
msgstr "사용자가 취소했습니다."
msgid "Head diameter"
msgstr "헤드 직경"
msgid "Max angle"
msgstr "최대 각도"
@@ -22057,6 +22159,22 @@ msgstr ""
"뒤틀림 방지\n"
"ABS와 같이 뒤틀림이 발생하기 쉬운 소재를 출력할 때, 히트베드 온도를 적절하게 높이면 뒤틀림 가능성을 줄일 수 있다는 사실을 알고 계셨나요?"
#~ msgid ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "레이어 높이가 너무 작습니다.\n"
#~ "min_layer_height로 설정됩니다.\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "레이어 높이가 프린터 설정 -> 압출기 -> 레이어의 제한을 초과합니다.높이 제한으로 인해 출력 품질 문제가 발생할 수 있습니다."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "설정 범위에 자동으로 맞춰지나요?\n"
#~ msgid "Head diameter"
#~ msgstr "헤드 직경"
#~ msgid "Print order within a single layer."
#~ msgstr "단일 레이어 내의 출력 순서"
+157 -39
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: 2026-07-02 14:13+0300\n"
"Last-Translator: Gintaras Kučinskas <sharanchius@gmail.com>\n"
"Language-Team: \n"
@@ -4728,6 +4728,23 @@ msgstr "Dabartinė kameros temperatūra yra aukštesnė už saugią medžiagos t
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "Minimali kameros temperatūra (%d℃) yra aukštesnė nei tikslinė kameros temperatūra (%d℃). Minimali vertė yra slenkstis, kurį pasiekus pradedamas spausdinimas, kol kamera vis dar kaitinama iki tikslinės temperatūros, todėl ji neturėtų viršyti tikslinės. Vertė bus apribota iki tikslinės temperatūros."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "Sluoksnio aukštis per mažas. Jis bus nustatytas į mažiausią reikšmę (%g mm)."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Sluoksnio aukštis yra už ribų, nurodytų Spausdintuvo nustatymai -> Ekstruderis -> Sluoksnio aukščio ribos, tai gali sukelti spausdinimo kokybės problemų."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "Automatiškai sureguliuoti iki ribos (%g mm)?"
msgid "Adjust"
msgstr "Sureguliuoti"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4847,6 +4864,13 @@ msgstr ""
"Taip įjungti „Arachne“ sienelių generatorių\n"
"Ne išjungti „Arachne“ sienelių generatorių ir nustatyti „Šiurkštaus paviršius“ režimą [Slinktis]"
# AI Translated
msgid "Brim ear radius"
msgstr "Apvado „ausies“ spindulys"
msgid "Brim width"
msgstr "Pado apvado plotis"
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 "Spiralinis režimas veikia tik tada, kai sienelės kilpų skaičius yra 1, atramos išjungtos, sulipimo aptikimas zonduojant išjungtas, viršutinių apvalkalo sluoksnių yra 0, reto užpildo tankis yra 0 %, o laiko intervalų vaizdo įrašo tipas tradicinis."
@@ -5101,6 +5125,14 @@ msgstr "Nepavyko sugeneruoti kalibravimo G-kodo"
msgid "Calibration error"
msgstr "Kalibravimo klaida"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "Šiame spausdintuve nėra sukonfigūruotos įrangos, kurios reikia šiam valdikliui."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Šis valdiklis šiame spausdintuve nepalaikomas."
# AI Translated
msgid "Network unavailable"
msgstr "Tinklas neprieinamas"
@@ -5961,7 +5993,7 @@ msgstr "Tūris:"
msgid "Size:"
msgstr "Dydis:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "Rasta G-kodo trajektorijų konfliktų %d sluoksnyje, Z = %.2lfmm. Prašome labiau atskirti konfliktuojančius objektus (%s <-> %s)."
@@ -6142,6 +6174,10 @@ msgstr "Kelių įrenginių valdymas (Multi-device)"
msgid "Project"
msgstr "Projektas"
# AI Translated
msgid "Device (Web)"
msgstr "Įrenginys (Web)"
msgid "Yes"
msgstr "Taip"
@@ -8239,19 +8275,19 @@ msgstr ""
"Pakeista 3D failais iš katalogo:\n"
"\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ Praleistas %s: tas pats failas.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ Praleistas %s: failas neegzistuoja.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ Praleistas %s: nepavyko pakeisti.\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ Pakeistas %s.\n"
@@ -8977,6 +9013,18 @@ msgstr "Kai įjungta ši funkcija, jūs galite siųsti užduotį keliems įrengi
msgid "Pop up to select filament grouping mode"
msgstr "Iššokantis langas gijų grupavimo režimui pasirinkti"
# AI Translated
msgid "Visible plugin pages"
msgstr "Matomi papildinių puslapiai"
# AI Translated
msgid "pages"
msgstr "puslapiai"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "Papildinių puslapių, rodomų kaip fiksuotos kortelės, skaičius; likę puslapiai sutraukiami į išskleidžiamąjį sąrašą paskutinėje kortelėje."
msgid "Behaviour"
msgstr "Elgsena"
@@ -9329,6 +9377,18 @@ msgstr "Rodyti nepalaikomus profilius"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "Rodyti nesuderinamus / nepalaikomus profilius spausdintuvų ir gijų išskleidžiamuosiuose sąrašuose. Šių profilių pasirinkti negalima."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Eksperimentinė) Naudoti spausdintuvo agentus vietoj spausdinimo serverių"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Nukreipia ne Bambu spausdintuvų spausdinimo užduotis per spausdintuvo papildinių agentus, o ne per klasikinį įkėlimo į spausdinimo serverį srautą.\n"
"Kai išjungta, OrcaSlicer naudoja senąjį spausdinimo serverio veikimą."
msgid "Experimental Features"
msgstr "Eksperimentinis"
@@ -9590,9 +9650,25 @@ msgstr "Naudotojo profilis"
msgid "Preset Inside Project"
msgstr "Profilis projekto viduje"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Nukopijuoja į šį profilį visas iš pirminio profilio paveldėtas reikšmes ir pašalina paveldėjimo ryšį. Profiliai, suderinami tik su pirminiu profiliu, gali tapti nepalaikomi."
msgid "Detach from parent"
msgstr "Atskirti nuo tėvinio profilio"
# AI Translated
msgid "Unique preset"
msgstr "Savarankiškas profilis"
# AI Translated
msgid "Parent preset"
msgstr "Pirminis profilis"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Šis profilis nepaveldi iš kito profilio."
msgid "Name is unavailable."
msgstr "Nėra pavadinimo."
@@ -10330,24 +10406,6 @@ msgstr "Ar tikrai norite įjungti šią parinktį?"
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 "Užpildymo modeliai paprastai yra suprojektuoti taip, kad automatiškai tvarkytų sukimąsi, siekiant užtikrinti tinkamą spausdinimą ir pasiekti numatytus efektus (pvz., Gyroid, Cubic). Sukant esamą retą užpildymo modelį, gali atsirasti nepakankamas atraminis paviršius. Prašome elgtis atsargiai ir atidžiai patikrinti, ar nėra galimų spausdinimo problemų. Ar tikrai norite įjungti šią parinktį?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"Per mažas sluoksnio aukštis.\n"
"Jis bus nustatytas į min_layer_height\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Sluoksnio aukštis viršija ribą, nurodytą Spausdintuvo nustatymai -> Ekstruderis -> Sluoksnio aukščio ribos, tai gali sukelti spausdinimo kokybės problemų."
msgid "Adjust to the set range automatically?\n"
msgstr ""
"Sureguliuoti pagal nustatytą diapazoną automatiškai?\n"
"\n"
msgid "Adjust"
msgstr "Sureguliuoti"
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 "Eksperimentinė funkcija: gijos įtraukimas ir nukirpimas didesniu atstumu keičiant giją, siekiant sumažinti išvalymą (flush). Nors tai gali pastebimai sumažinti išvalymą, taip pat gali padidėti purkštuko užsikimšimo ar kitų spausdinimo komplikacijų rizika."
@@ -10547,6 +10605,9 @@ msgstr "Rasti rezervuoti raktažodžiai"
msgid "Setting Overrides"
msgstr "Nustatymų perrašymas"
msgid "Retraction when switching material"
msgstr "Įtraukimas keičiant medžiagą"
msgid "Basic information"
msgstr "Pagrindinė informacija"
@@ -10673,6 +10734,12 @@ msgstr "Suderinami apdorojimo profiliai"
msgid "Printable space"
msgstr "Erdvė spausdinimui"
msgid "Printer Agent"
msgstr "Spausdintuvo agentas"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Pasirinkite tinklo agento modulį ryšiui su spausdintuvu palaikyti. Prieinami agentai užregistruojami paleidimo metu."
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10798,9 +10865,6 @@ msgstr "Sluoksnio aukščio ribos"
msgid "Z-Hop"
msgstr "Z šuolis"
msgid "Retraction when switching material"
msgstr "Įtraukimas keičiant medžiagą"
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
"\n"
@@ -12146,6 +12210,10 @@ msgstr ""
" yra per arti sulipimo aptikimo zonos, todėl įvyks susidūrimai.\n"
"\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " yra iš dalies už spausdinimo srities ribų ir negali būti atspausdintas.\n"
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."
msgstr "Pasirinktos purkštuko temperatūros yra nesuderinamos. Kiekvienos gijos purkštuko temperatūra turi patekti į kitų gijų rekomenduojamos temperatūros diapazoną. Priešingu atveju gali užsikimšti purkštukas arba sugesti spausdintuvas."
@@ -12459,9 +12527,6 @@ msgstr "Vietoj G-kodo naudoti 3MF"
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 "Įjunkite, jei spausdintuvas spausdinimo užduotims priima 3MF failus. Kai įjungta, „Orca Slicer“ sugeneruotą failą siunčia kaip „.gcode.3mf“, o ne kaip paprastą „.gcode“ failą."
msgid "Printer Agent"
msgstr "Spausdintuvo agentas"
msgid "Select the network agent implementation for printer communication."
msgstr "Pasirinkite tinklo agento modulį ryšiui su spausdintuvu palaikyti."
@@ -13134,9 +13199,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "Vidinių tiltelių spausdinimo greitis. Jei reikšmė nurodoma procentais, ji apskaičiuojama pagal „bridge_speed“ (tiltelių greitį). Numatytoji reikšmė 150 %."
msgid "Brim width"
msgstr "Pado apvado plotis"
msgid "This is the distance from the model to the outermost brim line."
msgstr "Atstumas nuo modelio iki išorinės krašto linijos"
@@ -13217,6 +13279,14 @@ msgstr ""
"Prieš aptinkant aštrius kampus, geometrija yra supaprastinama (decimuojama). Šis parametras nurodo minimalų nuokrypio ilgį supaprastinimui atlikti.\n"
"Įrašykite 0, kad išjungtumėte."
# AI Translated
msgid "Brim ears outer only"
msgstr "Apvado „ausys“ tik išorėje"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Kuria peliukų ausis tik ant išorinio modelio kontūro, praleidžiant skyles ir uždaras sritis."
msgid "upward compatible machine"
msgstr "atgaliniu būdu suderinamas įrenginys"
@@ -14370,6 +14440,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "Giroidas"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Reto užpildo glotninimo koeficientas"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Nustato, kaip stipriai suapvalinami reto užpildo kampai. 0% palieka pradinę aštrią trajektoriją, o 100% sukuria didžiausias įmanomas kreives tarp gretimų užpildo linijų."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "Viršutinio paviršiaus užpildo pagreitis. Naudojant mažesnę vertę gali pagerėti viršutinio paviršiaus kokybė."
@@ -14914,6 +14992,14 @@ msgstr "Su kokiu G kodu suderinamas spausdintuvas."
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "Praleisti G-code konfigūracijos bloką"
# AI Translated
msgid "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."
msgstr "Neįrašo CONFIG_BLOCK (pjaustyklės konfigūracijos raktų ir reikšmių porų) į G-code failą. Tai gali padėti su spausdintuvais, kurių programinė įranga stringa apdorodama šias komentarų eilutes (pvz., Anycubic go-klipper). Pastaba: G-code faile nebeliks pjaustyklės nustatymų, todėl importavus jį atgal į OrcaSlicer konfigūracija nebus atkurta."
msgid "Pellet Modded Printer"
msgstr "Modifikuotas granulinis spausdintuvas"
@@ -15955,6 +16041,14 @@ msgstr "Ilgas įtraukimas keičiant ekstruderį"
msgid "Retraction distance when extruder change"
msgstr "Įtraukimo atstumas keičiant ekstruderį"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "Atitraukimo ilgis (Įrankio keitimas)"
# 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 "Kai atitraukimas suaktyvinamas prieš įrankio keitimą, gija atitraukiama nurodytu atstumu (ilgis matuojamas ant neapdorotos gijos, prieš jai patenkant į ekstruderį)."
msgid "Z-hop height"
msgstr "„Z-hop“ (pakėlimo) aukštis"
@@ -16049,6 +16143,10 @@ msgstr "Papildomas ilgis po sugrąžinimo"
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 "Kai po judėjimo kompensuojamas gijos įtraukimas, ekstruderis papildomai išstums šį gijos kiekį. Šis nustatymas reikalingas retai."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "Papildomas ilgis po sugrąžinimo (Įrankio keitimas)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "Kai po įrankio pakeitimo kompensuojamas gijos įtraukimas, ekstruderis papildomai išstums šį gijos kiekį."
@@ -16461,6 +16559,14 @@ msgstr "Įrankio keitimas virš valymo bokšto"
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 "Priverstinai nukreipti spausdinimo galvutę prie valymo bokšto prieš vykdant įrankio keitimo komandą (Tx). Aktualu tik spausdintuvams su keliais ekstruderiais (keliomis galvutėmis), naudojantiems 2 tipo valymo bokštą. Pagal numatytuosius nustatymus „OrcaSlicer“ praleidžia šį judesį kelių galvučių įrenginiuose, nes galvučių sukeitimą valdo aparatinė programinė įranga, todėl Tx komanda gali būti įvykdyta virš spausdinamos detalės. Įjunkite šią parinktį, jei norite, kad įrankio keitimas visada vyktų virš valymo bokšto."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "Laukti temperatūros ant valymo bokšto"
# 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 "Paima naują įrankį nelaukdamas, kol jis pasieks spausdinimo temperatūrą, nuvažiuoja prie valymo bokšto ir ten laukia temperatūros, prieš pat pravalymą. Kaitinant ištekėjusi medžiaga patenka ant bokšto, o ne ant modelio, o pervažiavimas persidengia su kaitinimu. Aktualu tik daugiaekstruderiams (kelių spausdinimo galvučių) spausdintuvams, naudojantiems 2 tipo valymo bokštą. Programinė įranga ar įrankio keitimo makrokomanda neturi pati laukti temperatūros. Kai išjungta, laukimo temperatūros komanda pateikiama iškart po įrankio keitimo komandos."
msgid "No sparse layers (beta)"
msgstr "Nėra retų sluoksnių (beta)"
@@ -19702,9 +19808,6 @@ msgstr "Fizinis spausdintuvas"
msgid "Print Host upload"
msgstr "Įkėlimas spausdinimui tinkle"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Pasirinkite tinklo agento modulį ryšiui su spausdintuvu palaikyti. Prieinami agentai užregistruojami paleidimo metu."
msgid "Select a Flashforge printer"
msgstr "Pasirinkite „Flashforge“ spausdintuvą"
@@ -20552,9 +20655,6 @@ msgstr "Bandant prisijungti įvyko kažkas netikėto. Bandykite dar kartą."
msgid "User canceled."
msgstr "Vartotojas atšaukė."
msgid "Head diameter"
msgstr "Galvutės skersmuo"
msgid "Max angle"
msgstr "Maksimalus kampas"
@@ -21336,6 +21436,24 @@ 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 ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "Per mažas sluoksnio aukštis.\n"
#~ "Jis bus nustatytas į min_layer_height\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "Sluoksnio aukštis viršija ribą, nurodytą Spausdintuvo nustatymai -> Ekstruderis -> Sluoksnio aukščio ribos, tai gali sukelti spausdinimo kokybės problemų."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr ""
#~ "Sureguliuoti pagal nustatytą diapazoną automatiškai?\n"
#~ "\n"
#~ msgid "Head diameter"
#~ msgstr "Galvutės skersmuo"
#~ msgid "Print order within a single layer."
#~ msgstr "Elementų spausdinimo eiliškumas vieno sluoksnio ribose."
+157 -39
View File
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
@@ -5150,6 +5150,23 @@ msgstr "De huidige kamertemperatuur is hoger dan de veilige temperatuur van het
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "De minimale kamertemperatuur (%d℃) is hoger dan de doelkamertemperatuur (%d℃). De minimale waarde is de drempel waarbij het printen start terwijl de kamer verder opwarmt naar de doelwaarde; deze mag die dus niet overschrijden. De waarde wordt begrensd tot de doelwaarde."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "De laaghoogte is te klein. Deze wordt ingesteld op het minimum (%g mm)."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "De laaghoogte valt buiten de limieten die zijn ingesteld in Printerinstellingen -> Extruder -> Laaghoogtelimieten, dit kan problemen met de afdrukkwaliteit veroorzaken."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "Automatisch aanpassen naar de limiet (%g mm)?"
msgid "Adjust"
msgstr "Aanpassen"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -5277,6 +5294,13 @@ msgstr ""
"Ja - Arachne-wandgenerator inschakelen\n"
"Nee - Arachne-wandgenerator uitschakelen en de modus [Displacement] van Vage buitenkant instellen"
# AI Translated
msgid "Brim ear radius"
msgstr "Straal van randoren"
msgid "Brim width"
msgstr "Rand breedte"
# AI Translated
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 "De spiraalmodus werkt alleen wanneer Wanden 1 is, ondersteuning is uitgeschakeld, klontdetectie via aftasten is uitgeschakeld, het aantal bovenste buitenlagen 0 is, de dichtheid van de dunne vulling (infill) 0 is en het timelapse-type traditioneel is."
@@ -5582,6 +5606,14 @@ msgstr "Cali G-code niet gegenereerd"
msgid "Calibration error"
msgstr "Kalibratiefout"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "Deze printer beschikt niet over de hardware die dit besturingselement nodig heeft."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Dit besturingselement wordt niet ondersteund op deze printer."
# AI Translated
msgid "Network unavailable"
msgstr "Netwerk niet beschikbaar"
@@ -6513,7 +6545,7 @@ msgid "Size:"
msgstr "Maat:"
# AI Translated
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "Er zijn conflicten tussen G-code-paden gevonden op laag %d, Z = %.2lfmm. Plaats de conflicterende objecten verder uit elkaar (%s <-> %s)."
@@ -6714,6 +6746,10 @@ msgstr "Meerdere apparaten"
msgid "Project"
msgstr "Project"
# AI Translated
msgid "Device (Web)"
msgstr "Apparaat (Web)"
msgid "Yes"
msgstr "Ja"
@@ -8999,22 +9035,22 @@ msgid "Replaced with 3D files from directory:\n"
msgstr "Vervangen door 3D-bestanden uit de map:\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ Overgeslagen %s: hetzelfde bestand.\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ Overgeslagen %s: bestand bestaat niet.\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ Overgeslagen %s: vervangen is mislukt.\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ Vervangen %s.\n"
@@ -9827,6 +9863,18 @@ msgstr "Met deze optie ingeschakeld kunt u een taak tegelijkertijd naar meerdere
msgid "Pop up to select filament grouping mode"
msgstr "Pop-up om de filamentgroeperingsmodus te kiezen"
# AI Translated
msgid "Visible plugin pages"
msgstr "Zichtbare plug-inpagina's"
# AI Translated
msgid "pages"
msgstr "pagina's"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "Aantal plug-inpagina's dat als vaste tabbladen wordt getoond voordat de overige pagina's worden samengevouwen in een vervolgkeuzelijst op het laatste tabblad."
msgid "Behaviour"
msgstr "Gedrag"
@@ -10243,6 +10291,18 @@ msgstr "Niet-ondersteunde voorinstellingen tonen"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "Toon incompatibele/niet-ondersteunde voorinstellingen in de keuzelijsten voor printer en filament. Deze voorinstellingen kunnen niet worden geselecteerd."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Experimenteel) Printeragents gebruiken in plaats van printhosts"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Stuurt printtaken voor niet-Bambu-printers via printer-plug-inagents in plaats van via de klassieke uploadstroom naar de printhost.\n"
"Wanneer dit is uitgeschakeld, gebruikt OrcaSlicer het oude printhostgedrag."
# AI Translated
msgid "Experimental Features"
msgstr "Experimentele functies"
@@ -10523,10 +10583,26 @@ msgstr "Gebruikersvoorinstelling"
msgid "Preset Inside Project"
msgstr "Voorinstelling binnen project"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Kopieert alle overgeërfde waarden van de bovenliggende voorinstelling naar deze voorinstelling en verwijdert de overervingsrelatie. Voorinstellingen die alleen met de bovenliggende voorinstelling compatibel zijn, kunnen daardoor niet meer worden ondersteund."
# AI Translated
msgid "Detach from parent"
msgstr "Losmaken van bovenliggend element"
# AI Translated
msgid "Unique preset"
msgstr "Unieke voorinstelling"
# AI Translated
msgid "Parent preset"
msgstr "Bovenliggende voorinstelling"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Deze voorinstelling erft niet van een andere voorinstelling."
msgid "Name is unavailable."
msgstr "Naam is niet beschikbaar."
@@ -11336,22 +11412,6 @@ msgstr "Weet u zeker dat u deze optie wilt inschakelen?"
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 "Vulpatronen zijn doorgaans ontworpen om rotatie automatisch af te handelen, zodat ze goed printen en hun beoogde effect bereiken (bijv. Gyroide, Kubisch). Het roteren van het huidige patroon voor de dunne vulling (infill) kan tot onvoldoende ondersteuning leiden. Ga voorzichtig te werk en controleer grondig op mogelijke printproblemen. Weet u zeker dat u deze optie wilt inschakelen?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"Laaghoogte is te klein.\n"
"Het zal worden ingesteld op min_layer_height\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "De laaghoogte overschrijdt de limiet in Printerinstellingen -> Extruder -> Laaghoogtelimieten, dit kan problemen met de afdrukkwaliteit veroorzaken."
msgid "Adjust to the set range automatically?\n"
msgstr "Automatisch aanpassen aan het ingestelde bereik?\n"
msgid "Adjust"
msgstr "Aanpassen"
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 "Experimentele functie: Het filament op grotere afstand terugtrekken en afsnijden tijdens filamentwisselingen om flush te minimaliseren. Hoewel het het doorspoelen aanzienlijk kan verminderen, kan het ook het risico op een verstopt mondstuk of andere printcomplicaties vergroten."
@@ -11551,6 +11611,9 @@ msgstr "Gereserveerde zoekworden gevonden"
msgid "Setting Overrides"
msgstr "Overschrijvingen instellen"
msgid "Retraction when switching material"
msgstr "Terugtrekken (retraction) bij het wisselen van filament"
msgid "Basic information"
msgstr "Basisinformatie"
@@ -11689,6 +11752,14 @@ msgstr "Geschikte proces profielen"
msgid "Printable space"
msgstr "Ruimte waarbinnen geprint kan worden"
# AI Translated
msgid "Printer Agent"
msgstr "Printeragent"
# AI Translated
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Selecteer de implementatie van de netwerkagent voor de communicatie met de printer. Beschikbare agenten worden bij het opstarten geregistreerd."
# AI Translated
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
@@ -11829,9 +11900,6 @@ msgstr "Limieten voor laaghoogte"
msgid "Z-Hop"
msgstr "Z-hop"
msgid "Retraction when switching material"
msgstr "Terugtrekken (retraction) bij het wisselen van filament"
# AI Translated
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
@@ -13323,6 +13391,10 @@ msgstr " bevindt zich te dicht bij het uitsluitingsgebied en er zullen botsingen
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " ligt te dicht bij het gebied voor klontdetectie, waardoor er botsingen zullen ontstaan.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " ligt gedeeltelijk buiten het printbare gebied en kan niet worden geprint.\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."
msgstr "De geselecteerde mondstuktemperaturen zijn niet compatibel. De mondstuktemperatuur van elk filament moet binnen het aanbevolen mondstuktemperatuurbereik van de andere filamenten vallen. Anders kan het mondstuk verstopt raken of kan de printer beschadigd raken."
@@ -13686,10 +13758,6 @@ msgstr "3MF gebruiken in plaats van G-code"
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 "Schakel dit in als de printer een 3MF-bestand als printopdracht accepteert. Indien ingeschakeld verzendt Orca Slicer het geslicede bestand als een .gcode.3mf in plaats van als een gewoon .gcode-bestand."
# AI Translated
msgid "Printer Agent"
msgstr "Printeragent"
# AI Translated
msgid "Select the network agent implementation for printer communication."
msgstr "Selecteer de implementatie van de netwerkagent voor de communicatie met de printer."
@@ -14443,9 +14511,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "Snelheid van interne bruggen. Als de waarde als percentage wordt uitgedrukt, wordt deze berekend op basis van bridge_speed. De standaardwaarde is 150%."
msgid "Brim width"
msgstr "Rand breedte"
msgid "This is the distance from the model to the outermost brim line."
msgstr "Dit is de afstand van het model tot de buitenste randlijn."
@@ -14537,6 +14602,14 @@ msgstr ""
"De geometrie wordt vereenvoudigd voordat scherpe hoeken worden gedetecteerd. Deze parameter geeft de minimale lengte van de afwijking voor die vereenvoudiging aan.\n"
"0 om uit te schakelen."
# AI Translated
msgid "Brim ears outer only"
msgstr "Randoren alleen aan de buitenzijde"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Genereert alleen muisoren op de buitencontour van het model, met uitsluiting van gaten en gesloten secties."
msgid "upward compatible machine"
msgstr "opwaarts compatibele machine"
@@ -15846,6 +15919,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "Gyroide"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Afvlakkingsfactor voor dunne vulling"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Bepaalt hoe sterk de hoeken van de dunne vulling worden afgerond. 0% behoudt het oorspronkelijke scherpe pad, terwijl 100% de grootst mogelijke bochten tussen aangrenzende vullijnen oplevert."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "Versnelling van de topoppervlakte-invulling. Gebruik van een lagere waarde kan de kwaliteit van de bovenlaag verbeteren."
@@ -16456,6 +16537,14 @@ msgstr "Het type G-code waarmee de printer compatibel is."
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "G-code-configuratieblok overslaan"
# AI Translated
msgid "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."
msgstr "Schrijft het CONFIG_BLOCK (de sleutel/waarde-paren van de slicerconfiguratie) niet naar het G-code-bestand. Dit kan helpen bij printers waarvan de firmware vastloopt bij het verwerken van deze commentaarregels (bijv. Anycubic go-klipper). Let op: het G-code-bestand bevat dan geen slicerinstellingen meer, dus door het weer in OrcaSlicer te importeren wordt de configuratie niet hersteld."
# AI Translated
msgid "Pellet Modded Printer"
msgstr "Printer omgebouwd voor pellets"
@@ -17653,6 +17742,14 @@ msgstr "Lange terugtrekking bij extruderwissel"
msgid "Retraction distance when extruder change"
msgstr "Terugtrekafstand bij extruderwissel"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "Terugtreklengte (Gereedschapswissel)"
# 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 "Wanneer het terugtrekken vóór een gereedschapswissel wordt geactiveerd, wordt het filament met de opgegeven hoeveelheid teruggetrokken (de lengte wordt gemeten op het onbewerkte filament, voordat het de extruder ingaat)."
# AI Translated
msgid "Z-hop height"
msgstr "Z-hop-hoogte"
@@ -17763,6 +17860,10 @@ msgstr "Extra lengte bij herstart"
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 "Als retracten wordt gecompenseerd na een beweging, wordt deze extra hoeveelheid filament geëxtrudeerd. Deze instelling is zelden van toepassing."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "Extra lengte bij herstart (Gereedschapswissel)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "Als retracten wordt gecompenseerd na een toolwisseling, wordt deze extra hoeveelheid filament geëxtrudeerd."
@@ -18255,6 +18356,14 @@ msgstr "Toolwissel op het afveegblok"
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 "Dwing de printkop naar het afveegblok te bewegen voordat de opdracht voor de toolwissel (Tx) wordt gegeven. Alleen relevant voor printers met meerdere extruders (meerdere printkoppen) die een afveegblok van type 2 gebruiken. Standaard slaat Orca deze verplaatsing op machines met meerdere printkoppen over, omdat de firmware de kopwissel afhandelt, waardoor de Tx-opdracht boven het geprinte onderdeel kan worden gegeven. Schakel deze optie in als u wilt dat de toolwissel altijd boven het afveegblok wordt uitgevoerd."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "Wachten op temperatuur bij het afveegblok"
# 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 "Pakt het nieuwe gereedschap op zonder te wachten tot het de printtemperatuur bereikt, verplaatst zich naar het afveegblok en wacht daar op de temperatuur, vlak voor het spoelen. Het materiaal dat tijdens het opwarmen uitloopt komt op het blok terecht in plaats van op het model, en de verplaatsing overlapt met het opwarmen. Alleen relevant voor printers met meerdere extruders (meerdere printkoppen) die een afveegblok van type 2 gebruiken. De firmware of de gereedschapswisselmacro mag niet zelf op de temperatuur wachten. Wanneer dit is uitgeschakeld, wordt het wachten op de temperatuur direct na het gereedschapswisselcommando uitgevoerd."
# AI Translated
msgid "No sparse layers (beta)"
msgstr "Geen dunne lagen (bèta)"
@@ -21860,10 +21969,6 @@ msgstr "Fysieke printer"
msgid "Print Host upload"
msgstr "Host-upload afdrukken"
# AI Translated
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Selecteer de implementatie van de netwerkagent voor de communicatie met de printer. Beschikbare agenten worden bij het opstarten geregistreerd."
# AI Translated
msgid "Select a Flashforge printer"
msgstr "Selecteer een Flashforge-printer"
@@ -22918,9 +23023,6 @@ msgstr "Er is iets onverwachts gebeurd bij het inloggen. Probeer het opnieuw."
msgid "User canceled."
msgstr "Gebruiker geannuleerd."
msgid "Head diameter"
msgstr "Kopdiameter"
# AI Translated
msgid "Max angle"
msgstr "Maximale hoek"
@@ -23781,6 +23883,22 @@ 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?"
#~ msgid ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "Laaghoogte is te klein.\n"
#~ "Het zal worden ingesteld op min_layer_height\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "De laaghoogte overschrijdt de limiet in Printerinstellingen -> Extruder -> Laaghoogtelimieten, dit kan problemen met de afdrukkwaliteit veroorzaken."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "Automatisch aanpassen aan het ingestelde bereik?\n"
#~ msgid "Head diameter"
#~ msgstr "Kopdiameter"
# AI Translated
#~ msgid "Print order within a single layer."
#~ msgstr "Printvolgorde binnen één laag."
+157 -39
View File
@@ -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-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: Krzysztof Morga <<tlumaczeniebs@gmail.com>>\n"
"Language-Team: \n"
@@ -4843,6 +4843,23 @@ msgstr "Obecna temperatura komory jest wyższa niż bezpieczna temperatura dla f
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "Minimalna temperatura komory (%d℃) jest wyższa niż docelowa temperatura komory (%d℃). Wartość minimalna to próg, przy którym rozpoczyna się druk, podczas gdy komora nadal nagrzewa się do wartości docelowej, więc nie powinna jej przekraczać. Zostanie ograniczona do wartości docelowej."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "Wysokość warstwy jest zbyt mała. Zostanie ustawiona na minimum (%g mm)."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Wysokość warstwy wykracza poza limity ustawione w Ustawieniach Drukarki -> Ekstruder -> Limity wysokości warstwy, co może powodować problemy z jakością druku."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "Dostosować ją automatycznie do limitu (%g mm)?"
msgid "Adjust"
msgstr "Dostosuj"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4965,6 +4982,13 @@ msgstr ""
"Tak — włącz generator ścian Arachne\n"
"Nie — wyłącz generator ścian Arachne i ustaw tryb [Przesunięcie] skóry fuzzy"
# AI Translated
msgid "Brim ear radius"
msgstr "Promień ucha brim"
msgid "Brim width"
msgstr "Szerokość brimu"
# AI Translated
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 "Tryb spiralny działa tylko wtedy, gdy liczba pętli ściany wynosi 1, podpory są wyłączone, wykrywanie zlepiania przez sondowanie jest wyłączone, liczba warstw górnej powłoki wynosi 0, gęstość wypełnienia wynosi 0, a typ timelapse jest tradycyjny."
@@ -5226,6 +5250,14 @@ msgstr "Nie udało się wygenerować kodu kalibracji"
msgid "Calibration error"
msgstr "Błąd kalibracji"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "Ta drukarka nie ma skonfigurowanego sprzętu wymaganego przez ten element sterujący."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Ten element sterujący nie jest obsługiwany przez tę drukarkę."
# AI Translated
msgid "Network unavailable"
msgstr "Sieć niedostępna"
@@ -6109,7 +6141,7 @@ msgstr "Objętość:"
msgid "Size:"
msgstr "Rozmiar:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "Wykryto konflikty ścieżek G-code na warstwie %d, Z = %.2lfmm. Proszę oddalić od siebie obiekty będące w konflikcie (%s <-> %s)."
@@ -6295,6 +6327,10 @@ msgstr "Wiele urządzeń"
msgid "Project"
msgstr "Projekt"
# AI Translated
msgid "Device (Web)"
msgstr "Urządzenie (Web)"
msgid "Yes"
msgstr "Tak"
@@ -8444,22 +8480,22 @@ msgid "Replaced with 3D files from directory:\n"
msgstr "Zastąpiono plikami 3D z katalogu:\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ Pominięto %s: ten sam plik.\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ Pominięto %s: plik nie istnieje.\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ Pominięto %s: nie udało się zastąpić.\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ Zastąpiono %s.\n"
@@ -9232,6 +9268,18 @@ msgstr "Umożliwia wysyłanie zadania do wielu urządzeń jednocześnie i zarzą
msgid "Pop up to select filament grouping mode"
msgstr "Okno dialogowe do wyboru trybu grupowania filamentów"
# AI Translated
msgid "Visible plugin pages"
msgstr "Widoczne strony wtyczek"
# AI Translated
msgid "pages"
msgstr "stron"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "Liczba stron wtyczek wyświetlanych jako stałe karty, zanim pozostałe strony zostaną zwinięte do listy rozwijanej na ostatniej karcie."
# AI Translated
msgid "Behaviour"
msgstr "Zachowanie"
@@ -9647,6 +9695,18 @@ msgstr "Pokaż nieobsługiwane profile"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "Pokazuj niekompatybilne/nieobsługiwane profile na listach rozwijanych drukarek i filamentów. Tych profili nie można wybrać."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Eksperymentalne) Używaj agentów drukarki zamiast serwerów druku"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Kieruje zadania druku dla drukarek innych niż Bambu przez agentów wtyczek drukarki zamiast klasycznego przesyłania do serwera druku.\n"
"Gdy opcja jest wyłączona, OrcaSlicer korzysta z dotychczasowego działania serwera druku."
# AI Translated
msgid "Experimental Features"
msgstr "Funkcje eksperymentalne"
@@ -9918,10 +9978,26 @@ msgstr "Profil użytkownika"
msgid "Preset Inside Project"
msgstr "Profil wewnątrz projektu"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Kopiuje do tego profilu wszystkie wartości odziedziczone z profilu nadrzędnego i usuwa relację dziedziczenia. Profile zgodne wyłącznie z profilem nadrzędnym mogą przestać być obsługiwane."
# AI Translated
msgid "Detach from parent"
msgstr "Odłącz od elementu nadrzędnego"
# AI Translated
msgid "Unique preset"
msgstr "Profil niezależny"
# AI Translated
msgid "Parent preset"
msgstr "Profil nadrzędny"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Ten profil nie dziedziczy z innego profilu."
msgid "Name is unavailable."
msgstr "Nazwa jest niedostępna."
@@ -10684,22 +10760,6 @@ msgstr "Czy na pewno włączyć tę opcję?"
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 "Wzory wypełnienia są zwykle projektowane tak, aby samodzielnie obsługiwać obrót, co zapewnia prawidłowy druk i zamierzony efekt (np. Gyroidalny, Sześcienny). Obracanie bieżącego wzoru wypełnienia może prowadzić do niewystarczającego podparcia. Zachowaj ostrożność i dokładnie sprawdź, czy nie występują problemy z drukiem. Czy na pewno chcesz włączyć tę opcję?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"Wysokość warstwy jest zbyt mała.\n"
"Ustawione zostanie na min_layer_height\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Wysokość warstwy przekracza limit w Ustawieniach Drukarki -> Extruder -> Limity wysokości warstwy, co może powodować problemy z jakością druku."
msgid "Adjust to the set range automatically?\n"
msgstr "Dostosować automatycznie do ustawionego zakresu?\n"
msgid "Adjust"
msgstr "Dostosuj"
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 "Funkcja eksperymentalna: Polega na wycofywaniu filamentu na większą odległość w celu zminimalizowania płukania, a następne jego odcięcie. Choć może to znacząco zmniejszyć ilość zużytego filamentu, może również zwiększyć ryzyko zatknięcia dyszy lub innych problemów z drukowaniem."
@@ -10899,6 +10959,9 @@ msgstr "Znaleziono zarezerwowane słowa kluczowe"
msgid "Setting Overrides"
msgstr "Nadpisywane Ustawień"
msgid "Retraction when switching material"
msgstr "Retrakcja podczas zmiany filamentu"
msgid "Basic information"
msgstr "Podstawowe informacje"
@@ -11033,6 +11096,14 @@ msgstr "Kompatybilne profile procesów"
msgid "Printable space"
msgstr "Przestrzeń do druku"
# AI Translated
msgid "Printer Agent"
msgstr "Agent drukarki"
# AI Translated
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Wybierz implementację agenta sieciowego do komunikacji z drukarką. Dostępni agenci są rejestrowani przy uruchamianiu."
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -11165,9 +11236,6 @@ msgstr "Ograniczenia wysokości warstwy"
msgid "Z-Hop"
msgstr "Z-Hop"
msgid "Retraction when switching material"
msgstr "Retrakcja podczas zmiany filamentu"
# AI Translated
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
@@ -12559,6 +12627,10 @@ msgstr " jest zbyt blisko obszaru wykluczenia, mogą wystąpić kolizje.\n"
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " jest zbyt blisko obszaru wykrywania zalepienia dyszy, co doprowadzi do kolizji.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " znajduje się częściowo poza obszarem druku i nie może zostać wydrukowany.\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."
msgstr "Wybrane temperatury dyszy są niezgodne. Temperatura dyszy każdego filamentu musi mieścić się w zalecanym zakresie temperatur dyszy pozostałych filamentów. W przeciwnym razie może dojść do zatkania dyszy lub uszkodzenia drukarki."
@@ -12901,10 +12973,6 @@ msgstr "Użyj 3MF zamiast G-code"
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 "Włącz tę opcję, jeśli drukarka przyjmuje plik 3MF jako zadanie druku. Po włączeniu Orca Slicer wysyła plik po cięciu jako .gcode.3mf zamiast zwykłego pliku .gcode."
# AI Translated
msgid "Printer Agent"
msgstr "Agent drukarki"
# AI Translated
msgid "Select the network agent implementation for printer communication."
msgstr "Wybierz implementację agenta sieciowego do komunikacji z drukarką."
@@ -13617,9 +13685,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "Prędkość wewnętrznych mostów. Jeśli wartość jest wyrażona w procentach, będzie obliczana na podstawie prędkości mostu. Wartość domyślna wynosi 150%."
msgid "Brim width"
msgstr "Szerokość brimu"
msgid "This is the distance from the model to the outermost brim line."
msgstr "Odległość od modelu do najbardziej zewnętrznej linii brimu"
@@ -13703,6 +13768,14 @@ msgstr ""
"Kształt zostanie zredukowany przed wykryciem ostrych kątów. Ten parametr wskazuje minimalną długość odchylenia dla redukcji.\n"
"0, aby dezaktywować"
# AI Translated
msgid "Brim ears outer only"
msgstr "Uszy brim tylko na zewnątrz"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Generuje uszy myszy tylko na zewnętrznym obrysie modelu, z pominięciem otworów i zamkniętych sekcji."
msgid "upward compatible machine"
msgstr "drukarka kompatybilna i wzwyż"
@@ -14896,6 +14969,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "Gyroidalny"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Współczynnik wygładzania wypełnienia"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Określa, jak mocno zaokrąglane są narożniki wypełnienia. 0% zachowuje oryginalną ostrą ścieżkę, a 100% tworzy największe możliwe łuki pomiędzy sąsiednimi liniami wypełnienia."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "Przyspieszenie dla wypełnienia górnej powierzchni. Użycie niższej wartości może poprawić jakość górnej powierzchni"
@@ -15459,6 +15540,14 @@ msgstr "Z jakim rodzajem G-code drukarka jest kompatybilna."
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "Pomiń blok konfiguracyjny G-code"
# AI Translated
msgid "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."
msgstr "Nie zapisuje bloku CONFIG_BLOCK (par klucz/wartość z konfiguracją slicera) do pliku G-code. Może to pomóc w przypadku drukarek, których firmware ulega awarii podczas przetwarzania tych linii komentarza (np. Anycubic go-klipper). Uwaga: plik G-code nie będzie już zawierał ustawień slicera, więc ponowne zaimportowanie go do OrcaSlicer nie przywróci konfiguracji."
msgid "Pellet Modded Printer"
msgstr "Drukarka do druku granulatem"
@@ -16571,6 +16660,14 @@ msgstr "Długa retrakcja podczas zmian ekstruderów"
msgid "Retraction distance when extruder change"
msgstr "Długość retrakcji podczas zmian ekstruderów"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "Długość retrakcji (Zmiana narzędzia)"
# 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 "Gdy retrakcja jest wyzwalana przed zmianą narzędzia, filament zostaje wycofany o określoną wartość (długość mierzona jest na surowym filamencie, przed wejściem do ekstrudera)."
msgid "Z-hop height"
msgstr "Wysokość Z-hop"
@@ -16669,6 +16766,10 @@ msgstr "Dodatkowa ilość dla powrotu"
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 "Gdy retrakcja jest kompensowana po przemieszczeniu, ekstruder przepycha tę dodatkową ilość filamentu. To opcja jest rzadko potrzebna."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "Dodatkowa ilość dla powrotu (Zmiana narzędzia)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "Jeśli retrakcja jest korygowana po zmianie narzędzia, extruder przepchnie taką dodatkową ilość filamentu."
@@ -17099,6 +17200,14 @@ msgstr "Zmiana narzędzia na wieży czyszczącej"
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 "Wymusza przemieszczenie głowicy do wieży czyszczącej przed wydaniem polecenia zmiany narzędzia (Tx). Dotyczy tylko drukarek wieloekstruderowych (wielogłowicowych) korzystających z wieży czyszczącej typu 2. Domyślnie Orca pomija to przemieszczenie na maszynach wielogłowicowych, ponieważ zamianą głowic zajmuje się oprogramowanie sprzętowe, przez co polecenie Tx może zostać wydane nad drukowaną częścią. Włącz tę opcję, jeśli chcesz, aby zmiana narzędzia zawsze następowała nad wieżą czyszczącą."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "Czekaj na temperaturę na wieży czyszczącej"
# 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 "Pobiera nowe narzędzie bez czekania, aż osiągnie temperaturę druku, przejeżdża do wieży czyszczącej i tam czeka na temperaturę, tuż przed płukaniem. Materiał wyciekający podczas nagrzewania trafia na wieżę zamiast na model, a przejazd nakłada się na nagrzewanie. Dotyczy wyłącznie drukarek z wieloma ekstruderami (wieloma głowicami) używających wieży czyszczącej typu 2. Firmware ani makro zmiany narzędzia nie mogą samodzielnie czekać na temperaturę. Gdy opcja jest wyłączona, oczekiwanie na temperaturę jest wysyłane bezpośrednio po poleceniu zmiany narzędzia."
msgid "No sparse layers (beta)"
msgstr "Warstwy bez czyszczenia (beta)"
@@ -20445,10 +20554,6 @@ msgstr "Fizyczna drukarka"
msgid "Print Host upload"
msgstr "Przesyłanie do hosta drukowania"
# AI Translated
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Wybierz implementację agenta sieciowego do komunikacji z drukarką. Dostępni agenci są rejestrowani przy uruchamianiu."
# AI Translated
msgid "Select a Flashforge printer"
msgstr "Wybierz drukarkę Flashforge"
@@ -21401,9 +21506,6 @@ msgstr "Wystąpił problem podczas próby logowania, proszę spróbować ponowni
msgid "User canceled."
msgstr "Anulowane przez użytkownika."
msgid "Head diameter"
msgstr "Średnica łącznika"
msgid "Max angle"
msgstr "Maksymalny kąt"
@@ -22234,6 +22336,22 @@ 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 ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "Wysokość warstwy jest zbyt mała.\n"
#~ "Ustawione zostanie na min_layer_height\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "Wysokość warstwy przekracza limit w Ustawieniach Drukarki -> Extruder -> Limity wysokości warstwy, co może powodować problemy z jakością druku."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "Dostosować automatycznie do ustawionego zakresu?\n"
#~ msgid "Head diameter"
#~ msgstr "Średnica łącznika"
#~ 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"
+159 -43
View File
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: 2026-07-26 11:14-0300\n"
"Last-Translator: Alexandre Folle de Menezes\n"
"Language-Team: Portuguese, Brazilian\n"
@@ -4577,6 +4577,23 @@ msgstr "A temperatura da câmara atual está mais alta do que a temperatura segu
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "A temperatura mínima da câmara (%d℃) é superior à temperatura alvo da câmara (%d℃). O valor mínimo é o limite no qual a impressão começa enquanto a câmara continua aquecendo em direção ao alvo; portanto, não deve execedê-lo. O valor será limitado ao alvo."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "A altura da camada é muito pequena. Ela será definida para o mínimo (%g mm)."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "A altura da camada está fora dos limites definidos em Configurações da Impressora -> Extrusora -> Limites de altura da camada, isso pode causar problemas de qualidade de impressão."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "Ajustar automaticamente para o limite (%g mm)?"
msgid "Adjust"
msgstr "Ajustar"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4696,6 +4713,13 @@ msgstr ""
"Sim - Habilitar Gerador de Parede Arachne\n"
"Não - Desabilitar Gerador de Parede Arachne e setar o modo [Deslocamento] da Textura Difusa"
# AI Translated
msgid "Brim ear radius"
msgstr "Raio da orelha da borda"
msgid "Brim width"
msgstr "Largura da borda"
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 "O modo espiral só funciona quando as voltas da parede são 1, o suporte está desativado, a detecção de aglomeração por sondagem está desativada, as camadas da casca de topo são 0, a densidade de preenchimento esparso é 0 e o tipo de timelapse é tradicional."
@@ -4950,6 +4974,14 @@ msgstr "Falha ao gerar o G-code de calibração"
msgid "Calibration error"
msgstr "Erro de calibração"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "Esta impressora não está configurada com o hardware que este controle requer."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Este controle não é suportado nesta impressora."
msgid "Network unavailable"
msgstr "Rede indisponível"
@@ -5793,7 +5825,7 @@ msgstr "Volume:"
msgid "Size:"
msgstr "Tamanho:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "Foram encontrados conflitos de caminhos de G-code na camada %d, Z = %.2lfmm. Por favor, separe mais os objetos em conflito (%s <-> %s)."
@@ -5974,6 +6006,10 @@ msgstr "Multi-dispositivo"
msgid "Project"
msgstr "Projeto"
# AI Translated
msgid "Device (Web)"
msgstr "Dispositivo (Web)"
msgid "Yes"
msgstr "Sim"
@@ -8020,19 +8056,19 @@ 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"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ %s Ignorados: mesmo arquivo.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ %s Ignorados: arquivo não existe.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ %s Ignorados: falha ao substituir.\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ %s Substituídos.\n"
@@ -8759,6 +8795,18 @@ msgstr "Com esta opção habilitada, você pode enviar uma tarefa para vários d
msgid "Pop up to select filament grouping mode"
msgstr "Abrir seleção do modo de agrupamento de filamento"
# AI Translated
msgid "Visible plugin pages"
msgstr "Páginas de plugin visíveis"
# AI Translated
msgid "pages"
msgstr "páginas"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "Número de páginas de plugin exibidas como abas fixas antes que as páginas restantes sejam agrupadas em um menu suspenso na última aba."
msgid "Behaviour"
msgstr "Comportamento"
@@ -9113,6 +9161,18 @@ msgstr "Mostrar predefinições não suportadas"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "Exibir predefinições incompatíveis e não suportadas nas listas de impressora e filamento. Essas predefinições não podem ser selecionadas."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Experimental) Usar agentes de impressora em vez de hosts de impressão"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Encaminha os trabalhos de impressão de impressoras que não são Bambu pelos agentes de plugin de impressora em vez do fluxo clássico de envio ao host de impressão.\n"
"Quando desativado, o OrcaSlicer usa o comportamento antigo do host de impressão."
msgid "Experimental Features"
msgstr "Recursos Experimentais"
@@ -9374,9 +9434,25 @@ msgstr "Predefinição do Usuário"
msgid "Preset Inside Project"
msgstr "Predefinição Dentro do Projeto"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Copia para esta predefinição todos os valores herdados da predefinição pai e remove a relação de herança. Predefinições compatíveis apenas com a predefinição pai podem deixar de ser suportadas."
msgid "Detach from parent"
msgstr "Separar do pai"
# AI Translated
msgid "Unique preset"
msgstr "Predefinição única"
# AI Translated
msgid "Parent preset"
msgstr "Predefinição pai"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Esta predefinição não herda de outra predefinição."
msgid "Name is unavailable."
msgstr "O nome não está disponível."
@@ -10096,24 +10172,6 @@ msgstr "Tem certeza de que deseja habilitar esta opção?"
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 "Padrões de preenchimento são projetados para lidar com a rotação automaticamente para garantir a impressão adequada e atingir os efeitos pretendidos (Ex. Giroide, Cúbico). Girar o padrão de preenchimento esparso atual pode causar suporte insuficiente. Prossiga com cautela e verifique cuidadosamente se há possíveis problemas de impressão. Tem certeza de que deseja habilitar esta opção?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"A altura da camada é muito pequena.\n"
"Ela será definida como altura mínima da camada\n"
"A altura da camada é muito pequena.\n"
"Ela será definida como altura mínima da camada\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "A altura da camada excede o limite em Configurações da Impressora -> Extrusora -> Limites de altura da camada, isso pode causar problemas de qualidade de impressão."
msgid "Adjust to the set range automatically?\n"
msgstr "Ajustar automaticamente à faixa definida?\n"
msgid "Adjust"
msgstr "Ajustar"
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 "Funcionalidade experimental: Retrair e cortar o filamento a uma distância maior durante mudanças de filamento para minimizar a purga. Embora possa reduzir notavelmente a purga, ele também pode elevar o risco de bolhas no bico ou outras complicações de impressão."
@@ -10308,6 +10366,9 @@ msgstr "Palavras-chave reservadas encontradas"
msgid "Setting Overrides"
msgstr "Sobrescrever configurações"
msgid "Retraction when switching material"
msgstr "Retração ao trocar material"
msgid "Basic information"
msgstr "Informações básicas"
@@ -10435,6 +10496,12 @@ msgstr "Perfis de processo compatíveis"
msgid "Printable space"
msgstr "Espaço de impressão"
msgid "Printer Agent"
msgstr "Agente de Impressora"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Selecione a implementação do agente de rede para comunicação com a impressora. Os agentes disponíveis são registrados na inicialização."
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10560,9 +10627,6 @@ msgstr "Limites de altura da camada"
msgid "Z-Hop"
msgstr "Z-Hop"
msgid "Retraction when switching material"
msgstr "Retração ao trocar material"
# AI Translated
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
@@ -11893,6 +11957,10 @@ msgstr " está muito perto de uma área de exclusão, e colisões vão ocorrer.\
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " está muito perto da área de detecção de aglomeração, e ocorrerão colisões.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " está parcialmente fora da área imprimível, e não pode ser impresso.\n"
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."
msgstr "As temperaturas dos bicos selecionadas são incompatíveis. A temperatura do bico de cada filamento deve estar dentro da faixa de temperatura recomendada para os demais filamentos. Caso contrário, pode ocorrer entupimento do bico ou danos à impressora."
@@ -12206,9 +12274,6 @@ msgstr "Usar 3MF em vez de G-code"
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 "Ative esta opção se a impressora aceitar um arquivo 3MF como trabalho de impressão. Quando ativada, o OrcaSlicer envia o arquivo fatiado como .gcode.3mf, em vez de um arquivo .gcode comum."
msgid "Printer Agent"
msgstr "Agente de Impressora"
msgid "Select the network agent implementation for printer communication."
msgstr "Selecione a implementação do agente de rede para comunicação com a impressora."
@@ -12888,9 +12953,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "Velocidade de pontes internas. Se o valor for expresso como uma porcentagem, ele será calculado com base na bridge_speed. O valor padrão é 150%."
msgid "Brim width"
msgstr "Largura da borda"
msgid "This is the distance from the model to the outermost brim line."
msgstr "Essa é a distância do modelo até a linha da borda mais externa."
@@ -12970,6 +13032,14 @@ msgstr ""
"A geometria será decimada antes de detectar ângulos agudos. Este parâmetro indica o comprimento mínimo da divergência para a decimação.\n"
"0 para desativar."
# AI Translated
msgid "Brim ears outer only"
msgstr "Orelhas da borda apenas externas"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Gera orelhas de rato apenas no contorno externo do modelo, excluindo furos e seções fechadas."
msgid "upward compatible machine"
msgstr "uáquina compatível ascendente"
@@ -14104,6 +14174,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "Giroide"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Fator de suavização do preenchimento esparso"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Controla o quanto os cantos do preenchimento esparso são arredondados. 0% mantém o trajeto original com cantos vivos, enquanto 100% produz as maiores curvas possíveis entre linhas de preenchimento adjacentes."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "Esta é a aceleração do preenchimento da superfície superior. Usar um valor menor pode melhorar a qualidade da superfície superior."
@@ -14639,6 +14717,14 @@ msgstr "Com que tipo de G-code a impressora é compatível."
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "Omitir o bloco de configuração do G-code"
# AI Translated
msgid "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."
msgstr "Não grava o CONFIG_BLOCK (os pares chave/valor da configuração do fatiador) no arquivo G-code. Isso pode ajudar com impressoras cujo firmware trava ao interpretar essas linhas de comentário (por exemplo, Anycubic go-klipper). Observação: o arquivo G-code não conterá mais as configurações do fatiador, então importá-lo de volta no OrcaSlicer não restaurará a configuração."
msgid "Pellet Modded Printer"
msgstr "Impressora Modificada para Pellets"
@@ -15157,7 +15243,6 @@ 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"
#, fuzzy
msgid "N"
msgstr "N"
@@ -15167,9 +15252,9 @@ 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"
#, fuzzy
# AI Translated
msgid "g"
msgstr "G"
msgstr "g"
msgid "The allowed max printed mass"
msgstr "Massa máxima de impressão permitida"
@@ -15681,6 +15766,14 @@ 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)"
# 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"
@@ -15774,6 +15867,10 @@ 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)"
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."
@@ -16182,6 +16279,14 @@ 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."
msgid "No sparse layers (beta)"
msgstr "Sem camadas esparsas (beta)"
@@ -16733,7 +16838,6 @@ msgstr "Volume de preparo"
msgid "This is the volume of material to prime the extruder with on the tower."
msgstr "Este é o volume de material para preparar a extrusora na torre."
#,fuzzy
msgid "Prime volume mode"
msgstr "Modo de volume de preparação"
@@ -19369,9 +19473,6 @@ msgstr "Impressora Física"
msgid "Print Host upload"
msgstr "Upload do Host de Impressão"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Selecione a implementação do agente de rede para comunicação com a impressora. Os agentes disponíveis são registrados na inicialização."
msgid "Select a Flashforge printer"
msgstr "Selecione uma impressora Flashforge"
@@ -20213,9 +20314,6 @@ msgstr "Algo inesperado aconteceu ao tentar conectar, por favor tente novamente.
msgid "User canceled."
msgstr "Cancelado pelo usuário."
msgid "Head diameter"
msgstr "Diâmetro da cabeça"
msgid "Max angle"
msgstr "Ângulo máx"
@@ -20949,6 +21047,24 @@ 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 ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "A altura da camada é muito pequena.\n"
#~ "Ela será definida como altura mínima da camada\n"
#~ "A altura da camada é muito pequena.\n"
#~ "Ela será definida como altura mínima da camada\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "A altura da camada excede o limite em Configurações da Impressora -> Extrusora -> Limites de altura da camada, isso pode causar problemas de qualidade de impressão."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "Ajustar automaticamente à faixa definida?\n"
#~ msgid "Head diameter"
#~ msgstr "Diâmetro da cabeça"
#~ msgid "Print order within a single layer."
#~ msgstr "Ordem de impressão dentro de uma única camada."
+188 -50
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: OrcaSlicer V2.5.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-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"
@@ -4715,6 +4715,23 @@ msgstr "Текущая температура внутри термокамер
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "Стартовая температура внутри термокамеры (%d℃) превышает целевую (%d℃). Подразумевается, что печать начинается заранее, поэтому стартовая температура не должна превышать её. Значение будет уменьшено."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "Высота слоя слишком мала. Будет установлено минимальное значение (%g мм)."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Высота слоя выходит за пределы, заданные в настройках принтера → Экструдер → Ограничение высоты слоя. Это может вызвать проблемы с качеством печати."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "Автоматически подстроить под предел (%g мм)?"
msgid "Adjust"
msgstr "Подстроиться"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4839,6 +4856,13 @@ msgid ""
"No - Disable Arachne Wall Generator and set [Displacement] mode of the Fuzzy Skin"
msgstr "Использовать нечёткую оболочку с движком Arachne?"
# AI Translated
msgid "Brim ear radius"
msgstr "Радиус ушек каймы"
msgid "Brim width"
msgstr "Ширина каймы"
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 ""
"Для печати в режиме вазы необходимы следующие настройки:\n"
@@ -5107,6 +5131,14 @@ msgstr "Не удалось сгенерировать калибровочны
msgid "Calibration error"
msgstr "Ошибка калибровки"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "На этом принтере не настроено оборудование, необходимое для этого элемента управления."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Этот элемент управления не поддерживается на этом принтере."
msgid "Network unavailable"
msgstr "Сеть недоступна"
@@ -5991,7 +6023,7 @@ msgstr "Объём:"
msgid "Size:"
msgstr "Размер:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "В G-коде на %d слое (z = %.2lf мм) обнаружен конфликт путей. Пожалуйста, разместите конфликтующие модели дальше друг от друга (%s <-> %s)."
@@ -6198,6 +6230,10 @@ msgstr "Принтеры"
msgid "Project"
msgstr "Проект"
# AI Translated
msgid "Device (Web)"
msgstr "Принтер (веб)"
msgid "Yes"
msgstr "Да"
@@ -8299,19 +8335,19 @@ msgstr "Расположение для замены не указано"
msgid "Replaced with 3D files from directory:\n"
msgstr "Заменено файлами из расположения:\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ Пропущен %s: идентичный файл.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ Пропущен %s: файл не существует.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ Пропущен %s: не удалось заменить.\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ Заменён %s.\n"
@@ -9040,6 +9076,18 @@ msgstr "Если включено, вы сможете управлять нес
msgid "Pop up to select filament grouping mode"
msgstr "Всплывающее окно для выбора режима группировки материалов"
# AI Translated
msgid "Visible plugin pages"
msgstr "Видимые страницы плагинов"
# AI Translated
msgid "pages"
msgstr "стр."
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "Количество страниц плагинов, отображаемых как закреплённые вкладки, прежде чем остальные страницы будут свёрнуты в выпадающий список на последней вкладке."
msgid "Behaviour"
msgstr "Автоматизация"
@@ -9400,6 +9448,18 @@ msgstr ""
"\n"
"Примечание: профили остаются недоступными для выбора."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Экспериментально) Использовать агентов принтера вместо хостов печати"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Отправлять задания печати для принтеров, отличных от Bambu, через агентов плагинов принтера вместо классической загрузки на хост печати.\n"
"Если отключено, OrcaSlicer использует прежнее поведение хоста печати."
msgid "Experimental Features"
msgstr "Экспериментальные настройки"
@@ -9666,9 +9726,25 @@ msgstr "Пользовательский профиль"
msgid "Preset Inside Project"
msgstr "Профиль внутри проекта"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Копирует в этот профиль все значения, унаследованные от родительского профиля, и удаляет связь наследования. Профили, совместимые только с родительским, могут стать неподдерживаемыми."
msgid "Detach from parent"
msgstr "Сделать независимым"
# AI Translated
msgid "Unique preset"
msgstr "Независимый профиль"
# AI Translated
msgid "Parent preset"
msgstr "Родительский профиль"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Этот профиль не наследуется от другого профиля."
msgid "Name is unavailable."
msgstr "Имя недоступно."
@@ -9686,7 +9762,9 @@ msgstr ""
"несовместим с текущим принтером."
msgid "Please note that saving will overwrite the current preset."
msgstr "Обратите внимание: при сохранении произойдёт\nперезапись текущего профиля."
msgstr ""
"Обратите внимание: при сохранении произойдёт\n"
"перезапись текущего профиля."
msgid "The name cannot be the same as a preset alias name."
msgstr "Имя не должно совпадать с именем предустановленного профиля."
@@ -10389,22 +10467,6 @@ msgstr "Вы действительно хотите задействовать
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 "Многие шаблоны заполнения разработаны на основе автоматического поворота по определённым правилам для поддержания правильной печати и желаемого эффекта (например, «Гироид» или «Куб»). Изменение правила поворота текущего шаблона может привести к его провисанию. Будьте осторожны и внимательно проверяйте результат на наличие потенциальных проблем с печатью."
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"Высота слоя слишком мала.\n"
"Будет установлено значение min_layer_height\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Высота слоя не может превышать ограничения, установленные в настройках принтера → Экструдер → Ограничение высоты слоя. Это может вызвать проблемы с качеством печати."
msgid "Adjust to the set range automatically?\n"
msgstr "Автоматически подстроиться под заданный в настройках диапазон?\n"
msgid "Adjust"
msgstr "Подстроиться"
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 "[Экспериментальная функция] Втягивание и обрезка прутка на большем расстоянии во время его замены для минимизации очистки. Хотя это значительно сокращает величину очистки, это может повысить риск возникновения затора или вызвать другие проблемы при печати."
@@ -10604,6 +10666,9 @@ msgstr "Найдены зарезервированные ключевые сл
msgid "Setting Overrides"
msgstr "Замещение настроек"
msgid "Retraction when switching material"
msgstr "Откат при смене материала"
msgid "Basic information"
msgstr "Основные"
@@ -10751,6 +10816,12 @@ msgstr "Совместимые настройки"
msgid "Printable space"
msgstr "Область печати"
msgid "Printer Agent"
msgstr "Сетевой агент"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Реализация сетевого агента для обмена информацией с принтером. Доступные реализации определяются при запуске."
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10879,9 +10950,6 @@ msgstr "Ограничение высоты слоя"
msgid "Z-Hop"
msgstr "Подъём головы при откате"
msgid "Retraction when switching material"
msgstr "Откат при смене материала"
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
"\n"
@@ -12218,6 +12286,10 @@ msgstr " находится слишком близко к области иск
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " находится слишком близко к зоне обнаружения налипаний, столкновения неизбежны.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " частично находится за пределами области печати и не может быть напечатан.\n"
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."
msgstr "Обнаружен недопустимый перепад температур. Каждый из используемых материалов должен иметь в профиле температуру печати в пределах допустимого диапазона других материалов. В противном случае сопло может забиться и повредить принтер."
@@ -12539,9 +12611,6 @@ 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\"."
msgid "Printer Agent"
msgstr "Сетевой агент"
msgid "Select the network agent implementation for printer communication."
msgstr "Реализация сетевого агента для обмена информацией с принтером."
@@ -13232,9 +13301,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "Скорость печати внутреннего моста. Можно указать процент от скорости внешнего моста (bridge_speed). По умолчанию 150%."
msgid "Brim width"
msgstr "Ширина каймы"
msgid "This is the distance from the model to the outermost brim line."
msgstr "Расстояние от модели до внешней линии каймы."
@@ -13316,6 +13382,14 @@ msgstr ""
"Геометрия модели будет упрощена перед обнаружением острых углов. Этот параметр задаёт минимальную длину отклонения для её упрощения.\n"
"Установите 0 для отключения."
# AI Translated
msgid "Brim ears outer only"
msgstr "Ушки каймы только снаружи"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Создавать мышиные ушки только на внешнем контуре модели, исключая отверстия и замкнутые участки."
msgid "upward compatible machine"
msgstr "условия для совместимых принтеров"
@@ -14308,13 +14382,19 @@ msgid "Interface layer pre-extrusion distance"
msgstr "Дистанция избыточной подачи при смене"
msgid "Pre-extrusion distance for prime tower interface layer (where different materials meet)."
msgstr "Протяжённость первичного движения прочистки после смены материала. Позволяет быстро набрать давление в сопле и сбросить перегретый материал.\n\nПримечание: фактическая длина может быть ограничена шириной башни."
msgstr ""
"Протяжённость первичного движения прочистки после смены материала. Позволяет быстро набрать давление в сопле и сбросить перегретый материал.\n"
"\n"
"Примечание: фактическая длина может быть ограничена шириной башни."
msgid "Interface layer pre-extrusion length"
msgstr "Длина прутка для избыточной подачи"
msgid "Pre-extrusion length for prime tower interface layer (where different materials meet)."
msgstr "Длина прутка, которую необходимо продавить на этапе избыточной подачи.\n\n0 – отключить этот этап."
msgstr ""
"Длина прутка, которую необходимо продавить на этапе избыточной подачи.\n"
"\n"
"0 – отключить этот этап."
msgid "Tower ironing area"
msgstr "Разглаживание кончиков"
@@ -14626,6 +14706,14 @@ msgstr "ТПМП Фишера-Коха S"
msgid "Gyroid"
msgstr "Гироид"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Коэффициент сглаживания заполнения"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Определяет, насколько сильно скругляются углы заполнения. 0% сохраняет исходную траекторию с острыми углами, а 100% создаёт максимально возможные скругления между соседними линиями заполнения."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "Ускорение на верхней поверхности. Использование меньшего значения может улучшить качество верхней поверхности."
@@ -15213,6 +15301,14 @@ msgstr "Выбор типа G-кода для совместимости с пр
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "Пропустить блок конфигурации в G-code"
# AI Translated
msgid "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."
msgstr "Не записывать CONFIG_BLOCK (пары ключ/значение с настройками слайсера) в файл G-code. Это может помочь с принтерами, прошивка которых аварийно завершается при разборе этих строк комментариев (например, Anycubic go-klipper). Примечание: файл G-code больше не будет содержать настройки слайсера, поэтому при обратном импорте в OrcaSlicer конфигурация не восстановится."
msgid "Pellet Modded Printer"
msgstr "Гранульная модификация принтера"
@@ -15396,8 +15492,7 @@ msgstr "Наклон опор"
msgid ""
"Controls how aggressively short or unsupported Lightning branches are pruned.\n"
"This angle is converted internally to a per-layer distance."
msgstr ""
"Допустимый наклон опор молнии. Чем выше, тем быстрее и экономичнее распространяются её ветви."
msgstr "Допустимый наклон опор молнии. Чем выше, тем быстрее и экономичнее распространяются её ветви."
# "Выпрямление" здесь, вопреки первой мысли – это как раз-таки наоборот искажение шаблона по ходу печати для сокращения количества ветвей. Короче, опять путаница из-за того, что генерация ветвей происходит сверху вниз. При печати снизу вверх шаблон именно что искажается.
msgid "Straightening angle"
@@ -16309,8 +16404,7 @@ 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"
"Быстрый откат после очистки, выраженный в процентах от общей длины отката. В некоторых случаях позволяет значительно снизить количество «паутины».\n"
"Примечание: суммарное значение не должно превышать 100% и будет скорректировано автоматически."
msgid "Retract on layer change"
@@ -16344,6 +16438,14 @@ msgstr "Длинный откат перед сменой экструдера"
msgid "Retraction distance when extruder change"
msgstr "Длина отката перед сменой экструдера"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "Длина отката (смена инструмента)"
# 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 "При срабатывании отката перед сменой инструмента материал втягивается на указанную величину (длина измеряется по прутку материала до его входа в экструдер)."
msgid "Z-hop height"
msgstr "Высота подъёма"
@@ -16461,6 +16563,10 @@ msgstr "Доп. подача после отката"
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 "Дополнительная длина подачи при возврате прутка после отката. Требуется крайне редко (например, для компенсации багов прошивки принтера)."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "Доп. подача после отката (смена инструмента)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "Дополнительная длина подачи после смены насадки."
@@ -16474,7 +16580,9 @@ msgid "Deretraction speed"
msgstr "Скорость возврата"
msgid "Speed for reloading filament into the nozzle. Zero means same speed of retraction."
msgstr "Скорость возврата материала в сопло после отката.\n0 – использовать скорость отката."
msgstr ""
"Скорость возврата материала в сопло после отката.\n"
"0 – использовать скорость отката."
msgid "Deretraction speed (extruder change)"
msgstr "Скорость возврата (смена экструдера)"
@@ -16945,6 +17053,14 @@ msgstr ""
"\n"
"Внимание: применимо только к многоэкструдерным принтерам с черновой башней 2 типа."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "Ожидание температуры на черновой башне"
# 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 "Забирает новый инструмент, не дожидаясь достижения температуры печати, перемещается к черновой башне и ждёт нагрева там, непосредственно перед прочисткой. Подтёки при нагреве попадают на башню, а не на модель, а перемещение совмещается с нагревом. Актуально только для принтеров с несколькими экструдерами (несколькими печатающими головами), использующих черновую башню типа 2. Прошивка или макрос смены инструмента не должны сами ждать нагрева. Если отключено, команда ожидания температуры выдаётся сразу после команды смены инструмента."
msgid "No sparse layers (beta)"
msgstr "Без разреженных слоёв (beta)"
@@ -17942,13 +18058,21 @@ msgid "To prevent oozing, the nozzle temperature will be cooled during ramming.
msgstr "Во избежание подтёков температура сопла будет снижена на время рэмминга. Поэтому время рэмминга должно быть больше времени охлаждения. 0 значит отключено."
msgid "The maximum volumetric speed for ramming before extruder change, where -1 means using the maximum volumetric speed."
msgstr "Максимальный объёмный расход для рэмминга перед сменой экструдера.\n-1 – использовать максимальный расход."
msgstr ""
"Максимальный объёмный расход для рэмминга перед сменой экструдера.\n"
"-1 – использовать максимальный расход."
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 "Во избежание подтёков температура сопла будет снижена на время рэмминга.\n0 – не менять температуру.\n\nПримечание: срабатывают только команда охлаждения и включение вентилятора; достижение целевой температуры не гарантируется."
msgstr ""
"Во избежание подтёков температура сопла будет снижена на время рэмминга.\n"
"0 – не менять температуру.\n"
"\n"
"Примечание: срабатывают только команда охлаждения и включение вентилятора; достижение целевой температуры не гарантируется."
msgid "The maximum volumetric speed for ramming before a hotend change, where -1 means using the maximum volumetric speed."
msgstr "Максимальный объёмный расход для рэмминга перед сменой хотэнда.\n-1 – использовать максимальный расход."
msgstr ""
"Максимальный объёмный расход для рэмминга перед сменой хотэнда.\n"
"-1 – использовать максимальный расход."
msgid "length when change hotend"
msgstr "Откат при смене хотэнда"
@@ -19414,10 +19538,14 @@ msgid "Continue anyway?"
msgstr "Всё равно продолжить?"
msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?"
msgstr "Включить адаптацию к расходу для автоматического исправления?\nНет – игнорировать предупреждение."
msgstr ""
"Включить адаптацию к расходу для автоматического исправления?\n"
"Нет – игнорировать предупреждение."
msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?"
msgstr "Включить адаптацию к соплу и расходу для автоматического исправления?\nНет – игнорировать предупреждение."
msgstr ""
"Включить адаптацию к соплу и расходу для автоматического исправления?\n"
"Нет – игнорировать предупреждение."
msgid "Start retraction length: "
msgstr "Начальная длина отката: "
@@ -20341,9 +20469,6 @@ msgstr "Физический принтер"
msgid "Print Host upload"
msgstr "Загрузка на хост печати"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Реализация сетевого агента для обмена информацией с принтером. Доступные реализации определяются при запуске."
msgid "Select a Flashforge printer"
msgstr "Выберите принтер Flashforge"
@@ -21202,9 +21327,6 @@ msgstr "При попытке войти произошла какая-то ош
msgid "User canceled."
msgstr "Отменено пользователем."
msgid "Head diameter"
msgstr "Диаметр уха"
msgid "Max angle"
msgstr "Макс. угол"
@@ -21959,6 +22081,22 @@ msgstr ""
"Предотвращение коробления материала\n"
"Знаете ли вы, что при печати материалами, склонными к короблению, таких как ABS, повышение температуры подогреваемого стола может снизить эту вероятность?"
#~ msgid ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "Высота слоя слишком мала.\n"
#~ "Будет установлено значение min_layer_height\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "Высота слоя не может превышать ограничения, установленные в настройках принтера → Экструдер → Ограничение высоты слоя. Это может вызвать проблемы с качеством печати."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "Автоматически подстроиться под заданный в настройках диапазон?\n"
#~ msgid "Head diameter"
#~ msgstr "Диаметр уха"
#~ msgid "Print order within a single layer."
#~ msgstr "Последовательность печати моделей в пределах одного слоя."
+159 -41
View File
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"Language: sv\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -5213,6 +5213,23 @@ msgstr "Kammarens aktuella temperatur är högre än materialets säkra temperat
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "Kammarens minimitemperatur (%d℃) är högre än kammarens måltemperatur (%d℃). Minimivärdet är tröskeln där utskriften startar medan kammaren fortsätter värmas mot målet, så det bör inte överstiga målet. Värdet begränsas till måltemperaturen."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "Lagerhöjden är för liten. Den kommer att sättas till minimivärdet (%g mm)."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Lagerhöjden ligger utanför gränserna som anges i Skrivarinställningar -> Extruder -> Lagerhöjds gränser, detta kan orsaka problem med utskriftskvaliteten."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "Justera automatiskt till gränsvärdet (%g mm)?"
msgid "Adjust"
msgstr "Justera"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -5339,6 +5356,13 @@ msgstr ""
"Ja Aktivera Arachne-väggeneratorn\n"
"Nej Inaktivera Arachne-väggeneratorn och ställ in läget [Förskjutning] för ojämn yta"
# AI Translated
msgid "Brim ear radius"
msgstr "Radie för brim-öra"
msgid "Brim width"
msgstr "Brim bredd"
# AI Translated
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 "Spiralläget fungerar bara när antal väggar är 1, support är avstängt, detektering av klumpbildning med sondering är avstängd, antal översta skallager är 0, sparsam ifyllnadsdensitet är 0 och timelapse-typen är traditionell."
@@ -5645,6 +5669,14 @@ msgstr "Misslyckades med att generera cali G kod"
msgid "Calibration error"
msgstr "Fel vid kalibrering"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "Den här skrivaren är inte konfigurerad med den maskinvara som den här kontrollen kräver."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Den här kontrollen stöds inte på den här skrivaren."
# AI Translated
msgid "Network unavailable"
msgstr "Nätverket är inte tillgängligt"
@@ -6596,7 +6628,7 @@ msgid "Size:"
msgstr "Storlek:"
# AI Translated
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "Konflikter mellan G-code-banor hittades på lager %d, Z = %.2lfmm. Placera de objekt som krockar längre ifrån varandra (%s <-> %s)."
@@ -6798,6 +6830,10 @@ msgstr "Flera enheter"
msgid "Project"
msgstr "Projekt"
# AI Translated
msgid "Device (Web)"
msgstr "Enhet (Webb)"
msgid "Yes"
msgstr "Ja"
@@ -9088,22 +9124,22 @@ msgid "Replaced with 3D files from directory:\n"
msgstr "Ersatt med 3D-filer från mappen:\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ Hoppade över %s: samma fil.\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ Hoppade över %s: filen finns inte.\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ Hoppade över %s: det gick inte att ersätta.\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ Ersatte %s.\n"
@@ -9933,6 +9969,18 @@ msgstr "Med det här alternativet aktiverat kan du skicka en uppgift till flera
msgid "Pop up to select filament grouping mode"
msgstr "Visa dialogruta för val av filamentgrupperingsläge"
# AI Translated
msgid "Visible plugin pages"
msgstr "Synliga insticksmodulsidor"
# AI Translated
msgid "pages"
msgstr "sidor"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "Antal insticksmodulsidor som visas som fasta flikar innan de återstående sidorna fälls ihop i en rullgardinsmeny på den sista fliken."
# AI Translated
msgid "Behaviour"
msgstr "Beteende"
@@ -10357,6 +10405,18 @@ msgstr "Visa förinställningar som inte stöds"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "Visa inkompatibla förinställningar och förinställningar som inte stöds i rullgardinslistorna för skrivare och filament. Dessa förinställningar kan inte väljas."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Experimentellt) Använd skrivaragenter i stället för utskriftsvärdar"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Skickar utskriftsjobb för icke-Bambu-skrivare via skrivarens insticksmodulagenter i stället för det klassiska uppladdningsflödet till utskriftsvärden.\n"
"När detta är avaktiverat använder OrcaSlicer det äldre beteendet för utskriftsvärdar."
# AI Translated
msgid "Experimental Features"
msgstr "Experimentella funktioner"
@@ -10637,10 +10697,26 @@ msgstr "Användar förinställning"
msgid "Preset Inside Project"
msgstr "Projekt förinställning"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Kopierar alla ärvda värden från den överordnade förinställningen till den här förinställningen och tar bort arvsrelationen. Förinställningar som endast är kompatibla med den överordnade förinställningen kan sluta stödjas."
# AI Translated
msgid "Detach from parent"
msgstr "Koppla loss från överordnad"
# AI Translated
msgid "Unique preset"
msgstr "Unik förinställning"
# AI Translated
msgid "Parent preset"
msgstr "Överordnad förinställning"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Den här förinställningen ärver inte från någon annan förinställning."
msgid "Name is unavailable."
msgstr "Namnet ej tillgängligt."
@@ -11459,23 +11535,6 @@ msgstr "Är du säker på att du vill aktivera det här alternativet?"
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 "Ifyllnadsmönster är oftast konstruerade för att hantera rotation automatiskt så att de skrivs ut korrekt och ger avsedd effekt (t.ex. Gyroid, Kubisk). Att rotera det aktuella sparsamma ifyllnadsmönstret kan ge otillräckligt stöd. Var försiktig och kontrollera noga om det uppstår utskriftsproblem. Är du säker på att du vill aktivera det här alternativet?"
# AI Translated
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"Lagerhöjden är för liten.\n"
"Den ställs in på min_layer_height\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Lagerhöjden överskrider gränsen i Skrivarinställningar -> Extruder -> Lagerhöjds gränser, detta kan orsaka problem med utskriftskvaliteten."
msgid "Adjust to the set range automatically?\n"
msgstr "Justera automatiskt till det inställda området?\n"
msgid "Adjust"
msgstr "Justera"
# AI Translated
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 "Experimentell funktion: Filamentet dras tillbaka och kapas på ett längre avstånd vid filamentbyten för att minimera rensningen. Det kan minska rensningen avsevärt, men kan också öka risken för igensatt nozzel eller andra utskriftsproblem."
@@ -11707,6 +11766,9 @@ msgstr "Hittade reserverade nyckelord"
msgid "Setting Overrides"
msgstr "Åsidosätter inställningar"
msgid "Retraction when switching material"
msgstr "Reduktion vid material byte"
msgid "Basic information"
msgstr "Allmän information"
@@ -11848,6 +11910,14 @@ msgstr "Kompatibla process profiler"
msgid "Printable space"
msgstr "Utskriftsbar yta"
# AI Translated
msgid "Printer Agent"
msgstr "Skrivaragent"
# AI Translated
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Välj vilken nätverksagentimplementation som ska användas för kommunikation med skrivaren. Tillgängliga agenter registreras vid start."
# AI Translated
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
@@ -11992,9 +12062,6 @@ msgstr "Lagerhöjds begränsning"
msgid "Z-Hop"
msgstr "Z-Hop"
msgid "Retraction when switching material"
msgstr "Reduktion vid material byte"
# AI Translated
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
@@ -13486,6 +13553,10 @@ msgstr " är för nära uteslutningsområdet, och kollisioner kommer att orsakas
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " ligger för nära området för klumpdetektering, vilket kommer att orsaka kollisioner.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " är delvis utanför det utskrivbara området och kan inte skrivas ut.\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."
msgstr "De valda nozzeltemperaturerna är inkompatibla. Varje filaments nozzeltemperatur måste ligga inom de andra filamentens rekommenderade nozzeltemperaturintervall. Annars kan nozzeln sättas igen eller skrivaren skadas."
@@ -13856,10 +13927,6 @@ msgstr "Använd 3MF i stället för G-code"
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 "Aktivera detta om skrivaren tar emot en 3MF-fil som utskriftsjobb. När det är aktiverat skickar Orca Slicer den beredda filen som en .gcode.3mf i stället för en vanlig .gcode-fil."
# AI Translated
msgid "Printer Agent"
msgstr "Skrivaragent"
# AI Translated
msgid "Select the network agent implementation for printer communication."
msgstr "Välj vilken nätverksagentimplementation som ska användas för kommunikation med skrivaren."
@@ -14616,9 +14683,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "Hastighet för inre bridges. Om värdet anges i procent beräknas det utifrån bridge_speed. Standardvärdet är 150 %."
msgid "Brim width"
msgstr "Brim bredd"
msgid "This is the distance from the model to the outermost brim line."
msgstr "Avståndet från modellen till yttersta brim linjen"
@@ -14707,6 +14771,14 @@ msgstr ""
"Geometrin decimeras innan skarpa vinklar detekteras. Den här parametern anger avvikelsens minsta längd för decimeringen.\n"
"0 för att avaktivera."
# AI Translated
msgid "Brim ears outer only"
msgstr "Brim-öron endast utvändigt"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Genererar musöron endast på modellens yttre kontur, exklusive hål och slutna sektioner."
msgid "upward compatible machine"
msgstr "uppåt kompatibel maskin"
@@ -16039,6 +16111,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "Gyroid"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Utjämningsfaktor för sparsam ifyllnad"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Styr hur kraftigt hörnen i den sparsamma ifyllnaden rundas av. 0% behåller den ursprungliga skarpa banan, medan 100% ger största möjliga kurvor mellan intilliggande ifyllnadslinjer."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "Acceleration av fyllning av toppytan. Att använda ett lägre värde kan förbättra ytkvaliteten"
@@ -16651,6 +16731,14 @@ msgstr "Vilken typ av G-kod är skrivaren kompatibel med"
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "Hoppa över G-code-konfigurationsblocket"
# AI Translated
msgid "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."
msgstr "Skriver inte CONFIG_BLOCK (nyckel/värde-paren för slicerkonfigurationen) till G-code-filen. Detta kan hjälpa med skrivare vars firmware kraschar när dessa kommentarrader tolkas (t.ex. Anycubic go-klipper). Obs: G-code-filen kommer inte längre att innehålla slicerinställningarna, så att importera den tillbaka till OrcaSlicer återställer inte konfigurationen."
# AI Translated
msgid "Pellet Modded Printer"
msgstr "Skrivare ombyggd för pellets"
@@ -17868,6 +17956,14 @@ msgstr "Lång reduktion vid extruderbyte"
msgid "Retraction distance when extruder change"
msgstr "Reduktionssträcka vid extruderbyte"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "Reduktionslängd (Verktygsbyte)"
# 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 "När reduktionen utlöses före ett verktygsbyte dras filamentet tillbaka med den angivna mängden (längden mäts på det obearbetade filamentet, innan det når extrudern)."
# AI Translated
msgid "Z-hop height"
msgstr "Z-hop-höjd"
@@ -17983,6 +18079,10 @@ msgstr "Extra längd vid omstart"
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 "När reduktionen kompenseras efter flyttrörelsen trycker extrudern fram den här extra mängden filament. Den här inställningen behövs sällan."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "Extra längd vid omstart (Verktygsbyte)"
# AI Translated
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "När reduktionen kompenseras efter verktygsbyte trycker extrudern fram den här extra mängden filament."
@@ -18477,6 +18577,14 @@ msgstr "Verktygsbyte vid prime tornet"
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 "Tvinga verktygshuvudet att flytta till prime tornet innan verktygsbyteskommandot (Tx) skickas. Endast relevant för skrivare med flera extrudrar (flera verktygshuvuden) som använder ett prime torn av typ 2. Som standard hoppar Orca över flytten på maskiner med flera verktygshuvuden, eftersom den fasta programvaran hanterar huvudbytet, vilket kan leda till att Tx-kommandot skickas ovanför den utskrivna delen. Aktivera det här alternativet om du vill att verktygsbytet alltid ska ske ovanför prime tornet i stället."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "Vänta på temperatur vid prime tornet"
# 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 "Hämtar det nya verktyget utan att vänta på att det ska nå utskriftstemperatur, förflyttar sig till prime tornet och väntar på temperaturen där, precis före rensningen. Materialet som droppar under uppvärmningen hamnar på tornet i stället för på modellen, och förflyttningen sker samtidigt som uppvärmningen. Endast relevant för skrivare med flera extrudrar (flera verktygshuvuden) som använder ett prime torn av typ 2. Firmware eller verktygsbytesmakrot får inte vänta på temperaturen själv. När detta är avaktiverat utfärdas temperaturväntan direkt efter verktygsbyteskommandot."
# AI Translated
msgid "No sparse layers (beta)"
msgstr "Inga glesa lager (beta)"
@@ -22101,10 +22209,6 @@ msgstr "Fysisk printer"
msgid "Print Host upload"
msgstr "Uppladdning utskriftsvärd"
# AI Translated
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Välj vilken nätverksagentimplementation som ska användas för kommunikation med skrivaren. Tillgängliga agenter registreras vid start."
# AI Translated
msgid "Select a Flashforge printer"
msgstr "Välj en Flashforge-skrivare"
@@ -23181,10 +23285,6 @@ msgstr "Något oväntat hände vid inloggningen, försök igen."
msgid "User canceled."
msgstr "Användaren avbröt."
# AI Translated
msgid "Head diameter"
msgstr "Huvuddiameter"
# AI Translated
msgid "Max angle"
msgstr "Maxvinkel"
@@ -24071,6 +24171,24 @@ 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 ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "Lagerhöjden är för liten.\n"
#~ "Den ställs in på min_layer_height\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "Lagerhöjden överskrider gränsen i Skrivarinställningar -> Extruder -> Lagerhöjds gränser, detta kan orsaka problem med utskriftskvaliteten."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "Justera automatiskt till det inställda området?\n"
# AI Translated
#~ msgid "Head diameter"
#~ msgstr "Huvuddiameter"
# AI Translated
#~ msgid "Print order within a single layer."
#~ msgstr "Utskriftsordning inom ett enskilt lager."
+155 -37
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: 2026-06-19 13:40+0700\n"
"Last-Translator: Icezaza\n"
"Language-Team: Thai\n"
@@ -4720,6 +4720,23 @@ msgstr "อุณหภูมิห้องพิมพ์ปัจจุบั
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "อุณหภูมิห้องพิมพ์ต่ำสุด (%d℃) สูงกว่าอุณหภูมิห้องพิมพ์เป้าหมาย (%d℃) ค่าต่ำสุดคือเกณฑ์ที่การพิมพ์จะเริ่มต้นในขณะที่ห้องพิมพ์ยังคงร้อนขึ้นไปสู่เป้าหมาย จึงไม่ควรเกินค่าเป้าหมาย ระบบจะจำกัดค่าให้เท่ากับเป้าหมาย"
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "ความสูงเลเยอร์น้อยเกินไป จะถูกตั้งค่าเป็นค่าต่ำสุด (%g mm)"
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "ความสูงเลเยอร์อยู่นอกขีดจำกัดที่ตั้งไว้ใน การตั้งค่าเครื่องพิมพ์ -> ชุดดันเส้น -> การจำกัดความสูงของเลเยอร์ ซึ่งอาจทำให้เกิดปัญหาคุณภาพการพิมพ์"
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "ปรับเป็นค่าขีดจำกัด (%g mm) โดยอัตโนมัติหรือไม่?"
msgid "Adjust"
msgstr "ปรับ"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4840,6 +4857,13 @@ msgstr ""
"ใช่ - เปิดใช้งาน Arachne Wall Generator\n"
"ไม่ - ปิดการใช้งาน Arachne Wall Generator และตั้งค่าโหมด [Displacement] ของ Fuzzy Skin"
# AI Translated
msgid "Brim ear radius"
msgstr "รัศมีของหูขอบยึดชิ้นงาน"
msgid "Brim width"
msgstr "ความกว้าง ขอบยึดชิ้นงาน"
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 "โหมดเกลียวจะทำงานเฉพาะเมื่อลูปติดผนังเป็น 1, ปิดใช้งานส่วนรองรับ, การตรวจจับการจับตัวเป็นก้อนโดยการตรวจวัดถูกปิดใช้งาน, ชั้นเปลือกด้านบนเป็น 0, ความหนาแน่นของไส้ในแบบกระจายเป็น 0 และประเภทไทม์แลปส์เป็นแบบดั้งเดิม"
@@ -5094,6 +5118,14 @@ msgstr "ไม่สามารถสร้าง cali G-code"
msgid "Calibration error"
msgstr "ข้อผิดพลาดในการสอบเทียบ"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "เครื่องพิมพ์นี้ไม่ได้ตั้งค่าฮาร์ดแวร์ที่ตัวควบคุมนี้ต้องการ"
# AI Translated
msgid "This control is not supported on this printer."
msgstr "ตัวควบคุมนี้ไม่รองรับบนเครื่องพิมพ์นี้"
# AI Translated
msgid "Network unavailable"
msgstr "เครือข่ายไม่พร้อมใช้งาน"
@@ -5952,7 +5984,7 @@ msgstr "ปริมาณ:"
msgid "Size:"
msgstr "ขนาด:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "พบความขัดแย้งของเส้นทางรหัส G ที่เลเยอร์ %d, Z = %.2lfmm โปรดแยกวัตถุที่ขัดแย้งกันให้ไกลออกไป (%s <-> %s)"
@@ -6133,6 +6165,10 @@ msgstr "หลายอุปกรณ์"
msgid "Project"
msgstr "โปรเจกต์"
# AI Translated
msgid "Device (Web)"
msgstr "อุปกรณ์ (เว็บ)"
msgid "Yes"
msgstr "ใช่"
@@ -8199,19 +8235,19 @@ msgstr "ไม่ได้เลือกไดเรกทอรีสำหร
msgid "Replaced with 3D files from directory:\n"
msgstr "แทนที่ด้วยไฟล์ 3D จากไดเรกทอรี:\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ ข้าม %s: ไฟล์เดียวกัน\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ ข้าม %s: ไม่มีไฟล์อยู่\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ ข้าม %s: ไม่สามารถแทนที่ได้\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔แทนที่ %s\n"
@@ -8945,6 +8981,18 @@ msgstr "เมื่อเปิดใช้งานตัวเลือกน
msgid "Pop up to select filament grouping mode"
msgstr "ปรากฏขึ้นเพื่อเลือกโหมดการจัดกลุ่มเส้นพลาสติก"
# AI Translated
msgid "Visible plugin pages"
msgstr "หน้าปลั๊กอินที่แสดง"
# AI Translated
msgid "pages"
msgstr "หน้า"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "จำนวนหน้าปลั๊กอินที่แสดงเป็นแท็บถาวร ก่อนที่หน้าที่เหลือจะถูกยุบรวมเป็นเมนูแบบเลื่อนลงในแท็บสุดท้าย"
msgid "Behaviour"
msgstr "พฤติกรรม"
@@ -9299,6 +9347,18 @@ msgstr "แสดงค่าที่ตั้งไว้ล่วงหน้
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "แสดงค่าที่ตั้งไว้ล่วงหน้าที่ไม่เข้ากันหรือไม่รองรับในรายการเลือกเครื่องพิมพ์และเส้นพลาสติก ไม่สามารถเลือกค่าที่ตั้งไว้ล่วงหน้าเหล่านี้ได้"
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(ทดลอง) ใช้เอเจนต์เครื่องพิมพ์แทนโฮสต์การพิมพ์"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"ส่งงานพิมพ์ของเครื่องพิมพ์ที่ไม่ใช่ Bambu ผ่านเอเจนต์ปลั๊กอินของเครื่องพิมพ์ แทนการอัพโหลดไปยังโฮสต์การพิมพ์แบบเดิม\n"
"เมื่อปิดใช้ OrcaSlicer จะใช้พฤติกรรมโฮสต์การพิมพ์แบบเดิม"
# AI Translated
msgid "Experimental Features"
msgstr "ฟีเจอร์ทดลอง"
@@ -9563,9 +9623,25 @@ msgstr "พรีเซ็ตผู้ใช้"
msgid "Preset Inside Project"
msgstr "พรีเซ็ตภายในโปรเจ็กต์"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "คัดลอกค่าที่สืบทอดมาจากพรีเซ็ตแม่ทั้งหมดมาไว้ในพรีเซ็ตนี้ และตัดความสัมพันธ์กับพรีเซ็ตแม่ พรีเซ็ตที่เข้ากันได้กับพรีเซ็ตแม่เท่านั้นอาจไม่ได้รับการรองรับอีกต่อไป"
msgid "Detach from parent"
msgstr "แยกออกจากพรีเซ็ตแม่"
# AI Translated
msgid "Unique preset"
msgstr "พรีเซ็ตอิสระ"
# AI Translated
msgid "Parent preset"
msgstr "พรีเซ็ตแม่"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "พรีเซ็ตนี้ไม่ได้สืบทอดมาจากพรีเซ็ตอื่น"
msgid "Name is unavailable."
msgstr "ชื่อไม่พร้อมใช้งาน"
@@ -10305,22 +10381,6 @@ msgstr "คุณแน่ใจหรือไม่ว่าต้องกา
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 "โดยทั่วไปรูปแบบไส้ในได้รับการออกแบบให้รองรับการหมุนโดยอัตโนมัติเพื่อให้แน่ใจว่าการพิมพ์ถูกต้องและบรรลุผลตามที่ต้องการ (เช่น Gyroid, ลูกบาศก์) การหมุนรูปแบบ ไส้ใน แบบกระจัดกระจายในปัจจุบันอาจทำให้ส่วนรองรับไม่เพียงพอ โปรดดำเนินการด้วยความระมัดระวังและตรวจสอบปัญหาการพิมพ์ที่อาจเกิดขึ้นอย่างละเอียด คุณแน่ใจหรือไม่ว่าต้องการเปิดใช้งานตัวเลือกนี้"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"ความสูงของเลเยอร์น้อยเกินไป\n"
"มันจะตั้งค่าเป็น min_layer_height\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "ความสูงของเลเยอร์เกินขีดจำกัดในการตั้งค่าเครื่องพิมพ์ -> ชุดดันเส้น -> ขีดจำกัดความสูงของเลเยอร์ ซึ่งอาจทำให้เกิดปัญหาคุณภาพการพิมพ์"
msgid "Adjust to the set range automatically?\n"
msgstr "ปรับเป็นช่วงที่ตั้งไว้อัตโนมัติ?\n"
msgid "Adjust"
msgstr "ปรับ"
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 "คุณลักษณะการทดลอง: การดึงกลับและตัดเส้นพลาสติกออกในระยะห่างที่มากขึ้นระหว่างการเปลี่ยนเส้นพลาสติกเพื่อลดการไล่เส้น แม้ว่าจะสามารถลดการไล่เส้นได้อย่างเห็นได้ชัด แต่ก็อาจเพิ่มความเสี่ยงของการอุดตันของหัวฉีดหรือภาวะแทรกซ้อนในการพิมพ์อื่นๆ อีกด้วย"
@@ -10513,6 +10573,9 @@ msgstr "พบคีย์เวิร์ดที่สงวนไว้"
msgid "Setting Overrides"
msgstr "การตั้งค่าการแทนที่"
msgid "Retraction when switching material"
msgstr "การร่นกลับเมื่อเปลี่ยนวัสดุ"
msgid "Basic information"
msgstr "ข้อมูลพื้นฐาน"
@@ -10642,6 +10705,12 @@ msgstr "โปรไฟล์กระบวนการที่เข้าก
msgid "Printable space"
msgstr "พื้นที่ที่สามารถพิมพ์ได้"
msgid "Printer Agent"
msgstr "ตัวแทนเครื่องพิมพ์"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "เลือกการใช้งานตัวแทนเครือข่ายสำหรับการสื่อสารของเครื่องพิมพ์ ตัวแทนที่มีอยู่จะได้รับการลงทะเบียนเมื่อเริ่มต้น"
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10767,9 +10836,6 @@ msgstr "การจำกัดความสูงของเลเยอร
msgid "Z-Hop"
msgstr "ยกแกน Z"
msgid "Retraction when switching material"
msgstr "การร่นกลับเมื่อเปลี่ยนวัสดุ"
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
"\n"
@@ -12111,6 +12177,10 @@ msgstr "อยู่ใกล้เขตหวงห้ามมากเกิ
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr "อยู่ใกล้พื้นที่การตรวจจับการจับตัวกันมากเกินไป และจะเกิดการชนกัน\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr "อยู่นอกพื้นที่การพิมพ์บางส่วน จึงไม่สามารถพิมพ์ได้\n"
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."
msgstr "อุณหภูมิหัวฉีดที่เลือกเข้ากันไม่ได้ อุณหภูมิหัวฉีดของเส้นพลาสติกแต่ละเส้นต้องอยู่ในช่วงอุณหภูมิหัวฉีดที่แนะนำของเส้นพลาสติกอื่นๆ มิฉะนั้นอาจเกิดการอุดตันของหัวฉีดหรือเครื่องพิมพ์เสียหายได้"
@@ -12426,9 +12496,6 @@ msgstr "ใช้ 3MF แทน G-code"
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 เป็นงานพิมพ์ เมื่อเปิดใช้งาน OrcaSlicer จะส่งไฟล์ที่สไลซ์แล้วเป็น .gcode.3mf แทนไฟล์ .gcode ธรรมดา"
msgid "Printer Agent"
msgstr "ตัวแทนเครื่องพิมพ์"
msgid "Select the network agent implementation for printer communication."
msgstr "เลือกการใช้งานตัวแทนเครือข่ายสำหรับการสื่อสารของเครื่องพิมพ์"
@@ -13103,9 +13170,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "ความเร็วของสะพานภายใน หากค่าแสดงเป็นเปอร์เซ็นต์ ค่าดังกล่าวจะถูกคำนวณตาม bridge_speed ค่าเริ่มต้นคือ 150%"
msgid "Brim width"
msgstr "ความกว้าง ขอบยึดชิ้นงาน"
msgid "This is the distance from the model to the outermost brim line."
msgstr "ระยะห่างจากแบบจำลองถึงเส้นขอบยึดชิ้นงานด้านนอกสุด"
@@ -13185,6 +13249,14 @@ msgstr ""
"รูปทรงจะถูกทำลายก่อนที่จะตรวจจับมุมแหลม พารามิเตอร์นี้ระบุความยาวขั้นต่ำของการเบี่ยงเบนสำหรับการทำลาย\n"
"0 เพื่อปิดการใช้งาน"
# AI Translated
msgid "Brim ears outer only"
msgstr "หูขอบยึดชิ้นงานเฉพาะด้านนอก"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "สร้างหูหนูเฉพาะบนคอนทัวร์ด้านนอกของโมเดล โดยไม่รวมรูและส่วนที่ปิดล้อม"
msgid "upward compatible machine"
msgstr "เครื่องที่รองรับขึ้นไป"
@@ -14351,6 +14423,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "ไจรอยด์"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "ค่าความเรียบของไส้ในแบบโปร่ง"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "ควบคุมระดับความมนของมุมไส้ในแบบโปร่ง ค่า 0% จะคงเส้นทางเดิมที่เป็นมุมแหลม ส่วน 100% จะสร้างส่วนโค้งที่ใหญ่ที่สุดเท่าที่เป็นไปได้ระหว่างเส้นไส้ในที่อยู่ติดกัน"
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "ความเร่งของไส้ในพื้นผิวด้านบน การใช้ค่าที่ต่ำกว่าอาจปรับปรุงคุณภาพพื้นผิวด้านบนได้"
@@ -14893,6 +14973,14 @@ msgstr "เครื่องพิมพ์ G-code ชนิดใดที่
msgid "Klipper"
msgstr "คลิปเปอร์"
# AI Translated
msgid "Skip G-code config block"
msgstr "ข้ามบล็อกการตั้งค่าใน G-code"
# AI Translated
msgid "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."
msgstr "ไม่เขียน CONFIG_BLOCK (คู่คีย์/ค่าของการตั้งค่าโปรแกรมสไลซ์) ลงในไฟล์ G-code ซึ่งอาจช่วยได้กับเครื่องพิมพ์ที่เฟิร์มแวร์ขัดข้องเมื่ออ่านบรรทัดคอมเมนต์เหล่านี้ (เช่น Anycubic go-klipper) หมายเหตุ: ไฟล์ G-code จะไม่มีการตั้งค่าโปรแกรมสไลซ์อีกต่อไป ดังนั้นการนำเข้ากลับมาใน OrcaSlicer จะไม่คืนค่าการตั้งค่า"
msgid "Pellet Modded Printer"
msgstr "เครื่องพิมพ์ Modded เม็ด"
@@ -15945,6 +16033,14 @@ msgstr "การถอยกลับนานเมื่อเปลี่ย
msgid "Retraction distance when extruder change"
msgstr "ระยะการดึงกลับเมื่อชุดดันเส้นเปลี่ยน"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "ความยาวการดึงกลับ (การเปลี่ยนเครื่องมือ)"
# 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 "เมื่อการดึงกลับทำงานก่อนการเปลี่ยนเครื่องมือ เส้นพลาสติกจะถูกดึงกลับตามระยะที่กำหนด (วัดความยาวบนเส้นพลาสติกดิบ ก่อนเข้าสู่ชุดดันเส้น)"
msgid "Z-hop height"
msgstr "ความสูงยกแกน Z"
@@ -16039,6 +16135,10 @@ msgstr "ความยาวพิเศษเมื่อรีสตาร์
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 "เมื่อชดเชยการดึงกลับหลังการเคลื่อนที่เดินทาง ชุดดันเส้นจะดันเส้นพลาสติกเพิ่มเติมในปริมาณนี้ การตั้งค่านี้ไม่ค่อยจำเป็น"
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "ความยาวพิเศษเมื่อรีสตาร์ท (การเปลี่ยนเครื่องมือ)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "เมื่อชดเชยการดึงกลับหลังเปลี่ยนเครื่องมือ ชุดดันเส้นจะดันเส้นพลาสติกเพิ่มเติมในปริมาณนี้"
@@ -16451,6 +16551,14 @@ msgstr "การเปลี่ยนเครื่องมือบน Wipe
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 "บังคับให้หัวเครื่องมือเคลื่อนที่ไปที่ Wipe Tower ก่อนที่จะออกคำสั่งเปลี่ยนเครื่องมือ (Tx) เกี่ยวข้องเฉพาะกับเครื่องพิมพ์ที่มีชุดดันเส้นหลายเครื่อง (หลายหัวเครื่องมือ) ที่ใช้แผ่นเช็ดแบบ Type 2 ตามค่าเริ่มต้น Orca จะข้ามการเดินทางบนเครื่องที่มีหัวเครื่องมือหลายหัวเนื่องจากเฟิร์มแวร์จัดการการสลับหัว ซึ่งอาจส่งผลให้มีการออกคำสั่ง Tx เหนือส่วนที่พิมพ์ เปิดใช้งานตัวเลือกนี้หากคุณต้องการให้ทำการเปลี่ยนแปลงเครื่องมือเหนือ Wipe Tower แทนเสมอ"
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "รอให้ถึงอุณหภูมิที่ Wipe Tower"
# 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 "รับเครื่องมือใหม่โดยไม่รอให้ถึงอุณหภูมิการพิมพ์ แล้วเคลื่อนที่ไปยัง Wipe Tower และรออุณหภูมิที่นั่นก่อนไล่เส้นทันที เส้นพลาสติกที่ซึมออกมาระหว่างการอุ่นจะตกลงบน Wipe Tower แทนที่จะตกบนโมเดล และการเคลื่อนที่จะเกิดขึ้นพร้อมกับการอุ่น ใช้ได้เฉพาะกับเครื่องพิมพ์แบบหลายชุดดันเส้น (หลายหัวพิมพ์) ที่ใช้ Wipe Tower ชนิดที่ 2 เฟิร์มแวร์หรือแมโครการเปลี่ยนเครื่องมือต้องไม่รออุณหภูมิเอง เมื่อปิดใช้ คำสั่งรออุณหภูมิจะถูกส่งทันทีหลังคำสั่งเปลี่ยนเครื่องมือ"
msgid "No sparse layers (beta)"
msgstr "ไม่มีชั้นกระจัดกระจาย (เบต้า)"
@@ -19681,9 +19789,6 @@ msgstr "เครื่องพิมพ์ทางกายภาพ"
msgid "Print Host upload"
msgstr "อัพโหลดโฮสต์การพิมพ์"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "เลือกการใช้งานตัวแทนเครือข่ายสำหรับการสื่อสารของเครื่องพิมพ์ ตัวแทนที่มีอยู่จะได้รับการลงทะเบียนเมื่อเริ่มต้น"
msgid "Select a Flashforge printer"
msgstr "เลือกเครื่องพิมพ์ Flashforge"
@@ -20575,9 +20680,6 @@ msgstr "เกิดสิ่งที่ไม่คาดคิดขณะพ
msgid "User canceled."
msgstr "ผู้ใช้ยกเลิก"
msgid "Head diameter"
msgstr "เส้นผ่านศูนย์กลางหัว"
msgid "Max angle"
msgstr "มุมสูงสุด"
@@ -21361,6 +21463,22 @@ msgstr ""
"หลีกเลี่ยงการบิดเบี้ยว\n"
"คุณรู้หรือไม่ว่าเมื่อพิมพ์วัสดุที่มีแนวโน้มที่จะเกิดการบิดเบี้ยว เช่น ABS การเพิ่มอุณหภูมิฐานพิมพ์อย่างเหมาะสมสามารถลดความน่าจะเป็นของการบิดเบี้ยวได้"
#~ msgid ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "ความสูงของเลเยอร์น้อยเกินไป\n"
#~ "มันจะตั้งค่าเป็น min_layer_height\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "ความสูงของเลเยอร์เกินขีดจำกัดในการตั้งค่าเครื่องพิมพ์ -> ชุดดันเส้น -> ขีดจำกัดความสูงของเลเยอร์ ซึ่งอาจทำให้เกิดปัญหาคุณภาพการพิมพ์"
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "ปรับเป็นช่วงที่ตั้งไว้อัตโนมัติ?\n"
#~ msgid "Head diameter"
#~ msgstr "เส้นผ่านศูนย์กลางหัว"
#~ msgid "Print order within a single layer."
#~ msgstr "สั่งพิมพ์ภายในชั้นเดียว"
File diff suppressed because it is too large Load Diff
+158 -40
View File
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: orcaslicerua\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: 2026-07-17 16:25+0300\n"
"Last-Translator: Andrij Mizyk <andm1zyk@proton.me>\n"
"Language-Team: Ukrainian\n"
@@ -4142,10 +4142,10 @@ msgid "PA Profile"
msgstr "Профіль PA"
msgid "Factor K"
msgstr "Коэф. K"
msgstr "Коеф. K"
msgid "Factor N"
msgstr "Коэф. N"
msgstr "Коеф. N"
msgid "Setting AMS slot information while printing is not supported"
msgstr "Зміна інформації про слоти AMS під час друку не підтримується"
@@ -4716,6 +4716,23 @@ msgstr "Поточна температура камери вища, ніж бе
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "Мінімальна температура камери (%d℃) вища за цільову температуру камери (%d℃). Мінімальне значення — це поріг, за якого починається друк, поки камера продовжує нагріватися до цільової температури, тому воно не повинно її перевищувати. Значення буде обмежено цільовим."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "Висота шару занадто мала. Буде встановлено мінімальне значення (%g мм)."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Висота шару виходить за межі, задані в Налаштуваннях принтера -> Екструдер -> Ліміти висоти шару, це може призвести до проблем з якістю друку."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "Автоматично налаштувати до межі (%g мм)?"
msgid "Adjust"
msgstr "Налаштувати"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4839,6 +4856,13 @@ msgstr ""
"Так - Увімкнути генератор стінок Arachne\n"
"Ні - Вимкнути генератор стінок Arachne і встановити режим [Зміщення] для шорсткої поверхні"
# AI Translated
msgid "Brim ear radius"
msgstr "Радіус вушка кайми"
msgid "Brim width"
msgstr "Ширина кайми"
# AI Translated
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 "Спіральний режим працює лише тоді, коли кількість стінок дорівнює 1, підтримки вимкнено, виявлення налипання зондуванням вимкнено, кількість верхніх шарів оболонки дорівнює 0, щільність часткового заповнення дорівнює 0, а тип таймлапсу — традиційний."
@@ -5104,6 +5128,14 @@ msgstr "Не вдалося згенерувати калібрувальний
msgid "Calibration error"
msgstr "Помилка калібрування"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "На цьому принтері не налаштовано обладнання, потрібне для цього елемента керування."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Цей елемент керування не підтримується на цьому принтері."
# AI Translated
msgid "Network unavailable"
msgstr "Мережа недоступна"
@@ -5978,7 +6010,7 @@ msgid "Size:"
msgstr "Розмір:"
# AI Translated
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "Виявлено конфлікти шляхів G-коду на шарі %d, Z = %.2lf мм. Будь ласка, рознесіть конфліктуючі обʼєкти далі один від одного (%s <-> %s)."
@@ -6170,6 +6202,10 @@ msgstr "Багато пристроїв"
msgid "Project"
msgstr "Проєкт"
# AI Translated
msgid "Device (Web)"
msgstr "Пристрій (Веб)"
msgid "Yes"
msgstr "Так"
@@ -8306,19 +8342,19 @@ msgstr "Каталог для заміни не вибрано"
msgid "Replaced with 3D files from directory:\n"
msgstr "Замінено 3D-файлами з каталогу:\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ Пропущено %s: той самий файл.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ Пропущено %s: файл не існує.\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ Пропущено %s: не вдалося замінити.\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ Замінено %s.\n"
@@ -9069,6 +9105,18 @@ msgstr "З цією опцією ввімкненою, ви можете від
msgid "Pop up to select filament grouping mode"
msgstr "Показувати вікно вибору режиму групування філаментів"
# AI Translated
msgid "Visible plugin pages"
msgstr "Видимі сторінки плагінів"
# AI Translated
msgid "pages"
msgstr "стор."
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "Кількість сторінок плагінів, що показуються як закріплені вкладки, перш ніж решта сторінок згорнеться у випадний список на останній вкладці."
msgid "Behaviour"
msgstr "Поведінка"
@@ -9446,6 +9494,18 @@ msgstr "Показати непідтримувані пресети"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "Показати несумісні/непідтримувані пресети у випадаючому списку принтера і філаменту. Ці пресети не можна вибрати."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Експериментально) Використовувати агентів принтера замість хостів друку"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Спрямовує завдання друку для принтерів, відмінних від Bambu, через агентів плагінів принтера замість класичного завантаження на хост друку.\n"
"Коли вимкнено, OrcaSlicer використовує попередню поведінку хоста друку."
msgid "Experimental Features"
msgstr "Експериментальні функції"
@@ -9710,10 +9770,26 @@ msgstr "Пресети користувача"
msgid "Preset Inside Project"
msgstr "Налаштування проекту всередині"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Копіює в цей пресет усі значення, успадковані від батьківського пресета, і видаляє звʼязок успадкування. Пресети, сумісні лише з батьківським, можуть стати непідтримуваними."
# AI Translated
msgid "Detach from parent"
msgstr "Відʼєднати від батьківського"
# AI Translated
msgid "Unique preset"
msgstr "Незалежний пресет"
# AI Translated
msgid "Parent preset"
msgstr "Батьківський пресет"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Цей пресет не успадковується від іншого пресета."
msgid "Name is unavailable."
msgstr "Назва недоступна."
@@ -10492,22 +10568,6 @@ msgstr "Ви впевнені, що хочете ввімкнути цю опц
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 "Шаблони заповнення зазвичай розроблені так, щоб автоматично враховувати обертання, забезпечувати належний друк і досягати задуманого ефекту (наприклад, Гіроїд, Кубічний). Обертання поточного шаблону часткового заповнення може призвести до недостатньої підтримки. Дійте обережно та ретельно перевіряйте можливі проблеми друку. Ви впевнені, що хочете увімкнути цю опцію?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"Висота шару занадто мала.\n"
"Буде встановлено значення min_layer_height\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Висота шару перевищує ліміт у Налаштуваннях принтера -> Екструдер -> Ліміти висоти шару, це може призвести до проблем з якістю друку."
msgid "Adjust to the set range automatically?\n"
msgstr "Автоматично налаштувати на встановлений діапазон?\n"
msgid "Adjust"
msgstr "Налаштувати"
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 "Експериментальна функція: Втягування та відрізання філаменту на більшій відстані під час зміни філаменту для мінімізації промивання. Хоча це може помітно зменшити промивання, це також може підвищити ризик засмічення сопла або інших ускладнень друку."
@@ -10711,6 +10771,9 @@ msgstr "Знайдено зарезервовані ключові слова"
msgid "Setting Overrides"
msgstr "Налаштування перевизначень"
msgid "Retraction when switching material"
msgstr "Втягування під час зміни матеріалу"
msgid "Basic information"
msgstr "Базова інформація"
@@ -10848,6 +10911,13 @@ msgstr "Сумісні профілі процесів"
msgid "Printable space"
msgstr "Місце для друку"
msgid "Printer Agent"
msgstr "Агент принтера"
# AI Translated
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Виберіть реалізацію мережевого агента для звʼязку з принтером. Доступні агенти реєструються під час запуску."
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10978,9 +11048,6 @@ msgstr "Обмеження висоти шару"
msgid "Z-Hop"
msgstr "Стрибок-Z"
msgid "Retraction when switching material"
msgstr "Втягування під час зміни матеріалу"
# AI Translated
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
@@ -12376,6 +12443,10 @@ msgstr " знаходиться надто близько до зони відч
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " розташовано занадто близько до зони виявлення налипання, і це спричинить зіткнення.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " частково знаходиться за межами області друку, і його неможливо надрукувати.\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."
msgstr "Вибрані температури сопла несумісні. Температура сопла кожного філаменту має входити в рекомендований діапазон температур сопла інших філаментів. Інакше можливе засмічення сопла або пошкодження принтера."
@@ -12722,9 +12793,6 @@ msgstr "Використовувати 3MF замість 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 як завдання друку. Якщо увімкнено, Orca Slicer надсилає нарізаний файл як .gcode.3mf замість звичайного файлу .gcode."
msgid "Printer Agent"
msgstr "Агент принтера"
# AI Translated
msgid "Select the network agent implementation for printer communication."
msgstr "Виберіть реалізацію мережевого агента для звʼязку з принтером."
@@ -13438,9 +13506,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "Швидкість внутрішніх мостів. Якщо значення вказано у відсотках, воно буде розраховане на основі bridge_speed. Значення за замовчуванням: 150%."
msgid "Brim width"
msgstr "Ширина кайми"
msgid "This is the distance from the model to the outermost brim line."
msgstr "Відстань від моделі до останньої зовнішньої лінії кайми"
@@ -13525,6 +13590,14 @@ msgstr ""
"Геометрія буде оброблена перед детектуванням гострих кутів. Цей параметр вказує мінімальну довжину відхилення для обробки.\n"
"0 для вимкнення"
# AI Translated
msgid "Brim ears outer only"
msgstr "Вушка кайми лише ззовні"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Створювати мишачі вушка лише на зовнішньому контурі моделі, за винятком отворів і замкнених ділянок."
msgid "upward compatible machine"
msgstr "висхідна сумісна машина"
@@ -14734,6 +14807,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "Гіроїд"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Коефіцієнт згладжування часткового заповнення"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Визначає, наскільки сильно заокруглюються кути часткового заповнення. 0% зберігає початкову траєкторію з гострими кутами, а 100% створює максимально можливі заокруглення між сусідніми лініями заповнення."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "Прискорення заповнення верхньої поверхні. Використання меншого значенняможе покращити якість верхньої поверхні"
@@ -15300,6 +15381,14 @@ msgstr "З яким gcode сумісний принтер"
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "Пропустити блок конфігурації G-code"
# AI Translated
msgid "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."
msgstr "Не записувати CONFIG_BLOCK (пари ключ/значення з конфігурацією слайсера) у файл G-code. Це може допомогти з принтерами, прошивка яких аварійно завершується під час розбору цих рядків коментарів (напр. Anycubic go-klipper). Примітка: файл G-code більше не міститиме налаштувань слайсера, тож зворотний імпорт до OrcaSlicer не відновить конфігурацію."
msgid "Pellet Modded Printer"
msgstr "Принтер модифікований гранулами"
@@ -16438,6 +16527,14 @@ msgstr "Довге втягування при зміні екструдера"
msgid "Retraction distance when extruder change"
msgstr "Відстань втягування при зміні екструдера"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "Довжина втягування (Зміна інструменту)"
# 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 "Коли втягування спрацьовує перед зміною інструменту, філамент відтягується на вказану величину (довжина вимірюється на необробленому філаменті, до його входу в екструдер)."
msgid "Z-hop height"
msgstr "Висота Z-підйому"
@@ -16534,6 +16631,10 @@ msgstr "Додаткова довжина під час перезавантаж
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 "Коли втягування компенсується після переміщення, екструдер проштовхуєЦе додаткова кількість нитки. Ця установка рідко потрібна."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "Додаткова довжина під час перезавантаження (Зміна інструменту)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "Коли втягування компенсується після заміни інструменту, екструдерпроштовхує цю додаткову кількість нитки."
@@ -16960,6 +17061,14 @@ msgstr "Зміна інструмента на вежі протирання"
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). Стосується лише багатоекструдерних (багатоінструментальних) принтерів з вежею протирання типу 2. Типово Orca пропускає це переміщення на багатоінструментальних машинах, оскільки заміну головки виконує прошивка, через що команда Tx може бути видана над надрукованою деталлю. Увімкніть цю опцію, якщо хочете, щоб зміна інструмента завжди відбувалася над вежею протирання."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "Очікувати температуру на вежі протирання"
# 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 "Бере новий інструмент, не чекаючи, доки він досягне температури друку, переміщується до вежі протирання й чекає на температуру там, безпосередньо перед промивкою. Матеріал, що витікає під час нагрівання, потрапляє на вежу, а не на модель, а переміщення збігається з нагріванням. Актуально лише для принтерів із кількома екструдерами (кількома головками), які використовують вежу протирання типу 2. Прошивка або макрос зміни інструменту не повинні самі чекати на температуру. Коли вимкнено, команда очікування температури видається одразу після команди зміни інструменту."
msgid "No sparse layers (beta)"
msgstr "Без розріджених шарів (бета)"
@@ -20304,10 +20413,6 @@ msgstr "Фізичний принтер"
msgid "Print Host upload"
msgstr "Завантаження хоста друку"
# AI Translated
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Виберіть реалізацію мережевого агента для звʼязку з принтером. Доступні агенти реєструються під час запуску."
msgid "Select a Flashforge printer"
msgstr "Вибрати принтер Flashforge"
@@ -21181,9 +21286,6 @@ msgstr "Під час спроби входу трапилося щось нес
msgid "User canceled."
msgstr "Користувача скасовано."
msgid "Head diameter"
msgstr "Діаметр голови"
msgid "Max angle"
msgstr "Максимальний кут"
@@ -21979,6 +22081,22 @@ msgstr ""
"Уникнення деформації\n"
"Чи знаєте ви, що при друку матеріалами, схильними до деформації, такими як ABS, відповідне підвищення температури столу може зменшити ймовірність деформації?"
#~ msgid ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "Висота шару занадто мала.\n"
#~ "Буде встановлено значення min_layer_height\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "Висота шару перевищує ліміт у Налаштуваннях принтера -> Екструдер -> Ліміти висоти шару, це може призвести до проблем з якістю друку."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "Автоматично налаштувати на встановлений діапазон?\n"
#~ msgid "Head diameter"
#~ msgstr "Діаметр голови"
#~ msgid "Print order within a single layer."
#~ msgstr "Друк замовлення в один шар"
+157 -39
View File
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: 2025-10-02 17:43+0700\n"
"Last-Translator: \n"
"Language-Team: hainguyen.ts13@gmail.com\n"
@@ -4975,6 +4975,23 @@ msgstr "Nhiệt độ buồng hiện tại cao hơn nhiệt độ an toàn của
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "Nhiệt độ buồng tối thiểu (%d℃) cao hơn nhiệt độ buồng mục tiêu (%d℃). Giá trị tối thiểu là ngưỡng để bắt đầu in trong khi buồng vẫn tiếp tục gia nhiệt tới mục tiêu, nên nó không được vượt quá giá trị mục tiêu. Nó sẽ được giới hạn về mức mục tiêu."
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "Chiều cao lớp quá nhỏ. Nó sẽ được đặt về giá trị tối thiểu (%g mm)."
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Chiều cao lớp nằm ngoài giới hạn được đặt trong Cài đặt máy in -> Extruder -> Giới hạn chiều cao lớp, điều này có thể gây ra vấn đề chất lượng in."
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "Tự động điều chỉnh về giới hạn (%g mm)?"
msgid "Adjust"
msgstr "Điều chỉnh"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -5095,6 +5112,13 @@ msgstr ""
"Yes - Bật trình tạo wall Arachne\n"
"No - Tắt trình tạo wall Arachne và đặt chế độ [Displacement] của Fuzzy Skin"
# AI Translated
msgid "Brim ear radius"
msgstr "Bán kính tai brim"
msgid "Brim width"
msgstr "Độ rộng brim"
# AI Translated
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 "Chế độ xoắn ốc chỉ hoạt động khi vòng wall bằng 1, support bị tắt, phát hiện vón cục bằng dò bị tắt, số lớp vỏ trên bằng 0, mật độ infill thưa bằng 0 và loại timelapse là truyền thống."
@@ -5399,6 +5423,14 @@ msgstr "Không thể tạo G-code hiệu chỉnh"
msgid "Calibration error"
msgstr "Lỗi hiệu chỉnh"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "Máy in này không được cấu hình phần cứng mà điều khiển này cần."
# AI Translated
msgid "This control is not supported on this printer."
msgstr "Điều khiển này không được hỗ trợ trên máy in này."
# AI Translated
msgid "Network unavailable"
msgstr "Mạng không khả dụng"
@@ -6317,7 +6349,7 @@ msgstr "Thể tích:"
msgid "Size:"
msgstr "Kích thước:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "Đã tìm thấy xung đột đường đi G-code tại lớp %d, Z = %.2lfmm. Vui lòng tách các vật thể xung đột ra xa hơn (%s <-> %s)."
@@ -6516,6 +6548,10 @@ msgstr "Nhiều thiết bị"
msgid "Project"
msgstr "Dự án"
# AI Translated
msgid "Device (Web)"
msgstr "Thiết bị (Web)"
msgid "Yes"
msgstr "Có"
@@ -8721,22 +8757,22 @@ msgid "Replaced with 3D files from directory:\n"
msgstr "Đã thay thế bằng file 3D từ thư mục:\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ Đã bỏ qua %s: cùng một file.\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ Đã bỏ qua %s: file không tồn tại.\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ Đã bỏ qua %s: thay thế thất bại.\n"
# AI Translated
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ Đã thay thế %s.\n"
@@ -9532,6 +9568,18 @@ msgstr "Với tùy chọn này được bật, bạn có thể gửi tác vụ
msgid "Pop up to select filament grouping mode"
msgstr "Hiện cửa sổ để chọn chế độ nhóm filament"
# AI Translated
msgid "Visible plugin pages"
msgstr "Số trang plugin hiển thị"
# AI Translated
msgid "pages"
msgstr "trang"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "Số trang plugin được hiển thị dưới dạng tab cố định trước khi các trang còn lại được gom vào danh sách thả xuống ở tab cuối cùng."
# AI Translated
msgid "Behaviour"
msgstr "Hành vi"
@@ -9947,6 +9995,18 @@ msgstr "Hiện cài đặt sẵn không được hỗ trợ"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "Hiện các cài đặt sẵn không tương thích/không được hỗ trợ trong danh sách thả xuống máy in và filament. Không thể chọn các cài đặt sẵn này."
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(Thử nghiệm) Dùng tác nhân máy in thay cho máy chủ in"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"Định tuyến các tác vụ in của máy in không phải Bambu qua các tác nhân plugin máy in thay vì luồng tải lên máy chủ in cổ điển.\n"
"Khi tắt, OrcaSlicer sẽ dùng hành vi máy chủ in cũ."
# AI Translated
msgid "Experimental Features"
msgstr "Tính năng thử nghiệm"
@@ -10223,10 +10283,26 @@ msgstr "Preset người dùng"
msgid "Preset Inside Project"
msgstr "Preset bên trong dự án"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "Sao chép tất cả các giá trị kế thừa từ preset cha vào preset này và gỡ bỏ quan hệ kế thừa. Các preset chỉ tương thích với preset cha có thể không còn được hỗ trợ."
# AI Translated
msgid "Detach from parent"
msgstr "Tách khỏi vật thể cha"
# AI Translated
msgid "Unique preset"
msgstr "Preset độc lập"
# AI Translated
msgid "Parent preset"
msgstr "Preset cha"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "Preset này không kế thừa từ preset khác."
msgid "Name is unavailable."
msgstr "Tên không khả dụng."
@@ -11026,22 +11102,6 @@ msgstr "Bạn có chắc chắn muốn bật tùy chọn này?"
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 "Mẫu infill thường được thiết kế để xử lý xoay tự động nhằm đảm bảo in đúng cách và đạt được hiệu quả dự kiến (ví dụ: Gyroid, Cubic). Xoay mẫu infill thưa hiện tại có thể dẫn đến support không đủ . Vui lòng tiến hành thận trọng và kiểm tra kỹ bất kỳ vấn đề in tiềm ẩn nào. Bạn có chắc chắn muốn bật tùy chọn này?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"Chiều cao lớp quá nhỏ.\n"
"Nó sẽ được đặt thành min_layer_height\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "Chiều cao lớp vượt quá giới hạn trong Cài đặt máy in -> Extruder -> Giới hạn chiều cao lớp, điều này có thể gây ra vấn đề chất lượng in."
msgid "Adjust to the set range automatically?\n"
msgstr "Điều chỉnh về phạm vi đặt tự động?\n"
msgid "Adjust"
msgstr "Điều chỉnh"
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 "Tính năng thử nghiệm: Rút và cắt filament ở khoảng cách lớn hơn trong quá trình thay filament để giảm thiểu xả. Mặc dù có thể giảm đáng kể lượng xả, nó cũng có thể làm tăng nguy cơ tắc đầu phun hoặc các vấn đề in khác."
@@ -11235,6 +11295,9 @@ msgstr "Tìm thấy từ khóa dành riêng"
msgid "Setting Overrides"
msgstr "Ghi đè cài đặt"
msgid "Retraction when switching material"
msgstr "Rút khi chuyển vật liệu"
msgid "Basic information"
msgstr "Thông tin cơ bản"
@@ -11366,6 +11429,14 @@ msgstr "Hồ sơ quy trình tương thích"
msgid "Printable space"
msgstr "Không gian in"
# AI Translated
msgid "Printer Agent"
msgstr "Tác nhân máy in"
# AI Translated
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Chọn cách triển khai tác nhân mạng cho việc giao tiếp với máy in. Các tác nhân khả dụng được đăng ký khi khởi động."
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -11498,9 +11569,6 @@ msgstr "Giới hạn chiều cao lớp"
msgid "Z-Hop"
msgstr "Z-Hop"
msgid "Retraction when switching material"
msgstr "Rút khi chuyển vật liệu"
# AI Translated
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
@@ -12950,6 +13018,10 @@ msgstr " quá gần vùng loại trừ, và sẽ gây va chạm.\n"
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr " ở quá gần vùng phát hiện vón cục, và sẽ gây ra va chạm.\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr " nằm một phần ngoài vùng in được, và không thể in.\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."
msgstr "Nhiệt độ đầu phun đã chọn không tương thích. Nhiệt độ đầu phun của mỗi filament phải nằm trong dải nhiệt độ đầu phun được khuyến nghị của các filament còn lại. Nếu không, có thể xảy ra tắc đầu phun hoặc hư hỏng máy in."
@@ -13291,10 +13363,6 @@ msgstr "Dùng 3MF thay cho G-code"
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 "Bật tùy chọn này nếu máy in nhận file 3MF làm tác vụ in. Khi bật, Orca Slicer sẽ gửi file đã slice dưới dạng .gcode.3mf thay vì file .gcode thuần."
# AI Translated
msgid "Printer Agent"
msgstr "Tác nhân máy in"
# AI Translated
msgid "Select the network agent implementation for printer communication."
msgstr "Chọn cách triển khai tác nhân mạng cho việc giao tiếp với máy in."
@@ -14002,9 +14070,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "Tốc độ của cầu bên trong. Nếu giá trị được biểu thị dưới dạng phần trăm, nó sẽ được tính dựa trên bridge_speed. Giá trị mặc định là 150%."
msgid "Brim width"
msgstr "Độ rộng brim"
msgid "This is the distance from the model to the outermost brim line."
msgstr "Khoảng cách từ model đến đường brim ngoài cùng."
@@ -14088,6 +14153,14 @@ msgstr ""
"Hình học sẽ được giảm trước khi phát hiện góc sắc. Tham số này chỉ ra độ dài tối thiểu của độ lệch cho việc giảm.\n"
"0 để vô hiệu hóa."
# AI Translated
msgid "Brim ears outer only"
msgstr "Tai brim chỉ ở mặt ngoài"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "Chỉ tạo tai chuột trên đường viền ngoài của mô hình, không tính các lỗ và phần khép kín."
msgid "upward compatible machine"
msgstr "máy tương thích ngược"
@@ -15305,6 +15378,14 @@ msgstr "TPMS-FK"
msgid "Gyroid"
msgstr "Gyroid"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "Hệ số làm mượt infill thưa"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "Điều chỉnh mức độ bo tròn các góc của infill thưa. 0% giữ nguyên đường đi sắc cạnh ban đầu, còn 100% tạo ra các đường cong lớn nhất có thể giữa các đường infill liền kề."
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "Gia tốc của infill bề mặt trên. Sử dụng giá trị thấp hơn có thể cải thiện chất lượng bề mặt trên."
@@ -15868,6 +15949,14 @@ msgstr "Loại G-code mà máy in tương thích."
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "Bỏ qua khối cấu hình G-code"
# AI Translated
msgid "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."
msgstr "Không ghi CONFIG_BLOCK (các cặp khóa/giá trị cấu hình của phần mềm slice) vào tệp G-code. Điều này có thể hữu ích với các máy in có firmware bị treo khi phân tích những dòng chú thích này (ví dụ Anycubic go-klipper). Lưu ý: tệp G-code sẽ không còn chứa các thiết lập slice, nên việc nhập lại tệp vào OrcaSlicer sẽ không khôi phục được cấu hình."
msgid "Pellet Modded Printer"
msgstr "Máy in Pellet đã chỉnh sửa"
@@ -16971,6 +17060,14 @@ msgstr "Rút dài khi đổi extruder"
msgid "Retraction distance when extruder change"
msgstr "Khoảng cách rút khi đổi extruder"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "Độ dài rút (Đổi công cụ)"
# 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 "Khi rút được kích hoạt trước khi đổi công cụ, filament sẽ bị kéo lùi lại theo lượng đã chỉ định (độ dài được đo trên filament thô, trước khi nó đi vào extruder)."
msgid "Z-hop height"
msgstr "Chiều cao Z-hop"
@@ -17069,6 +17166,10 @@ msgstr "Độ dài bổ sung khi khởi động lại"
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 "Khi rút được bù sau khi di chuyển, extruder sẽ đẩy lượng filament bổ sung này. Cài đặt này hiếm khi cần thiết."
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "Độ dài bổ sung khi khởi động lại (Đổi công cụ)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "Khi rút được bù sau khi thay công cụ, extruder sẽ đẩy lượng filament bổ sung này."
@@ -17489,6 +17590,14 @@ msgstr "Đổi công cụ trên 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 "Buộc đầu công cụ di chuyển đến wipe tower trước khi phát lệnh đổi công cụ (Tx). Chỉ liên quan đến máy in nhiều extruder (nhiều đầu công cụ) dùng wipe tower Loại 2. Theo mặc định, Orca bỏ qua bước di chuyển này trên máy nhiều đầu công cụ vì firmware tự xử lý việc đổi đầu, điều này có thể khiến lệnh Tx được phát ra ngay phía trên phần đang in. Hãy bật tùy chọn này nếu bạn muốn việc đổi công cụ luôn diễn ra phía trên wipe tower."
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "Chờ nhiệt độ tại wipe tower"
# 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 "Lấy công cụ mới mà không chờ nó đạt nhiệt độ in, di chuyển đến wipe tower và chờ nhiệt độ tại đó, ngay trước khi xả. Nhựa chảy ra trong lúc gia nhiệt sẽ rơi lên wipe tower thay vì lên mô hình, và quãng di chuyển diễn ra đồng thời với quá trình gia nhiệt. Chỉ áp dụng cho máy in nhiều extruder (nhiều đầu công cụ) dùng wipe tower loại 2. Firmware hoặc macro đổi công cụ không được tự chờ nhiệt độ. Khi tắt, lệnh chờ nhiệt độ sẽ được phát ngay sau lệnh đổi công cụ."
msgid "No sparse layers (beta)"
msgstr "Không có lớp thưa (beta)"
@@ -20849,10 +20958,6 @@ msgstr "Máy in vật lý"
msgid "Print Host upload"
msgstr "Tải lên máy chủ in"
# AI Translated
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "Chọn cách triển khai tác nhân mạng cho việc giao tiếp với máy in. Các tác nhân khả dụng được đăng ký khi khởi động."
# AI Translated
msgid "Select a Flashforge printer"
msgstr "Chọn một máy in Flashforge"
@@ -21832,9 +21937,6 @@ msgstr "Đã xảy ra điều gì đó không mong đợi khi cố gắng đăng
msgid "User canceled."
msgstr "Người dùng đã hủy."
msgid "Head diameter"
msgstr "Đường kính đầu"
msgid "Max angle"
msgstr "Góc tối đa"
@@ -22702,6 +22804,22 @@ 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 ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "Chiều cao lớp quá nhỏ.\n"
#~ "Nó sẽ được đặt thành min_layer_height\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "Chiều cao lớp vượt quá giới hạn trong Cài đặt máy in -> Extruder -> Giới hạn chiều cao lớp, điều này có thể gây ra vấn đề chất lượng in."
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "Điều chỉnh về phạm vi đặt tự động?\n"
#~ msgid "Head diameter"
#~ msgstr "Đường kính đầu"
#~ msgid "Print order within a single layer."
#~ msgstr "Thứ tự in trong một lớp đơn."
+157 -39
View File
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Slic3rPE\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-0300\n"
"PO-Revision-Date: 2026-06-11 12:37-0300\n"
"Last-Translator: Handle <mail@bysb.net>\n"
"Language-Team: \n"
@@ -4574,6 +4574,23 @@ msgstr "当前腔体温度高于材料的安全温度,这可能导致材料软
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "最低机箱温度(%d℃)高于目标机箱温度(%d℃)。最低值是开始打印的阈值,此时机箱会持续朝目标温度加热,因此它不应超过目标值。该值将被限制到目标值。"
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "层高太小,将设置为最小值(%g mm)。"
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "层高超出了打印机设置 -> 挤出机 -> 层高限制中设置的范围,这可能导致打印质量问题。"
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "是否自动调整到限制值(%g mm)?"
msgid "Adjust"
msgstr "调整"
# AI Translated
msgid ""
"Layer height too small\n"
@@ -4696,6 +4713,13 @@ msgstr ""
"是 - 启用Arachne墙生成器\n"
"否 - 禁用Arachne墙生成器并将绒毛表面设置为[位移]模式"
# AI Translated
msgid "Brim ear radius"
msgstr "圆盘半径"
msgid "Brim width"
msgstr "Brim宽度"
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 "螺旋模式仅在壁环为 1、支撑被禁用、探测结块检测被禁用、顶部壳层为 0、稀疏填充密度为 0 且延时类型为传统时才起作用。"
@@ -4950,6 +4974,14 @@ msgstr "生成校准gcode失败"
msgid "Calibration error"
msgstr "校准错误"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "此打印机未配置该控件所需的硬件。"
# AI Translated
msgid "This control is not supported on this printer."
msgstr "此打印机不支持该控件。"
# AI Translated
msgid "Network unavailable"
msgstr "网络不可用"
@@ -5807,7 +5839,7 @@ msgstr "体积:"
msgid "Size:"
msgstr "尺寸:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "发现G-code路径在层%d,高度为%.2lf mm处有冲突。请将有冲突的对象分离得更远(%s <-> %s)。"
@@ -5988,6 +6020,10 @@ msgstr "多设备"
msgid "Project"
msgstr "项目"
# AI Translated
msgid "Device (Web)"
msgstr "设备(网页)"
msgid "Yes"
msgstr "是"
@@ -8028,19 +8064,19 @@ msgstr "未选择替换目录"
msgid "Replaced with 3D files from directory:\n"
msgstr "替换为目录中的 3D 文件:\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ 跳过 %s:同一文件。\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ 跳过%s:文件不存在。\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ 跳过%s:替换失败。\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ 替换了 %s。\n"
@@ -8767,6 +8803,18 @@ msgstr "启用此选项后,您可以同时向多个设备发送任务并管理
msgid "Pop up to select filament grouping mode"
msgstr "弹出选择耗材丝分组模式"
# AI Translated
msgid "Visible plugin pages"
msgstr "可见插件页数"
# AI Translated
msgid "pages"
msgstr "页"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "作为固定标签显示的插件页数量,其余页面将折叠到最后一个标签的下拉菜单中。"
msgid "Behaviour"
msgstr "行为"
@@ -9121,6 +9169,18 @@ msgstr "显示不受支持的预设"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "在打印机和耗材下拉列表中显示不兼容/不受支持的预设。这些预设无法被选择。"
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(实验性)使用打印机代理替代打印主机"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"非 Bambu 打印机的打印任务将通过打印机插件代理发送,而不是经典的打印主机上传流程。\n"
"禁用时,OrcaSlicer 使用旧的打印主机行为。"
# AI Translated
msgid "Experimental Features"
msgstr "实验性功能"
@@ -9385,9 +9445,25 @@ msgstr "用户预设"
msgid "Preset Inside Project"
msgstr "项目预设"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "将父预设继承的所有数值复制到当前预设,并解除继承关系。仅与父预设兼容的预设可能会变为不受支持。"
msgid "Detach from parent"
msgstr "与父级分离"
# AI Translated
msgid "Unique preset"
msgstr "独立预设"
# AI Translated
msgid "Parent preset"
msgstr "父预设"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "此预设未继承自其它预设。"
msgid "Name is unavailable."
msgstr "名称不可用。"
@@ -10093,24 +10169,6 @@ msgstr "您确定要启用此选项吗?"
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 "填充图案通常设计为自动处理旋转,以确保正确打印并实现其预期效果(例如,Gyroid、Cubic)。旋转当前的稀疏填充图案可能会导致支撑不足。请谨慎操作并彻底检查是否存在任何潜在的打印问题。您确定要启用此选项吗?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"层高太小。\n"
"将设置为min_layer_height\n"
"层高太小。\n"
"将自动设置为min_layer_height的值\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "层高超出了打印机设置->挤出机->层高限制中的范围,这可能导致打印质量问题。"
msgid "Adjust to the set range automatically?\n"
msgstr "是否自动调整到范围内?\n"
msgid "Adjust"
msgstr "调整"
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 "实验性选项。在更换耗材丝时,将耗材丝回抽一段距离后再切断以最小化冲刷。虽然这可以显著减少冲刷,但也可能增加喷嘴堵塞或其他打印问题的风险。"
@@ -10303,6 +10361,9 @@ msgstr "检测到保留的关键字"
msgid "Setting Overrides"
msgstr "参数覆盖"
msgid "Retraction when switching material"
msgstr "切换材料时的回抽量"
msgid "Basic information"
msgstr "基础信息"
@@ -10433,6 +10494,12 @@ msgstr "兼容的切片配置"
msgid "Printable space"
msgstr "可打印区域"
msgid "Printer Agent"
msgstr "打印机代理"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "为打印机通信选择网络代理。可用的代理将在启动时列出。"
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10558,9 +10625,6 @@ msgstr "层高限制"
msgid "Z-Hop"
msgstr "Z轴抬升"
msgid "Retraction when switching material"
msgstr "切换材料时的回抽量"
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
"\n"
@@ -11911,6 +11975,10 @@ msgstr "离不可打印区域太近,会发生碰撞。\n"
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr "距离聚集检测区域太近,会引起碰撞。\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr "有部分超出可打印区域,无法打印。\n"
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."
msgstr "所选的喷嘴温度不兼容。每种耗材的喷嘴温度都必须落在其他耗材的推荐喷嘴温度范围内。否则可能会发生喷嘴堵塞或打印机损坏。"
@@ -12224,9 +12292,6 @@ msgstr "使用 3MF 代替 G-code"
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 文件作为打印任务,请启用此选项。启用后,Orca Slicer 将以 .gcode.3mf 格式发送切片文件,而不是普通的 .gcode 文件。"
msgid "Printer Agent"
msgstr "打印机代理"
msgid "Select the network agent implementation for printer communication."
msgstr "选择打印机通信的网络代理实施。"
@@ -12861,9 +12926,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "内部桥接的速度。如果该值以百分比表示,将基于桥接速度计算。默认值为150%。"
msgid "Brim width"
msgstr "Brim宽度"
msgid "This is the distance from the model to the outermost brim line."
msgstr "从模型到最外圈brim走线的距离"
@@ -12944,6 +13006,14 @@ msgstr ""
"在检测尖锐角度之前,几何形状将被简化。此参数表示简化的最小偏差长度。\n"
"设为0以停用"
# AI Translated
msgid "Brim ears outer only"
msgstr "仅外轮廓生成圆盘"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "仅在模型的外轮廓上生成圆盘,不包括孔洞和封闭区域。"
msgid "upward compatible machine"
msgstr "向上兼容的机器"
@@ -14119,6 +14189,14 @@ msgstr "TPMS-FK结构"
msgid "Gyroid"
msgstr "螺旋体"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "稀疏填充平滑系数"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "控制稀疏填充拐角的圆滑程度。0% 保持原有的尖锐路径,100% 则在相邻填充线之间生成尽可能大的圆弧。"
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "顶面填充的加速度。使用较低值可能会改善顶面质量"
@@ -14659,6 +14737,14 @@ msgstr "打印机兼容的G-code风格'"
msgid "Klipper"
msgstr "Klipper固件"
# AI Translated
msgid "Skip G-code config block"
msgstr "跳过 G-code 配置块"
# AI Translated
msgid "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."
msgstr "不将 CONFIG_BLOCK(切片软件配置的键值对)写入 G-code 文件。这对固件在解析这些注释行时会崩溃的打印机(例如 Anycubic go-klipper)有帮助。注意:G-code 文件将不再包含切片设置,因此重新导入到 OrcaSlicer 时无法恢复配置。"
msgid "Pellet Modded Printer"
msgstr "颗粒改装打印机"
@@ -15704,6 +15790,14 @@ msgstr "更换挤出机时长回缩"
msgid "Retraction distance when extruder change"
msgstr "更换挤出机时的回缩距离"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "回抽长度(换工具头)"
# 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 "在换工具头之前触发回抽时,耗材丝会按指定的长度回抽(长度是在耗材丝进入挤出机之前,以原始耗材丝测量的)。"
msgid "Z-hop height"
msgstr "Z抬升高度"
@@ -15797,6 +15891,10 @@ msgstr "额外回填长度"
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 "每当空驶后回抽被补偿时,挤出机将推入额外数量的耗材丝。很少需要此设置。"
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "额外回填长度(换工具头)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "当换色后回抽被补偿时,挤出机将推入额外数量的耗材丝。"
@@ -16211,6 +16309,14 @@ msgstr "在擦拭塔上换头"
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) 之前,强制打印头先移动到擦拭塔。仅与使用第 2 类擦拭塔的多挤出机(多打印头)打印机相关。默认情况下,Orca 会在多打印头机器上跳过此移动,因为固件会处理换头,这可能导致 Tx 命令在打印件上方发出。如果您希望换头命令始终在擦拭塔上方发出,请启用此选项。"
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "在擦拭塔上等待温度"
# 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 "拾取新工具头后不等待其达到打印温度,直接移动到擦拭塔,并在冲刷前于擦拭塔上等待温度。升温过程中渗出的耗材丝会落在擦拭塔上而不是模型上,且移动时间与加热过程重叠。仅适用于使用 2 型擦拭塔的多挤出机(多工具头)打印机。固件或换工具头宏本身不得等待温度。禁用时,等待温度的指令将在换工具头命令之后立即发出。"
msgid "No sparse layers (beta)"
msgstr "无稀疏层 (实验功能)"
@@ -19433,9 +19539,6 @@ msgstr "物理打印机"
msgid "Print Host upload"
msgstr "打印主机上传"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "为打印机通信选择网络代理。可用的代理将在启动时列出。"
msgid "Select a Flashforge printer"
msgstr "选择一台 Flashforge 打印机"
@@ -20325,9 +20428,6 @@ msgstr "在尝试登录时发生了异常,请重试。"
msgid "User canceled."
msgstr "用户已取消。"
msgid "Head diameter"
msgstr "Brim 直径"
msgid "Max angle"
msgstr "最大角度"
@@ -21111,6 +21211,24 @@ msgstr ""
"避免翘曲\n"
"您知道吗?打印ABS这类易翘曲材料时,适当提高热床温度可以降低翘曲的概率。"
#~ msgid ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "层高太小。\n"
#~ "将设置为min_layer_height\n"
#~ "层高太小。\n"
#~ "将自动设置为min_layer_height的值\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "层高超出了打印机设置->挤出机->层高限制中的范围,这可能导致打印质量问题。"
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "是否自动调整到范围内?\n"
#~ msgid "Head diameter"
#~ msgstr "Brim 直径"
#~ msgid "Print order within a single layer."
#~ msgstr "同一层内的打印顺序"
+155 -37
View File
@@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-29 17:40-0300\n"
"POT-Creation-Date: 2026-08-19 14:07-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"
@@ -4691,6 +4691,23 @@ msgstr "目前列印裝置內部溫度高於線材的安全溫度,可能會導
msgid "The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, so it should not exceed it. It will be clamped to the target."
msgstr "最低倉室溫度(%d℃)高於目標倉室溫度(%d℃)。最低值是列印開始的門檻,此時倉室會持續朝目標溫度加熱,因此不應超過目標值。系統會將其限制在目標值。"
# AI Translated
#, c-format, boost-format
msgid "Layer height is too small. It will be set to the minimum (%g mm)."
msgstr "層高過小,將設定為最小值(%g mm)。"
# AI Translated
msgid "Layer height is outside the limits set in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "層高超出了印表裝置設定 -> 擠出機 -> 層高限制中設定的範圍,這可能會導致列印品質問題。"
# AI Translated
#, c-format, boost-format
msgid "Adjust it to the limit (%g mm) automatically?"
msgstr "是否自動調整至限制值(%g mm)?"
msgid "Adjust"
msgstr "調整"
msgid ""
"Layer height too small\n"
"It has been reset to 0.2"
@@ -4825,6 +4842,13 @@ msgstr ""
"是 - 啟用 Arachne Wall 產生器\n"
"否 - 停用 Arachne Wall 產生器,並將 Fuzzy Skin 設定為 [位移] 模式"
# AI Translated
msgid "Brim ear radius"
msgstr "耳狀 Brim 半徑"
msgid "Brim width"
msgstr "Brim 寬度"
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 "花瓶模式僅適用於牆體圈數為 1、停用支撐、停用偵測堵塞、頂部外殼層數為 0、稀疏填充密度為 0,且延時攝影類型為傳統模式時。"
@@ -5079,6 +5103,14 @@ msgstr "產生校正代碼失敗"
msgid "Calibration error"
msgstr "校正錯誤"
# AI Translated
msgid "This printer is not configured with the hardware this control needs."
msgstr "此列印裝置未配置此控制項所需的硬體。"
# AI Translated
msgid "This control is not supported on this printer."
msgstr "此列印裝置不支援此控制項。"
# AI Translated
msgid "Network unavailable"
msgstr "網路無法使用"
@@ -5936,7 +5968,7 @@ msgstr "體積:"
msgid "Size:"
msgstr "尺寸:"
#, c-format, boost-format
#, boost-format
msgid "Conflicts of G-code paths have been found at layer %d, Z = %.2lfmm. Please separate the conflicted objects farther (%s <-> %s)."
msgstr "發現 G-code 路徑在 %d 層,Z = %.2lf mm 處的衝突。請將有衝突的物件分離得更遠(%s <-> %s)。"
@@ -6118,6 +6150,10 @@ msgstr "多臺裝置"
msgid "Project"
msgstr "專案"
# AI Translated
msgid "Device (Web)"
msgstr "裝置(網頁)"
msgid "Yes"
msgstr "是"
@@ -8193,19 +8229,19 @@ msgstr "未選擇替換的目錄"
msgid "Replaced with 3D files from directory:\n"
msgstr "已從目錄替換為 3D 檔案:\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: same file.\n"
msgstr "✖ 已跳過 %s:相同檔案。\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: file does not exist.\n"
msgstr "✖ 已跳過 %s:檔案不存在。\n"
#, c-format
#, c-format, boost-format
msgid "✖ Skipped %s: failed to replace.\n"
msgstr "✖ 已跳過 %s:無法替換。\n"
#, c-format
#, c-format, boost-format
msgid "✔ Replaced %s.\n"
msgstr "✔ 已替換 %s。\n"
@@ -8940,6 +8976,18 @@ msgstr "啟用時可以同時傳送到並管理多個機臺。"
msgid "Pop up to select filament grouping mode"
msgstr "彈出視窗選擇線材分組模式"
# AI Translated
msgid "Visible plugin pages"
msgstr "可見的外掛頁面數"
# AI Translated
msgid "pages"
msgstr "頁"
# AI Translated
msgid "Number of plugin pages shown as fixed tabs before the remaining pages collapse into a dropdown on the last tab."
msgstr "以固定分頁顯示的外掛頁面數量,其餘頁面會收合至最後一個分頁的下拉選單中。"
msgid "Behaviour"
msgstr "行為"
@@ -9294,6 +9342,18 @@ msgstr "顯示不支援的預設"
msgid "Show incompatible/unsupported presets in the printer and filament dropdown lists. These presets cannot be selected."
msgstr "在列印裝置和線材下拉選單中顯示不相容/不支援的預設。這些預設無法選取。"
# AI Translated
msgid "(Experimental) Use printer agents instead of print hosts"
msgstr "(實驗性)使用列印裝置代理程式取代列印主機"
# AI Translated
msgid ""
"Route print jobs for non-Bambu printers through printer plug-in agents instead of the classic print-host upload flow.\n"
"When disabled, OrcaSlicer uses the legacy print-host behavior."
msgstr ""
"將非 Bambu 列印裝置的列印工作透過列印裝置外掛代理程式傳送,而非傳統的列印主機上傳流程。\n"
"停用時,OrcaSlicer 會使用舊有的列印主機行為。"
# AI Translated
msgid "Experimental Features"
msgstr "實驗性功能"
@@ -9558,9 +9618,25 @@ msgstr "使用者預設"
msgid "Preset Inside Project"
msgstr "項目預設"
# AI Translated
msgid "Copies all inherited values from the parent into this preset and removes the parent relationship. Presets compatible only with the parent may become unsupported."
msgstr "將父配置繼承的所有數值複製到目前的配置,並解除繼承關係。僅與父配置相容的配置可能會變成不受支援。"
msgid "Detach from parent"
msgstr "從父預設分離"
# AI Translated
msgid "Unique preset"
msgstr "獨立配置"
# AI Translated
msgid "Parent preset"
msgstr "父配置"
# AI Translated
msgid "This preset does not inherit from another preset."
msgstr "此配置未繼承自其他配置。"
msgid "Name is unavailable."
msgstr "名稱不可用。"
@@ -10299,22 +10375,6 @@ msgstr "您確認要啟用此選項嗎?"
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 "填充模式通常設計為自動處理旋轉,以確保正確列印並實現其預期效果(例如:Gyroid、Cubic)。旋轉目前的稀疏填充模式可能會導致支撐不足。請謹慎操作,並仔細檢查任何潛在的列印問題。您確定要啟用此選項嗎?"
msgid ""
"Layer height is too small.\n"
"It will set to min_layer_height\n"
msgstr ""
"層高過薄\n"
"將改為 min_layer_height\n"
msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
msgstr "層高超過了印表裝置設定 -> 擠出機 -> 層高限制,這可能會導致列印品質問題。"
msgid "Adjust to the set range automatically?\n"
msgstr "是否自動調整至設定範圍?\n"
msgid "Adjust"
msgstr "調整"
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 "實驗性功能:在換線過程中以更大的距離收回並切斷線材,以減少沖洗量。儘管這可以顯著減少沖洗,但也可能增加噴嘴堵塞或其他列印問題的風險。"
@@ -10507,6 +10567,9 @@ msgstr "偵測到保留的關鍵字"
msgid "Setting Overrides"
msgstr "參數覆蓋"
msgid "Retraction when switching material"
msgstr "切換線材時的回抽量"
msgid "Basic information"
msgstr "基本資訊"
@@ -10637,6 +10700,12 @@ msgstr "相容的切片設定"
msgid "Printable space"
msgstr "可列印區域"
msgid "Printer Agent"
msgstr "列印裝置代理"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "選擇列印裝置通訊的網路代理實施。可用代理在啟動時註冊。"
#. TRN: The first argument is the parameter's name; the second argument is its value.
#, boost-format
msgid "Invalid value provided for parameter %1%: %2%"
@@ -10762,9 +10831,6 @@ msgstr "層高限制"
msgid "Z-Hop"
msgstr "Z 軸抬升"
msgid "Retraction when switching material"
msgstr "切換線材時的回抽量"
msgid ""
"The Retract before wipe option could be only 100% when using the Firmware Retraction mode.\n"
"\n"
@@ -12113,6 +12179,10 @@ msgstr "離淨空區域太近,會發生碰撞。\n"
msgid " is too close to clumping detection area, and collisions will be caused.\n"
msgstr "離堵塞偵測區域太近,會發生碰撞。\n"
# AI Translated
msgid " is partially outside the printable area, and it cannot be printed.\n"
msgstr "有部分超出可列印區域,無法列印。\n"
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."
msgstr "所選的噴嘴溫度不相容。每種線材的噴嘴溫度都必須落在其他線材的建議噴嘴溫度範圍內。否則可能會發生噴嘴堵塞或列印裝置損壞。"
@@ -12426,9 +12496,6 @@ msgstr "使用 3MF 取代 G-code"
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 檔案作為列印作業,請啟用此選項。啟用後,Orca Slicer 會將切片後的檔案以 .gcode.3mf 形式傳送,而非單純的 .gcode 檔案。"
msgid "Printer Agent"
msgstr "列印裝置代理"
msgid "Select the network agent implementation for printer communication."
msgstr "選擇用於列印裝置通訊的網路代理實作。"
@@ -13074,9 +13141,6 @@ msgstr ""
msgid "Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."
msgstr "內部橋接速度。如果該值以百分比表示,將基於 bridge_speed 進行計算。預設值為 150%。"
msgid "Brim width"
msgstr "Brim 寬度"
msgid "This is the distance from the model to the outermost brim line."
msgstr "從模型到 Brim 最外圈的距離"
@@ -13157,6 +13221,14 @@ msgstr ""
"在偵測尖銳角度之前,幾何形狀將被簡化。此參數表示簡化的最小偏差長度。\n"
"設為 0 以停用"
# AI Translated
msgid "Brim ears outer only"
msgstr "僅外輪廓產生耳狀 Brim"
# AI Translated
msgid "Generate mouse ears only on the outer contour of the model, excluding holes and enclosed sections."
msgstr "僅在模型的外輪廓上產生耳狀 Brim,不包含孔洞與封閉區域。"
msgid "upward compatible machine"
msgstr "向上相容的裝置"
@@ -14316,6 +14388,14 @@ msgstr "TPMS-FK結構"
msgid "Gyroid"
msgstr "螺旋體"
# AI Translated
msgid "Sparse infill smooth factor"
msgstr "稀疏填充平滑係數"
# AI Translated
msgid "Controls how strongly sparse infill corners are rounded. 0% keeps the original sharp path, while 100% produces the largest possible curves between adjacent infill lines."
msgstr "控制稀疏填充轉角的圓滑程度。0% 保持原有的銳利路徑,100% 則在相鄰填充線之間產生盡可能大的圓弧。"
msgid "This is the acceleration of top surface infill. Using a lower value may improve top surface quality."
msgstr "頂面填充的加速度。使用較低值可能會改善頂面列印品質"
@@ -14856,6 +14936,14 @@ msgstr "列印裝置相容的 G-code 樣式"
msgid "Klipper"
msgstr "Klipper"
# AI Translated
msgid "Skip G-code config block"
msgstr "略過 G-code 設定區塊"
# AI Translated
msgid "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."
msgstr "不將 CONFIG_BLOCK(切片軟體設定的鍵值對)寫入 G-code 檔案。這對於韌體在解析這些註解行時會當機的列印裝置(例如 Anycubic go-klipper)有幫助。注意:G-code 檔案將不再包含切片設定,因此重新匯入 OrcaSlicer 時無法還原設定。"
msgid "Pellet Modded Printer"
msgstr "顆粒改裝列印裝置"
@@ -15909,6 +15997,14 @@ msgstr "更換擠出機時長回抽"
msgid "Retraction distance when extruder change"
msgstr "更換擠出機時的回抽距離"
# AI Translated
msgid "Retraction Length (Toolchange)"
msgstr "回抽長度(換工具)"
# 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 "在換工具之前觸發回抽時,線材會依指定的長度回抽(長度是在線材進入擠出機之前,以原始線材測量)。"
msgid "Z-hop height"
msgstr "Z 抬升高度"
@@ -16002,6 +16098,10 @@ msgstr "額外回填長度"
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 "每當空駛後回抽被補償時,擠出機將推入額外長度的線材。很少需要此設定。"
# AI Translated
msgid "Extra length on restart (Toolchange)"
msgstr "額外回填長度(換工具)"
msgid "When the retraction is compensated after changing tool, the extruder will push this additional amount of filament."
msgstr "當換色後回抽被補償時,擠出機將推入額外長度的線材。"
@@ -16405,6 +16505,14 @@ msgstr "在換料塔上換刀"
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 指令在已列印零件上方發出。若您希望換刀一律改在換料塔上方發出,請啟用此選項。"
# AI Translated
msgid "Wait for temperature on wipe tower"
msgstr "在換料塔上等待溫度"
# 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 "取用新工具時不等待其達到列印溫度,先移動到換料塔,並在清理前於換料塔上等待溫度。升溫過程中滲出的線材會落在換料塔上而非模型上,且移動時間與加熱過程重疊。僅適用於使用第 2 型換料塔的多擠出機(多工具頭)列印裝置。韌體或換工具巨集本身不得等待溫度。停用時,等待溫度的指令會在換工具命令之後立即發出。"
msgid "No sparse layers (beta)"
msgstr "取消稀疏層(Beta"
@@ -19622,9 +19730,6 @@ msgstr "實體列印裝置"
msgid "Print Host upload"
msgstr "列印主機上傳"
msgid "Select the network agent implementation for printer communication. Available agents are registered at startup."
msgstr "選擇列印裝置通訊的網路代理實施。可用代理在啟動時註冊。"
msgid "Select a Flashforge printer"
msgstr "選取 Flashforge 列印裝置"
@@ -20516,9 +20621,6 @@ msgstr "嘗試登入時發生了意外錯誤,請再試一次。"
msgid "User canceled."
msgstr "使用者取消。"
msgid "Head diameter"
msgstr "頭直徑"
msgid "Max angle"
msgstr "最大角度"
@@ -21323,6 +21425,22 @@ msgstr ""
"避免翹曲\n"
"您知道嗎?當列印容易翹曲的材料(如 ABS)時,適當提高熱床溫度可以降低翹曲的機率。"
#~ msgid ""
#~ "Layer height is too small.\n"
#~ "It will set to min_layer_height\n"
#~ msgstr ""
#~ "層高過薄\n"
#~ "將改為 min_layer_height\n"
#~ msgid "Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits, this may cause printing quality issues."
#~ msgstr "層高超過了印表裝置設定 -> 擠出機 -> 層高限制,這可能會導致列印品質問題。"
#~ msgid "Adjust to the set range automatically?\n"
#~ msgstr "是否自動調整至設定範圍?\n"
#~ msgid "Head diameter"
#~ msgstr "頭直徑"
#~ msgid "Print order within a single layer."
#~ msgstr "每一層的列印順序"
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "Qidi",
"version": "02.04.00.10",
"version": "02.04.00.11",
"force_update": "0",
"description": "Qidi configurations",
"machine_model_list": [
@@ -20,6 +20,9 @@
"close_fan_the_first_x_layers": [
"3"
],
"during_print_exhaust_fan_speed": [
"0"
],
"fan_cooling_layer_time": [
"10"
],
@@ -20,6 +20,9 @@
"close_fan_the_first_x_layers": [
"3"
],
"during_print_exhaust_fan_speed": [
"0"
],
"fan_cooling_layer_time": [
"10"
],
@@ -20,6 +20,9 @@
"close_fan_the_first_x_layers": [
"3"
],
"during_print_exhaust_fan_speed": [
"0"
],
"fan_cooling_layer_time": [
"10"
],
+141
View File
@@ -0,0 +1,141 @@
@echo off
rem Build the per-vendor system preset caches (one <vendor>.opc per vendor) by
rem running the generate_system_cache.exe dev tool against a profiles directory,
rem and make every profiles directory named on the command line ship-ready:
rem install the caches into it and delete the preset JSONs they replace, so a
rem build ships one copy of its presets instead of two.
rem
rem scripts\build_preset_cache.bat [build_dir] [target_dir ...]
rem
rem build_dir defaults to "build"
rem target_dir profiles directories to ship into. Caches are generated into
rem the source tree's resources\profiles, which is what every
rem packaging step copies from; a target may be that same
rem directory, which then only gets pruned.
rem --prune-source
rem allow a target that is the directory the caches were generated
rem into (resources\profiles). Pruning it deletes the checkout's
rem own preset JSONs, which is a packaging step - not something a
rem build should do to a working tree by surprise. CI passes it.
rem
rem Shipping deletes, so it is a CI packaging step. A vendor's own <vendor>.json
rem goes along with its preset JSONs: the cache carries the vendor profile and
rem the version it was built at, so discovery, version checks and installing all
rem read it there. Only a vendor that has a cache is pruned, so non-vendor JSONs
rem (blacklist.json) are left alone, as are the vendor directories themselves -
rem thumbnails, covers and bed models still live there.
rem
rem set CONFIG=<cfg> to pin the build config for multi-config generators
rem (default: the config of the tool already in the build tree, else Release)
setlocal enabledelayedexpansion
set "REPO_ROOT=%~dp0.."
set "PRUNE_SOURCE="
:parse_flags
if /i "%~1"=="--prune-source" (
set "PRUNE_SOURCE=1"
shift
goto :parse_flags
)
set "BUILD_DIR=%~1"
if "%BUILD_DIR%"=="" set "BUILD_DIR=build"
if not exist "%BUILD_DIR%\" (
echo ERROR: build tree not found: %BUILD_DIR% 1>&2
exit /b 1
)
if not "%~1"=="" shift
rem Newest match wins: a stale binary silently produces a stale cache layout.
call :find_tool
if not defined CONFIG (
for %%c in (Debug Release RelWithDebInfo MinSizeRel) do (
echo !TOOL! | findstr /i "\\%%c\\" >nul && set "CONFIG=%%c"
)
)
if not defined CONFIG set "CONFIG=Release"
echo Building generate_system_cache in %BUILD_DIR% (%CONFIG%)
cmake --build "%BUILD_DIR%" --config %CONFIG% --target generate_system_cache
if errorlevel 1 (
echo ERROR: could not build generate_system_cache - configure the build tree with -DORCA_TOOLS=ON: 1>&2
echo cmake -S "%REPO_ROOT%" -B "%BUILD_DIR%" -DORCA_TOOLS=ON 1>&2
exit /b 1
)
call :find_tool
if not defined TOOL (
echo ERROR: generate_system_cache.exe not found under %BUILD_DIR% - build with -DORCA_TOOLS=ON 1>&2
exit /b 1
)
set "PROFILES=%REPO_ROOT%\resources\profiles"
if not exist "%PROFILES%\" (
echo ERROR: profiles directory not found: %PROFILES% 1>&2
exit /b 1
)
for %%d in ("%PROFILES%") do set "PROFILES=%%~fd"
rem Add the slicer's runtime DLL directory to PATH so generate_system_cache.exe
rem can resolve its dependencies (TKernel.dll etc.) without a full install step.
set "DLL_DIR="
for /f "delims=" %%f in ('dir /s /b "%BUILD_DIR%\TKernel.dll" 2^>nul') do (
if not defined DLL_DIR set "DLL_DIR=%%~dpf"
)
if defined DLL_DIR set "PATH=%DLL_DIR%;%PATH%"
echo Generating per-vendor preset caches in %PROFILES%
rem Start clean so vendors that went away - and caches written by older tool
rem versions - don't linger next to the freshly generated ones.
del /q "%PROFILES%\*.opc" 2>nul
del /q "%PROFILES%\*.cache" 2>nul
"%TOOL%" --path "%PROFILES%" --log_level 2
if errorlevel 1 exit /b %errorlevel%
:next_target
if "%~1"=="" exit /b 0
call :ship "%~1"
if errorlevel 1 exit /b 1
shift
goto :next_target
:ship
set "TARGET=%~1"
if not exist "%TARGET%\" (
echo ERROR: profiles directory not found: %TARGET% 1>&2
exit /b 1
)
for %%d in ("%TARGET%") do set "TARGET=%%~fd"
if /i "%TARGET%"=="%PROFILES%" if not defined PRUNE_SOURCE (
echo %TARGET%: skipped - this is where the caches were generated.
echo Pass --prune-source to prune it; that deletes this checkout's preset JSONs.
exit /b 0
)
if /i not "%TARGET%"=="%PROFILES%" copy /y "%PROFILES%\*.opc" "%TARGET%\" >nul
set /a SHIPPED=0
set /a PRUNED=0
for %%c in ("%PROFILES%\*.opc") do (
set /a SHIPPED+=1
set "VENDOR=%%~nc"
if exist "%TARGET%\!VENDOR!.json" (
del /q "%TARGET%\!VENDOR!.json"
set /a PRUNED+=1
)
if exist "%TARGET%\!VENDOR!\" (
for /f %%n in ('dir /s /b "%TARGET%\!VENDOR!\*.json" 2^>nul ^| find /c /v ""') do set /a PRUNED+=%%n
del /s /q "%TARGET%\!VENDOR!\*.json" >nul 2>&1
rem Deepest first, so a directory the delete above emptied goes too; rd
rem refuses the ones still holding covers or meshes.
for /f "delims=" %%d in ('dir /s /b /ad "%TARGET%\!VENDOR!" 2^>nul ^| sort /r') do rd "%%d" 2>nul
)
)
echo %TARGET%: !SHIPPED! caches, dropped !PRUNED! preset JSONs
exit /b 0
:find_tool
set "TOOL="
for /f "delims=" %%f in ('dir /s /b /o-d "%BUILD_DIR%\generate_system_cache.exe" 2^>nul') do (
if not defined TOOL set "TOOL=%%f"
)
exit /b 0
+161
View File
@@ -0,0 +1,161 @@
#!/usr/bin/env bash
# Build the per-vendor system preset caches (one <vendor>.opc per vendor) by
# running the generate_system_cache dev tool against a profiles directory, and
# make every profiles directory named on the command line ship-ready: install
# the caches into it and delete the preset JSONs they replace, so a build ships
# one copy of its presets instead of two.
#
# ./scripts/build_preset_cache.sh # caches into resources/profiles
# ./scripts/build_preset_cache.sh -b build/arm64 # search this build tree for the tool
# ./scripts/build_preset_cache.sh <dir> [<dir> ...] # and ship into these profiles dirs
#
# Caches are generated into the source tree's resources/profiles, which is what
# every packaging step copies from. Shipping deletes, so it is a CI packaging
# step: pass packaged output directories, or the checkout of a build that is
# about to be packaged from it.
#
# A vendor's own <vendor>.json goes along with its preset JSONs: the cache
# carries the vendor profile and the version it was built at, so discovery,
# version checks and installing all read it there. A shipped vendor is its cache
# and nothing else. Only a vendor that has a cache is pruned, so an ungenerated
# vendor keeps its JSONs and is simply parsed at startup; non-vendor JSONs
# (blacklist.json) are left alone, as are the vendor directories themselves —
# thumbnails, covers and bed models still live there.
#
# -b <dir> build tree holding the tool
# (default: build/arm64, build/x86_64, or build — first that exists)
# -p <dir> profiles directory to generate caches into
# (default: <repo>/resources/profiles)
# -c <cfg> build config for multi-config generators
# (default: the config of the tool already in the build tree, else
# the build tree's CMAKE_BUILD_TYPE)
# -n skip the rebuild and run the tool already in the build tree
# -l <level> tool log level (default: 2)
# --prune-source
# allow a target that is the directory the caches were generated
# into (resources/profiles). Pruning it deletes the checkout's own
# preset JSONs, which is a packaging step - not something a build
# should do to a working tree by surprise.
set -euo pipefail
repo_root="$(cd "$(dirname "$0")/.." && pwd -P)"
build_dir=""
profiles_dir=""
config=""
build_tool=1
log_level=2
prune_source=0
# getopts does not do long options; pull this one out first.
args=()
for arg in "$@"; do
if [ "$arg" = "--prune-source" ]; then prune_source=1; else args+=("$arg"); fi
done
set -- ${args+"${args[@]}"}
while getopts "b:p:c:l:nh" opt; do
case $opt in
b) build_dir="$OPTARG" ;;
p) profiles_dir="$OPTARG" ;;
c) config="$OPTARG" ;;
n) build_tool=0 ;;
l) log_level="$OPTARG" ;;
h) sed -n '2,${/^#/!q;p;}' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
*) exit 1 ;;
esac
done
shift $((OPTIND - 1))
if [ -z "$build_dir" ]; then
for candidate in "$repo_root/build/arm64" "$repo_root/build/x86_64" "$repo_root/build"; do
if [ -d "$candidate" ]; then build_dir="$candidate"; break; fi
done
fi
if [ -z "$build_dir" ] || [ ! -d "$build_dir" ]; then
echo "ERROR: build tree not found (pass -b <build_dir>)" >&2
exit 1
fi
# Newest match wins: multi-config trees keep one binary per config, and a stale
# one silently produces a stale cache layout.
find_tool() {
local best="" f
while IFS= read -r f; do
[ -n "$f" ] || continue
if [ -z "$best" ] || [ "$f" -nt "$best" ]; then best="$f"; fi
done < <(find "$build_dir" -name generate_system_cache -type f 2>/dev/null)
printf '%s' "$best"
}
tool=$(find_tool)
if [ -z "$config" ]; then
case "$tool" in
*/Debug/*) config=Debug ;;
*/Release/*) config=Release ;;
*/RelWithDebInfo/*) config=RelWithDebInfo ;;
*/MinSizeRel/*) config=MinSizeRel ;;
*) config=$(sed -n 's/^CMAKE_BUILD_TYPE:[A-Z]*=\(.\+\)$/\1/p' "$build_dir/CMakeCache.txt" 2>/dev/null | head -1 || true) ;;
esac
fi
if [ "$build_tool" = 1 ]; then
echo "Building generate_system_cache in $build_dir${config:+ ($config)}"
build_args=(--build "$build_dir" --target generate_system_cache)
if [ -n "$config" ]; then build_args+=(--config "$config"); fi
if ! cmake "${build_args[@]}"; then
echo "ERROR: could not build generate_system_cache — configure the build tree with -DORCA_TOOLS=ON:" >&2
echo " cmake -S \"$repo_root\" -B \"$build_dir\" -DORCA_TOOLS=ON" >&2
exit 1
fi
tool=$(find_tool)
fi
if [ -z "$tool" ]; then
echo "ERROR: generate_system_cache not found under $build_dir — build with -DORCA_TOOLS=ON" >&2
exit 1
fi
if [ -z "$profiles_dir" ]; then profiles_dir="$repo_root/resources/profiles"; fi
if [ ! -d "$profiles_dir" ]; then
echo "ERROR: profiles directory not found: $profiles_dir" >&2
exit 1
fi
profiles_dir=$(cd "$profiles_dir" && pwd -P)
# Start clean so vendors that went away — and caches written by older tool
# versions — don't linger next to the freshly generated ones.
echo "Generating per-vendor preset caches in $profiles_dir"
rm -f "$profiles_dir"/*.opc "$profiles_dir"/*.cache
"$tool" --path "$profiles_dir" --log_level "$log_level"
for target in "$@"; do
resolved=$(cd "$target" 2>/dev/null && pwd -P) || {
echo "ERROR: profiles directory not found: $target" >&2
exit 1
}
if [ "$resolved" = "$profiles_dir" ] && [ "$prune_source" -eq 0 ]; then
echo "$resolved: skipped - this is where the caches were generated."
echo " Pass --prune-source to prune it; that deletes this checkout's preset JSONs."
continue
fi
if [ "$resolved" != "$profiles_dir" ]; then
cp "$profiles_dir"/*.opc "$resolved"/
fi
pruned=0
shipped=0
for cache in "$profiles_dir"/*.opc; do
vendor=$(basename "$cache" .opc)
shipped=$(( shipped + 1 ))
if [ -f "$resolved/$vendor.json" ]; then
rm -f "$resolved/$vendor.json"
pruned=$(( pruned + 1 ))
fi
[ -d "$resolved/$vendor" ] || continue
n=$(find "$resolved/$vendor" -name '*.json' | wc -l)
find "$resolved/$vendor" -name '*.json' -delete
find "$resolved/$vendor" -type d -empty -delete
pruned=$(( pruned + n ))
done
echo "$resolved: $shipped caches, dropped $pruned preset JSONs"
done
@@ -276,6 +276,12 @@ modules:
sha256: 27b72ba2d5ff3d0a9814ad40d4cb88f8dc89a35491c0866d952473f8f9416b77
dest: external-packages/Draco
# Assimp 5.4.3
- type: file
url: https://github.com/assimp/assimp/archive/refs/tags/v5.4.3.tar.gz
sha256: 66dfbaee288f2bc43172440a55d0235dfc7bf885dda6435c038e8000e79582cb
dest: external-packages/Assimp
# OpenSSL 1.1.1w (GNOME SDK has 3.x; OrcaSlicer requires 1.1.x)
- type: file
url: https://github.com/openssl/openssl/archive/OpenSSL_1_1_1w.tar.gz
@@ -347,6 +353,7 @@ modules:
- |
cmake . -B build_flatpak \
-DFLATPAK=ON \
-DORCA_TOOLS=ON \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH=/app \
-DCMAKE_INSTALL_PREFIX=/app \
@@ -357,6 +364,13 @@ modules:
- ./scripts/run_gettext.sh
- cmake --build build_flatpak --target install -j$FLATPAK_BUILDER_N_JOBS
# Per-vendor preset caches. On the other platforms CI runs this script
# itself; the flatpak is built inside flatpak-builder and the generator
# only exists in here, so the swap is a build step instead, against the
# profiles the install above copied into /app.
- cmake --build build_flatpak --target generate_system_cache -j$FLATPAK_BUILDER_N_JOBS
- ./scripts/build_preset_cache.sh -n -b build_flatpak /app/share/OrcaSlicer/profiles
cleanup:
- /include
@@ -403,6 +417,9 @@ modules:
- type: file
path: ../run_gettext.sh
dest: scripts
- type: file
path: ../build_preset_cache.sh
dest: scripts
# AppData metainfo for GNOME Software & Co.
- type: file
+2
View File
@@ -3,7 +3,9 @@
#define _WIN32_WINNT 0x0502
// The standard Windows includes.
#define WIN32_LEAN_AND_MEAN
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <Windows.h>
#include <wchar.h>
#include <commctrl.h>
+2
View File
@@ -2,7 +2,9 @@
#define _WIN32_WINNT 0x0502
// The standard Windows includes.
#define WIN32_LEAN_AND_MEAN
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <Windows.h>
#include <shellapi.h>
#include <wchar.h>
+10
View File
@@ -20,6 +20,16 @@ if (SLIC3R_ENC_CHECK)
)
endif()
if (ORCA_TOOLS)
set(_DEV_DEFS -DBOOST_ALL_NO_LIB -DBOOST_USE_WINAPI_VERSION=0x602 -DBOOST_SYSTEM_USE_UTF8)
# generate_system_cache: pre-generates per-vendor <vendor>.opc files under resources/profiles for CI bundling.
add_executable(generate_system_cache generate_system_cache.cpp)
target_link_libraries(generate_system_cache libslic3r boost_headeronly)
target_compile_definitions(generate_system_cache PRIVATE ${_DEV_DEFS})
endif()
# Function that adds source file encoding check to a target
# using the above encoding-check binary
+84
View File
@@ -0,0 +1,84 @@
#include "libslic3r/PresetBundle.hpp"
#include "libslic3r/Preset.hpp"
#include "libslic3r/Utils.hpp"
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
#include <boost/log/trivial.hpp>
#include <boost/program_options.hpp>
#include <iostream>
using namespace Slic3r;
namespace fs = boost::filesystem;
namespace po = boost::program_options;
int main(int argc, char* argv[])
{
po::options_description desc("OrcaSlicer System Cache Generator\nUsage");
// clang-format off
desc.add_options()
("help,h", "Show help")
#ifdef __APPLE__
("path,p", po::value<std::string>()->default_value("../../../../../../../resources/profiles"), "Path to profiles directory")
#else
("path,p", po::value<std::string>()->default_value("../../../resources/profiles"), "Path to profiles directory")
#endif
("log_level,l", po::value<int>()->default_value(2), "Log level (0=trace, 2=info, 4=error)");
// clang-format on
po::variables_map vm;
try {
po::store(po::parse_command_line(argc, argv, desc), vm);
if (vm.count("help")) { std::cout << desc << "\n"; return 0; }
po::notify(vm);
} catch (const po::error& e) {
std::cerr << "Error: " << e.what() << "\n" << desc << "\n";
return 1;
}
const std::string profiles_path = vm["path"].as<std::string>();
const int log_level = vm["log_level"].as<int>();
if (!fs::exists(profiles_path) || !fs::is_directory(profiles_path)) {
std::cerr << "Error: '" << profiles_path << "' is not a valid directory\n";
return 1;
}
set_logging_level(log_level);
set_data_dir(profiles_path);
set_resources_dir(fs::path(profiles_path).parent_path().make_preferred().string());
const fs::path user_dir = fs::path(data_dir()) / PRESET_USER_DIR;
if (!fs::exists(user_dir))
fs::create_directories(user_dir);
AppConfig app_config;
app_config.set("preset_folder", "default");
auto preset_bundle = std::make_unique<PresetBundle>();
preset_bundle->set_is_validation_mode(true);
preset_bundle->set_default_suppressed(true);
preset_bundle->set_generate_vendor_caches(true);
std::cout << "Loading system presets from: " << profiles_path << "\n";
try {
// In validation mode data_dir() is the profiles directory set above, so the
// loader writes each <vendor>.opc next to its <vendor>.json as it parses it.
preset_bundle->load_presets(app_config, ForwardCompatibilitySubstitutionRule::EnableSilent);
} catch (const std::exception& ex) {
std::cerr << "Failed to load presets: " << ex.what() << "\n";
return 1;
}
size_t cache_count = 0;
for (auto& entry : fs::directory_iterator(profiles_path))
if (boost::iends_with(entry.path().string(), ".opc"))
++ cache_count;
if (cache_count == 0) {
std::cerr << "No vendor cache files were generated under " << profiles_path << "\n";
return 1;
}
std::cout << "Generated " << cache_count << " vendor cache file(s) under " << profiles_path << "\n";
return 0;
}
+6
View File
@@ -872,6 +872,10 @@ std::string AppConfig::load()
local_machine.dev_ip = p["dev_ip"].get<std::string>();
if (p.contains("printer_type"))
local_machine.printer_type = p["printer_type"].get<std::string>();
if (p.contains("printer_agent_id"))
local_machine.printer_agent_id = p["printer_agent_id"].get<std::string>();
if (p.contains("access_code"))
local_machine.access_code = p["access_code"].get<std::string>();
m_local_machines[local_machine.dev_id] = local_machine;
}
} else {
@@ -1084,6 +1088,8 @@ void AppConfig::save()
m_json["dev_name"] = local_machine.second.dev_name;
m_json["dev_ip"] = local_machine.second.dev_ip;
m_json["printer_type"] = local_machine.second.printer_type;
m_json["printer_agent_id"] = local_machine.second.printer_agent_id;
m_json["access_code"] = local_machine.second.access_code;
j["local_machines"][local_machine.first] = m_json;
}
+10 -1
View File
@@ -66,10 +66,19 @@ struct BBLocalMachine
std::string dev_ip;
std::string dev_id; /* serial number */
std::string printer_type; /* model_id */
std::string printer_agent_id; /* id of the IPrinterAgent that discovered/bound this device, e.g. "bbl"; empty for entries persisted before this field existed */
// Access code, scoped to printer_agent_id above - so a code saved while bound under one
// printer agent isn't treated as valid for a different, independent agent talking to the
// same physical dev_id. Empty for entries persisted before this field existed; those fall
// back to the legacy flat "access_code"/"user_access_code" AppConfig sections (BBL-only,
// since BBL was the only agent when they were saved) - see
// get_access_code_with_legacy_fallback() in DevManager.cpp.
std::string access_code;
bool operator==(const BBLocalMachine& other) const
{
return dev_name == other.dev_name && dev_ip == other.dev_ip && dev_id == other.dev_id && printer_type == other.printer_type;
return dev_name == other.dev_name && dev_ip == other.dev_ip && dev_id == other.dev_id && printer_type == other.printer_type &&
printer_agent_id == other.printer_agent_id && access_code == other.access_code;
}
bool operator!=(const BBLocalMachine& other) const { return !operator==(other); }
};
+2 -2
View File
@@ -154,8 +154,8 @@ void simplify(Polygon &thiss, const int64_t smallest_line_segment_squared, const
//h^2 = L^2 / b^2 [factor the divisor]
const int64_t height_2 = double(area_removed_so_far) * double(area_removed_so_far) / double(base_length_2);
// Orca: The value of `height_2` is squared, so we need to compare it with the squared value
if ((height_2 <= Slic3r::sqr(scaled<coord_t>(0.005)) //Almost exactly colinear (barring rounding errors).
&& Line::distance_to_infinite(current, previous, next) <= scaled<double>(0.005))) // make sure that height_2 is not small because of cancellation of positive and negative areas
if ((height_2 <= Slic3r::sqr(colinear_vertex_tolerance()) //Almost exactly colinear (barring rounding errors).
&& Line::distance_to_infinite(current, previous, next) <= double(colinear_vertex_tolerance()))) // make sure that height_2 is not small because of cancellation of positive and negative areas
continue;
if (length2 < smallest_line_segment_squared
@@ -133,8 +133,8 @@ void ExtrusionLine::simplify(const int64_t smallest_line_segment_squared, const
const auto height_2 = int64_t(double(area_removed_so_far) * double(area_removed_so_far) / double(base_length_2));
const int64_t extrusion_area_error = calculateExtrusionAreaDeviationError(previous, current, next);
// Orca: The value of `height_2` is squared, so we need to compare it with the squared value
if ((height_2 <= Slic3r::sqr(scaled<coord_t>(0.005)) // Almost exactly colinear (barring rounding errors).
&& Line::distance_to_infinite(current.p, previous.p, next.p) <= scaled<double>(0.005)) // Make sure that height_2 is not small because of cancellation of positive and negative areas
if ((height_2 <= Slic3r::sqr(colinear_vertex_tolerance()) // Almost exactly colinear (barring rounding errors).
&& Line::distance_to_infinite(current.p, previous.p, next.p) <= double(colinear_vertex_tolerance())) // Make sure that height_2 is not small because of cancellation of positive and negative areas
// We shouldn't remove middle junctions of colinear segments if the area changed for the C-P segment is exceeding the maximum allowed
&& extrusion_area_error <= maximum_extrusion_area_deviation)
{
@@ -32,6 +32,14 @@ class Flow;
namespace Slic3r::Arachne
{
// ORCA: Tolerance of the "almost exactly colinear" early-out shared by the two simplify() passes
// (this file and WallToolPaths.cpp). That test drops a vertex regardless of the user's Maximum wall
// resolution/deviation, so it has to stay at the scale of coordinate rounding noise. A larger value
// silently decimates finely tessellated curves: on a circle, one vertex may be removed whenever the
// sagitta of the resulting chord falls below the tolerance, which halves the point count and turns
// smooth arcs into corners the firmware has to decelerate through.
inline coord_t colinear_vertex_tolerance() { return coord_t(SCALED_EPSILON); }
/*!
* Represents a polyline (not just a line) that is to be extruded with variable
* line width.
+19 -1
View File
@@ -184,6 +184,17 @@ set(lisbslic3r_sources
Fill/Lightning/Layer.hpp
Fill/Lightning/TreeNode.cpp
Fill/Lightning/TreeNode.hpp
FilamentMixer.cpp
FilamentMixer.hpp
FilamentMixerModel.hpp
ColorDecomposeRecipe.cpp
ColorDecomposeRecipe.hpp
TexturePainting.hpp
TexturePainting.cpp
TextureToColor/TextureToColor.hpp
TextureToColor/TextureToColor.cpp
TextureToColor/ColorUtils.hpp
TextureToColor/ColorUtils.cpp
Flow.cpp
Flow.hpp
FlushVolCalc.cpp
@@ -199,6 +210,9 @@ set(lisbslic3r_sources
format.hpp
Format/OBJ.cpp
Format/OBJ.hpp
Format/AssimpImport.hpp
Format/AssimpImport.cpp
Format/ResourcePathUtils.hpp
Format/objparser.cpp
Format/objparser.hpp
Format/SL1.cpp
@@ -353,6 +367,8 @@ set(lisbslic3r_sources
Polyline.hpp
PresetBundle.cpp
PresetBundle.hpp
PresetCacheFormat.cpp
PresetCacheFormat.hpp
Preset.cpp
Preset.hpp
PrincipalComponents2D.cpp
@@ -535,6 +551,7 @@ cmake_policy(SET CMP0011 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0167 NEW)
find_package(CGAL REQUIRED)
find_package(OpenCV REQUIRED core)
find_package(assimp REQUIRED)
unset(CMAKE_POLICY_DEFAULT_CMP0167)
cmake_policy(POP)
@@ -575,7 +592,7 @@ target_compile_definitions(libslic3r PUBLIC -DUSE_TBB -DTBB_USE_CAPTURED_EXCEPTI
if (USE_SLIC3R_CONSOLE_LOG)
target_compile_definitions(libslic3r PRIVATE $<$<CONFIG:RelWithDebInfo>:SLIC3R_CONSOLE_LOG>)
endif()
target_include_directories(libslic3r PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(libslic3r PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/TextureToColor PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(libslic3r SYSTEM PUBLIC ${EXPAT_INCLUDE_DIRS})
# Find the OCCT and related libraries
@@ -642,6 +659,7 @@ target_link_libraries(libslic3r
libnest2d
miniz
opencv_world
assimp::assimp
PRIVATE
${CMAKE_DL_LIBS}
${EXPAT_LIBRARIES}
+530
View File
@@ -0,0 +1,530 @@
#include "ColorDecomposeRecipe.hpp"
#include "FilamentMixer.hpp"
#include "Utils.hpp"
#include "nlohmann/json.hpp"
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <fstream>
#include <limits>
#include <utility>
namespace Slic3r {
namespace {
struct LabColor {
double l{0.0};
double a{0.0};
double b{0.0};
};
struct StandardRecipeEntry {
ColorDecomposeRecipeMode mode{ColorDecomposeRecipeMode::CMYW};
std::string material;
std::string source;
std::vector<std::string> component_keys;
std::vector<std::string> component_hexes;
std::vector<int> ratios;
std::string measured_hex;
LabColor measured_lab;
};
static double srgb_to_linear(double v)
{
v /= 255.0;
return v <= 0.04045 ? v / 12.92 : std::pow((v + 0.055) / 1.055, 2.4);
}
static double xyz_to_lab_component(double v)
{
constexpr double eps = 216.0 / 24389.0;
constexpr double kappa = 24389.0 / 27.0;
return v > eps ? std::cbrt(v) : (kappa * v + 16.0) / 116.0;
}
static LabColor rgb_to_lab(const ColorDecomposeRgb& rgb)
{
const double r = srgb_to_linear(rgb.r);
const double g = srgb_to_linear(rgb.g);
const double b = srgb_to_linear(rgb.b);
const double x = (0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / 0.95047;
const double y = (0.2126729 * r + 0.7151522 * g + 0.0721750 * b);
const double z = (0.0193339 * r + 0.1191920 * g + 0.9503041 * b) / 1.08883;
const double fx = xyz_to_lab_component(x);
const double fy = xyz_to_lab_component(y);
const double fz = xyz_to_lab_component(z);
return {116.0 * fy - 16.0, 500.0 * (fx - fy), 200.0 * (fy - fz)};
}
static std::string lab_to_srgb_hex(const LabColor& lab)
{
constexpr double Xn = 0.95047, Yn = 1.0, Zn = 1.08883;
auto f_inv = [](double t) -> double {
constexpr double eps = 216.0 / 24389.0;
constexpr double kappa = 24389.0 / 27.0;
const double t3 = t * t * t;
return t3 > eps ? t3 : (t * 116.0 - 16.0) / kappa;
};
const double fy = (lab.l + 16.0) / 116.0;
const double fx = lab.a / 500.0 + fy;
const double fz = fy - lab.b / 200.0;
const double X = Xn * f_inv(fx);
const double Y = Yn * f_inv(fy);
const double Z = Zn * f_inv(fz);
double r = 3.2406 * X - 1.5372 * Y - 0.4986 * Z;
double g = -0.9689 * X + 1.8758 * Y + 0.0415 * Z;
double b = 0.0557 * X - 0.2040 * Y + 1.0570 * Z;
auto gamma = [](double c) -> double {
c = std::max(0.0, std::min(1.0, c));
return c <= 0.0031308 ? 12.92 * c : 1.055 * std::pow(c, 1.0 / 2.4) - 0.055;
};
auto u8 = [&](double c) -> int {
return std::max(0, std::min(255, static_cast<int>(std::lround(gamma(c) * 255.0))));
};
char buf[8];
std::snprintf(buf, sizeof(buf), "#%02X%02X%02X", u8(r), u8(g), u8(b));
return std::string(buf);
}
static double delta_e76(const LabColor& a, const LabColor& b)
{
return std::sqrt(std::pow(a.l - b.l, 2.0) + std::pow(a.a - b.a, 2.0) + std::pow(a.b - b.b, 2.0));
}
static bool material_matches(const std::string& a, const std::string& b)
{
if (a.empty() || b.empty())
return false;
return a == b || a == b + " Basic" || b == a + " Basic";
}
static std::vector<std::vector<int>> ratio_grid(size_t n)
{
std::vector<std::vector<int>> out;
if (n == 2) {
for (int a = 20; a <= 80; a += 5)
out.push_back({a, 100 - a});
} else if (n == 3) {
for (int a = 20; a <= 60; a += 5)
for (int b = 20; b <= 80 - a; b += 5) {
const int c = 100 - a - b;
if (c >= 20)
out.push_back({a, b, c});
}
}
return out;
}
static ColorDecomposeRecipeMode parse_mode(const std::string& s)
{
if (s == "RYBW" || s == "RGBY")
return ColorDecomposeRecipeMode::RYBW;
return ColorDecomposeRecipeMode::CMYW;
}
static std::vector<StandardRecipeEntry> load_standard_entries()
{
std::vector<StandardRecipeEntry> entries;
const std::string path = resources_dir() + "/filament_mixing/standard_color_recipes.json";
std::ifstream ifs(path);
if (!ifs)
return entries;
nlohmann::json root = nlohmann::json::parse(ifs, nullptr, false);
if (root.is_discarded() || !root.contains("entries") || !root["entries"].is_array())
return entries;
for (const auto& item : root["entries"]) {
if (!item.is_object())
continue;
StandardRecipeEntry entry;
entry.mode = parse_mode(item.value("mode", "CMYW"));
entry.material = item.value("material", "");
entry.source = item.value("source", "");
entry.measured_hex = item.value("measured_rgb", "");
if (item.contains("components") && item["components"].is_array()) {
for (const auto& comp : item["components"]) {
if (comp.is_object()) {
entry.component_keys.push_back(comp.value("key", ""));
entry.component_hexes.push_back(comp.value("rgb", ""));
}
}
}
if (item.contains("ratios") && item["ratios"].is_array()) {
for (const auto& ratio : item["ratios"]) {
if (ratio.is_number_integer())
entry.ratios.push_back(ratio.get<int>());
}
}
if (item.contains("measured_lab") && item["measured_lab"].is_array() && item["measured_lab"].size() >= 3) {
entry.measured_lab = {
item["measured_lab"][0].get<double>(),
item["measured_lab"][1].get<double>(),
item["measured_lab"][2].get<double>()
};
} else {
ColorDecomposeRgb measured_rgb;
if (!color_decompose_hex_to_rgb(entry.measured_hex, measured_rgb))
continue;
entry.measured_lab = rgb_to_lab(measured_rgb);
}
if (entry.component_hexes.size() >= 2 && entry.component_hexes.size() == entry.ratios.size() &&
!entry.measured_hex.empty())
entries.push_back(std::move(entry));
}
return entries;
}
static const std::vector<StandardRecipeEntry>& standard_entries()
{
static const std::vector<StandardRecipeEntry> entries = load_standard_entries();
return entries;
}
static void evaluate_candidate(const ColorDecomposeRgb& target,
const std::vector<std::string>& hexes,
const std::vector<int>& ratios,
const std::vector<unsigned int>& indices,
ColorDecomposeRecipeMode mode,
double& best_score,
ColorDecomposeRecipeResult& best)
{
const std::string mixed = blend_color_multi(hexes, ratios);
ColorDecomposeRgb mixed_rgb;
if (!color_decompose_hex_to_rgb(mixed, mixed_rgb))
return;
const double score = delta_e76(rgb_to_lab(target), rgb_to_lab(mixed_rgb));
if (score >= best_score)
return;
best_score = score;
best.valid = true;
best.mode = mode;
best.matched_color_hex = mixed;
best.components.clear();
for (size_t i = 0; i < hexes.size(); ++i) {
ColorDecomposeRecipeComponent comp;
comp.color_hex = hexes[i];
comp.ratio = ratios[i];
comp.filament_index = i < indices.size() ? indices[i] : 0;
best.components.push_back(comp);
}
}
} // namespace
std::string color_decompose_rgb_to_hex(const ColorDecomposeRgb& rgb)
{
char buf[8];
std::snprintf(buf, sizeof(buf), "#%02X%02X%02X", rgb.r, rgb.g, rgb.b);
return std::string(buf);
}
bool color_decompose_hex_to_rgb(const std::string& hex, ColorDecomposeRgb& out)
{
if (hex.size() < 7 || hex[0] != '#')
return false;
unsigned r = 0, g = 0, b = 0;
if (std::sscanf(hex.c_str(), "#%02x%02x%02x", &r, &g, &b) != 3)
return false;
out = {static_cast<unsigned char>(r), static_cast<unsigned char>(g), static_cast<unsigned char>(b)};
return true;
}
ColorDecomposeRecipeResult recommend_from_physical_filaments(
const ColorDecomposeRgb& target,
const std::vector<ColorDecomposePhysicalFilament>& physical_filaments,
const std::string& preferred_material_type)
{
std::vector<ColorDecomposePhysicalFilament> candidates;
for (const auto& filament : physical_filaments) {
if (filament.is_mixed)
continue;
ColorDecomposeRgb ignored;
if (!color_decompose_hex_to_rgb(filament.color_hex, ignored))
continue;
if (preferred_material_type.empty() || material_matches(filament.type, preferred_material_type))
candidates.push_back(filament);
}
// Early exit: if a material-matched candidate has the exact target color,
// return it as 100%. Downstream rejects single-component results (no mixed
// slot created), which is correct -- the color already exists.
const std::string target_hex = color_decompose_rgb_to_hex(target);
for (const auto& cand : candidates) {
ColorDecomposeRgb cand_rgb;
if (!color_decompose_hex_to_rgb(cand.color_hex, cand_rgb))
continue;
if (color_decompose_rgb_to_hex(cand_rgb) == target_hex) {
ColorDecomposeRecipeResult exact;
exact.valid = true;
exact.mode = ColorDecomposeRecipeMode::MaterialList;
exact.matched_color_hex = cand.color_hex;
ColorDecomposeRecipeComponent comp;
comp.color_hex = cand.color_hex;
comp.ratio = 100;
comp.filament_index = cand.filament_index;
exact.components.push_back(comp);
return exact;
}
}
if (candidates.size() < 2)
candidates = physical_filaments;
candidates.erase(std::remove_if(candidates.begin(), candidates.end(), [](const auto& filament) {
if (filament.is_mixed)
return true;
ColorDecomposeRgb ignored;
return !color_decompose_hex_to_rgb(filament.color_hex, ignored);
}), candidates.end());
constexpr size_t kMaxCandidates = 8;
if (candidates.size() > kMaxCandidates) {
const LabColor target_lab = rgb_to_lab(target);
std::sort(candidates.begin(), candidates.end(),
[&target_lab](const ColorDecomposePhysicalFilament& a, const ColorDecomposePhysicalFilament& b) {
ColorDecomposeRgb rgb_a, rgb_b;
color_decompose_hex_to_rgb(a.color_hex, rgb_a);
color_decompose_hex_to_rgb(b.color_hex, rgb_b);
return delta_e76(target_lab, rgb_to_lab(rgb_a))
< delta_e76(target_lab, rgb_to_lab(rgb_b));
});
candidates.resize(kMaxCandidates);
}
ColorDecomposeRecipeResult best;
double best_score = std::numeric_limits<double>::max();
for (size_t i = 0; i < candidates.size(); ++i) {
for (size_t j = i + 1; j < candidates.size(); ++j) {
const std::vector<std::string> hexes = {candidates[i].color_hex, candidates[j].color_hex};
const std::vector<unsigned int> indices = {candidates[i].filament_index, candidates[j].filament_index};
for (const auto& ratios : ratio_grid(2))
evaluate_candidate(target, hexes, ratios, indices, ColorDecomposeRecipeMode::MaterialList, best_score, best);
for (size_t k = j + 1; k < candidates.size(); ++k) {
const std::vector<std::string> hexes3 = {candidates[i].color_hex, candidates[j].color_hex, candidates[k].color_hex};
const std::vector<unsigned int> indices3 = {candidates[i].filament_index, candidates[j].filament_index, candidates[k].filament_index};
for (const auto& ratios : ratio_grid(3))
evaluate_candidate(target, hexes3, ratios, indices3, ColorDecomposeRecipeMode::MaterialList, best_score, best);
}
}
}
return best;
}
ColorDecomposeRecipeResult lookup_standard_recipe(
const ColorDecomposeRgb& target,
ColorDecomposeRecipeMode mode,
const std::string& preferred_material_type)
{
const LabColor target_lab = rgb_to_lab(target);
ColorDecomposeRecipeResult best;
double best_score = std::numeric_limits<double>::max();
auto consider = [&](bool require_material_match) {
for (const StandardRecipeEntry& entry : standard_entries()) {
if (entry.mode != mode)
continue;
if (require_material_match && !material_matches(entry.material, preferred_material_type))
continue;
if (!require_material_match && !preferred_material_type.empty() && material_matches(entry.material, preferred_material_type))
continue;
const double score = delta_e76(target_lab, entry.measured_lab);
if (score >= best_score)
continue;
best_score = score;
best.valid = true;
best.mode = mode;
best.matched_color_hex = entry.measured_hex;
best.components.clear();
for (size_t i = 0; i < entry.component_hexes.size(); ++i) {
ColorDecomposeRecipeComponent comp;
comp.color_hex = entry.component_hexes[i];
comp.base_color = i < entry.component_keys.size() ? entry.component_keys[i] : "";
comp.ratio = entry.ratios[i];
comp.filament_index = 0;
best.components.push_back(comp);
}
}
};
consider(true);
if (!best.valid)
consider(false);
return best;
}
std::string lookup_measured_blend_color(const std::vector<std::string>& component_hexes,
const std::vector<int>& ratios)
{
if (component_hexes.size() < 2 || component_hexes.size() != ratios.size())
return {};
auto normalize_hex = [](const std::string& hex) -> std::string {
ColorDecomposeRgb rgb;
if (!color_decompose_hex_to_rgb(hex, rgb))
return {};
char buf[8];
std::snprintf(buf, sizeof(buf), "#%02X%02X%02X", rgb.r, rgb.g, rgb.b);
return std::string(buf);
};
// Stage 1: canonicalize input by sorting (hex, ratio) pairs so matching
// is independent of the caller's component order.
const size_t n = component_hexes.size();
std::vector<std::pair<std::string, int>> in_pairs;
in_pairs.reserve(n);
for (size_t i = 0; i < n; ++i) {
std::string nh = normalize_hex(component_hexes[i]);
if (nh.empty())
return {};
in_pairs.emplace_back(std::move(nh), ratios[i]);
}
std::sort(in_pairs.begin(), in_pairs.end());
std::vector<std::string> in_hexes;
std::vector<int> in_ratios;
in_hexes.reserve(n);
in_ratios.reserve(n);
for (const auto& p : in_pairs) {
in_hexes.push_back(p.first);
in_ratios.push_back(p.second);
}
// Normalize ratios to sum=100 (callers may pass arbitrary weights,
// e.g. MixedFilamentDialog uses ratio*10000).
{
int sum = 0;
for (int r : in_ratios) sum += r;
if (sum > 0 && sum != 100) {
int new_sum = 0;
for (size_t i = 0; i < in_ratios.size(); ++i) {
in_ratios[i] = static_cast<int>(std::lround(
static_cast<double>(in_ratios[i]) * 100.0 / static_cast<double>(sum)));
new_sum += in_ratios[i];
}
if (new_sum != 100) {
auto it = std::max_element(in_ratios.begin(), in_ratios.end());
*it += (100 - new_sum);
}
}
}
// Fall back to polynomial model for ratios outside the measured range.
{
bool out_of_range = false;
if (n == 2) {
for (int r : in_ratios)
if (r < 20 || r > 80) { out_of_range = true; break; }
} else {
for (int r : in_ratios)
if (r < 20) { out_of_range = true; break; }
}
if (out_of_range)
return {};
}
// Stage 2: collect anchors with the same component hex set; try exact match.
struct Anchor {
std::vector<int> ratios;
LabColor lab;
std::string hex;
};
std::vector<Anchor> anchors;
for (const StandardRecipeEntry& entry : standard_entries()) {
if (entry.source != "measured" && entry.source != "interpolated")
continue;
if (entry.component_hexes.size() != n)
continue;
std::vector<std::pair<std::string, int>> e_pairs;
e_pairs.reserve(n);
for (size_t i = 0; i < n; ++i)
e_pairs.emplace_back(normalize_hex(entry.component_hexes[i]), entry.ratios[i]);
std::sort(e_pairs.begin(), e_pairs.end());
bool same_set = true;
for (size_t i = 0; i < n; ++i)
if (e_pairs[i].first != in_hexes[i]) { same_set = false; break; }
if (!same_set)
continue;
Anchor a;
a.ratios.reserve(n);
for (const auto& p : e_pairs) a.ratios.push_back(p.second);
a.lab = entry.measured_lab;
a.hex = entry.measured_hex;
if (a.ratios == in_ratios)
return a.hex;
anchors.push_back(std::move(a));
}
if (anchors.size() < 2)
return {};
// Stage 3: interpolation in Lab space.
if (n == 2) {
// 1D linear interpolation along ratio[0].
std::sort(anchors.begin(), anchors.end(),
[](const Anchor& a, const Anchor& b) { return a.ratios[0] < b.ratios[0]; });
const double x = static_cast<double>(in_ratios[0]);
size_t lo = 0;
while (lo + 2 < anchors.size() && static_cast<double>(anchors[lo + 1].ratios[0]) <= x)
++lo;
const Anchor& a0 = anchors[lo];
const Anchor& a1 = anchors[lo + 1];
const double span = static_cast<double>(a1.ratios[0] - a0.ratios[0]);
const double t = span > 0.0 ? (x - static_cast<double>(a0.ratios[0])) / span : 0.0;
return lab_to_srgb_hex({a0.lab.l + t * (a1.lab.l - a0.lab.l),
a0.lab.a + t * (a1.lab.a - a0.lab.a),
a0.lab.b + t * (a1.lab.b - a0.lab.b)});
}
// 3+ color: IDW (p=2) with 3 nearest anchors in the (ratio[0], ratio[1]) plane.
const double ra = static_cast<double>(in_ratios[0]);
const double rb = static_cast<double>(in_ratios[1]);
std::vector<std::pair<double, const Anchor*>> dists;
dists.reserve(anchors.size());
for (const Anchor& a : anchors) {
const double d = std::sqrt(std::pow(ra - static_cast<double>(a.ratios[0]), 2.0) +
std::pow(rb - static_cast<double>(a.ratios[1]), 2.0));
if (d == 0.0)
return a.hex;
dists.emplace_back(d, &a);
}
const size_t k = std::min(static_cast<size_t>(3), dists.size());
std::partial_sort(dists.begin(), dists.begin() + k, dists.end(),
[](const auto& a, const auto& b) { return a.first < b.first; });
double num_l = 0.0, num_a = 0.0, num_b = 0.0, den = 0.0;
for (size_t j = 0; j < k; ++j) {
const double w = 1.0 / (dists[j].first * dists[j].first);
num_l += w * dists[j].second->lab.l;
num_a += w * dists[j].second->lab.a;
num_b += w * dists[j].second->lab.b;
den += w;
}
return lab_to_srgb_hex({num_l / den, num_a / den, num_b / den});
}
} // namespace Slic3r
+64
View File
@@ -0,0 +1,64 @@
#ifndef SLIC3R_COLOR_DECOMPOSE_RECIPE_HPP
#define SLIC3R_COLOR_DECOMPOSE_RECIPE_HPP
#include <string>
#include <vector>
namespace Slic3r {
enum class ColorDecomposeRecipeMode {
MaterialList,
CMYW,
RYBW
};
struct ColorDecomposeRgb {
unsigned char r{0};
unsigned char g{0};
unsigned char b{0};
};
struct ColorDecomposePhysicalFilament {
std::string color_hex;
std::string name;
std::string type;
bool is_mixed{false};
unsigned int filament_index{0}; // 1-based physical filament index
};
struct ColorDecomposeRecipeComponent {
std::string color_hex;
std::string base_color;
int ratio{0};
unsigned int filament_index{0}; // 1-based for physical filaments, 0 for standard base colors
};
struct ColorDecomposeRecipeResult {
bool valid{false};
ColorDecomposeRecipeMode mode{ColorDecomposeRecipeMode::MaterialList};
std::string matched_color_hex;
std::vector<ColorDecomposeRecipeComponent> components;
};
std::string color_decompose_rgb_to_hex(const ColorDecomposeRgb& rgb);
bool color_decompose_hex_to_rgb(const std::string& hex, ColorDecomposeRgb& out);
ColorDecomposeRecipeResult recommend_from_physical_filaments(
const ColorDecomposeRgb& target,
const std::vector<ColorDecomposePhysicalFilament>& physical_filaments,
const std::string& preferred_material_type);
ColorDecomposeRecipeResult lookup_standard_recipe(
const ColorDecomposeRgb& target,
ColorDecomposeRecipeMode mode,
const std::string& preferred_material_type);
// Look up the measured blend color for an exact (component_hexes, ratios) match
// in the standard color recipe table. Returns the measured hex color if found
// with reliable source data ("measured" or "interpolated"), empty string otherwise.
std::string lookup_measured_blend_color(const std::vector<std::string>& component_hexes,
const std::vector<int>& ratios);
} // namespace Slic3r
#endif // SLIC3R_COLOR_DECOMPOSE_RECIPE_HPP
+2 -1
View File
@@ -2031,7 +2031,8 @@ const double& DynamicConfig::opt_float(const t_config_option_key &opt_key, unsig
return opt_floats_nullable->get_at(idx);
} else {
assert(false);
return 0;
static const double zero = 0.0;
return zero;
}
}
+3
View File
@@ -28,6 +28,9 @@
#include <cereal/access.hpp>
#include <cereal/types/base_class.hpp>
// The serialize() members below archive ConfigOption hierarchies through
// cereal::base_class, whose registration machinery lives in polymorphic.hpp.
#include <cereal/types/polymorphic.hpp>
namespace Slic3r {
struct FloatOrPercent
+14 -5
View File
@@ -682,7 +682,7 @@ Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perim
return fuzzified;
}
void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerator& perimeter_generator, const bool is_contour)
void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerator& perimeter_generator, const bool is_contour, const bool closed)
{
const auto slice_z = perimeter_generator.slice_z;
const auto& regions = perimeter_generator.regions_by_fuzzify;
@@ -690,7 +690,7 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
const auto& config = regions.begin()->first;
const bool fuzzify = should_fuzzify(config, perimeter_generator.layer_id, extrusion->inset_idx, is_contour);
if (fuzzify)
fuzzy_extrusion_line(extrusion->junctions, slice_z, config);
fuzzy_extrusion_line(extrusion->junctions, slice_z, config, closed);
} else {
// Merge regions that produce identical fuzzy effects (differ only in type).
// When the style (e.g. External) and a painted region (All) both fuzzify this loop
@@ -701,10 +701,19 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
// Fast path: single merged region — apply directly without splitting
if (merged_regions.size() == 1 && merged_regions.front().expolygons.empty()) {
fuzzy_extrusion_line(extrusion->junctions, slice_z, *merged_regions.front().config);
fuzzy_extrusion_line(extrusion->junctions, slice_z, *merged_regions.front().config, closed);
return;
}
// Open path means this is a thin wall that collapsed into a single thick line, in this case the path will go exactly
// between the middle two sides of the object. And since the paint segmentation never goes beyond the middle line because
// it uses voronoi diagram, we need to expand the segmentation a little bit to make sure it covers the path.
if (!closed) {
for (auto& r : merged_regions) {
r.expolygons = offset_ex(r.expolygons, perimeter_generator.ext_perimeter_flow.scaled_width() / 10);
}
}
#ifdef DEBUG_FUZZY
{
int i = 0;
@@ -752,7 +761,7 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
// Fuzzy splitted extrusion
if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) {
// The entire polygon is fuzzified
fuzzy_extrusion_line(extrusion->junctions, slice_z, *r.config);
fuzzy_extrusion_line(extrusion->junctions, slice_z, *r.config, closed);
continue;
} else {
const auto current_ext = extrusion->junctions;
@@ -803,7 +812,7 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
}
//Orca: ensure the loop is closed after fuzzy
if (!extrusion->junctions.empty() && extrusion->junctions.front().p != extrusion->junctions.back().p) {
if (closed && !extrusion->junctions.empty() && extrusion->junctions.front().p != extrusion->junctions.back().p) {
extrusion->junctions.back().p = extrusion->junctions.front().p;
extrusion->junctions.back().w = extrusion->junctions.front().w;
}
@@ -16,7 +16,7 @@ void group_region_by_fuzzify(PerimeterGenerator& g);
bool should_fuzzify(const FuzzySkinConfig& config, int layer_id, size_t loop_idx, bool is_contour);
Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perimeter_generator, size_t loop_idx, bool is_contour);
void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerator& perimeter_generator, bool is_contour);
void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerator& perimeter_generator, bool is_contour, bool closed = true);
} // namespace Slic3r::Feature::FuzzySkin
+1 -1
View File
@@ -1021,7 +1021,7 @@ namespace Slic3r
if (FGMode::MatchMode == ctx.group_info.mode)
return calc_filament_group_for_match(cost);
}
catch (const FilamentGroupException& e) {
catch (const FilamentGroupException&) {
}
return calc_filament_group_for_flush(cost);
+829
View File
@@ -0,0 +1,829 @@
#include "FilamentMixer.hpp"
#include <algorithm>
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <limits>
#include <set>
#include <sstream>
#include <numeric>
#include <boost/log/trivial.hpp>
#include "ColorDecomposeRecipe.hpp"
#include "FilamentMixerModel.hpp"
#include "LocalesUtils.hpp"
namespace Slic3r {
namespace {
inline float clamp01(float x)
{
return std::max(0.0f, std::min(1.0f, x));
}
inline float srgb_to_linear(float x)
{
return (x >= 0.04045f) ? std::pow((x + 0.055f) / 1.055f, 2.4f) : x / 12.92f;
}
inline float linear_to_srgb(float x)
{
return (x >= 0.0031308f) ? (1.055f * std::pow(x, 1.0f / 2.4f) - 0.055f) : (12.92f * x);
}
inline unsigned char to_u8(float x)
{
const float clamped = clamp01(x);
return static_cast<unsigned char>(clamped * 255.0f + 0.5f);
}
inline float to_f01(unsigned char x)
{
return static_cast<float>(x) / 255.0f;
}
} // namespace
void filament_mixer_lerp(unsigned char r1, unsigned char g1, unsigned char b1,
unsigned char r2, unsigned char g2, unsigned char b2,
float t,
unsigned char* out_r, unsigned char* out_g, unsigned char* out_b)
{
::filament_mixer::lerp(r1, g1, b1, r2, g2, b2, t, out_r, out_g, out_b);
}
void filament_mixer_lerp_float(float r1, float g1, float b1,
float r2, float g2, float b2,
float t,
float* out_r, float* out_g, float* out_b)
{
unsigned char ur = 0, ug = 0, ub = 0;
filament_mixer_lerp(to_u8(r1), to_u8(g1), to_u8(b1),
to_u8(r2), to_u8(g2), to_u8(b2),
t, &ur, &ug, &ub);
*out_r = to_f01(ur);
*out_g = to_f01(ug);
*out_b = to_f01(ub);
}
void filament_mixer_lerp_linear_float(float r1, float g1, float b1,
float r2, float g2, float b2,
float t,
float* out_r, float* out_g, float* out_b)
{
const float sr1 = linear_to_srgb(clamp01(r1));
const float sg1 = linear_to_srgb(clamp01(g1));
const float sb1 = linear_to_srgb(clamp01(b1));
const float sr2 = linear_to_srgb(clamp01(r2));
const float sg2 = linear_to_srgb(clamp01(g2));
const float sb2 = linear_to_srgb(clamp01(b2));
float out_sr = 0.0f, out_sg = 0.0f, out_sb = 0.0f;
filament_mixer_lerp_float(sr1, sg1, sb1, sr2, sg2, sb2, t, &out_sr, &out_sg, &out_sb);
*out_r = srgb_to_linear(clamp01(out_sr));
*out_g = srgb_to_linear(clamp01(out_sg));
*out_b = srgb_to_linear(clamp01(out_sb));
}
static bool parse_hex(const std::string &hex, unsigned char &r, unsigned char &g, unsigned char &b)
{
if (hex.size() < 7 || hex[0] != '#') return false;
unsigned rv = 0, gv = 0, bv = 0;
if (std::sscanf(hex.c_str(), "#%02x%02x%02x", &rv, &gv, &bv) != 3) return false;
r = (unsigned char)rv; g = (unsigned char)gv; b = (unsigned char)bv;
return true;
}
std::string blend_color(const std::string& hex_a, const std::string& hex_b, float ratio_b)
{
unsigned char r1 = 128, g1 = 128, b1 = 128;
unsigned char r2 = 128, g2 = 128, b2 = 128;
parse_hex(hex_a, r1, g1, b1);
parse_hex(hex_b, r2, g2, b2);
unsigned char mr = 0, mg = 0, mb = 0;
filament_mixer_lerp(r1, g1, b1, r2, g2, b2, ratio_b, &mr, &mg, &mb);
char buf[8];
std::snprintf(buf, sizeof(buf), "#%02X%02X%02X", mr, mg, mb);
return std::string(buf);
}
std::string blend_color_multi(const std::vector<std::string> &hex_colors,
const std::vector<int> &weights)
{
if (hex_colors.size() >= 2 && hex_colors.size() == weights.size()) {
std::string measured = lookup_measured_blend_color(hex_colors, weights);
if (!measured.empty())
return measured;
}
if (hex_colors.empty())
return "#000000";
if (hex_colors.size() == 1) {
unsigned char cr = 128, cg = 128, cb = 128;
parse_hex(hex_colors.front(), cr, cg, cb);
char buf[8];
std::snprintf(buf, sizeof(buf), "#%02X%02X%02X", cr, cg, cb);
return std::string(buf);
}
assert(hex_colors.size() == weights.size());
unsigned char r = 128, g = 128, b = 128;
int accumulated = 0;
for (size_t i = 0; i < hex_colors.size() && i < weights.size(); ++i) {
if (weights[i] <= 0)
continue;
unsigned char cr = 128, cg = 128, cb = 128;
parse_hex(hex_colors[i], cr, cg, cb);
if (accumulated == 0) {
r = cr; g = cg; b = cb;
accumulated = weights[i];
} else {
const int new_total = accumulated + weights[i];
const float t = static_cast<float>(weights[i]) / static_cast<float>(new_total);
filament_mixer_lerp(r, g, b, cr, cg, cb, t, &r, &g, &b);
accumulated = new_total;
}
}
if (accumulated == 0)
return "#000000";
char buf[8];
std::snprintf(buf, sizeof(buf), "#%02X%02X%02X", r, g, b);
return std::string(buf);
}
std::vector<unsigned int> parse_mixed_components(const std::string &str)
{
std::vector<unsigned int> components;
if (str.empty())
return components;
std::istringstream ss(str);
std::string token;
while (std::getline(ss, token, ',')) {
try {
int val = std::stoi(token);
if (val >= 0)
components.push_back(static_cast<unsigned int>(val));
} catch (...) {}
}
return components;
}
namespace {
// Parse a token that may represent a finite double or "use default" (empty / "nan").
// Returns NaN on either explicit sentinel or any parse error.
inline double parse_tangent_token(const std::string& tok)
{
if (tok.empty()) return std::numeric_limits<double>::quiet_NaN();
std::string lower(tok.size(), '\0');
std::transform(tok.begin(), tok.end(), lower.begin(),
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
if (lower == "nan") return std::numeric_limits<double>::quiet_NaN();
try {
const double v = std::stod(tok);
if (!std::isfinite(v)) return std::numeric_limits<double>::quiet_NaN();
return v;
} catch (...) {
return std::numeric_limits<double>::quiet_NaN();
}
}
// Split a "a,b,c,d" segment on commas, preserving empty tokens (so "0.5,0.4,," yields
// {"0.5","0.4","",""}). Used by the gradient-curve parser to distinguish NaN tangents
// from a malformed segment.
inline std::vector<std::string> split_commas(const std::string& seg)
{
std::vector<std::string> out;
size_t start = 0;
while (true) {
const size_t comma = seg.find(',', start);
if (comma == std::string::npos) {
out.emplace_back(seg.substr(start));
return out;
}
out.emplace_back(seg.substr(start, comma - start));
start = comma + 1;
}
}
} // namespace
// Default Fritsch-Carlson PCHIP tangents for a sorted-by-x anchor list. m has size n
// matching the anchor count; for n == 1 the tangent is 0; for n == 2 both endpoint
// tangents equal the single secant (degenerates to linear).
std::vector<double> compute_pchip_default_tangents(const std::vector<GradientAnchor>& pts)
{
const size_t n = pts.size();
std::vector<double> m(n, 0.0);
if (n < 2) return m;
std::vector<double> d(n - 1);
for (size_t i = 0; i + 1 < n; ++i) {
const double h = std::max(1e-12, pts[i + 1].x - pts[i].x);
d[i] = (pts[i + 1].y - pts[i].y) / h;
}
m[0] = d[0];
m[n - 1] = d[n - 2];
for (size_t i = 1; i + 1 < n; ++i)
m[i] = 0.5 * (d[i - 1] + d[i]);
// Fritsch-Carlson monotonic guard: kill flats then rescale steep tangents so the
// resulting cubic never overshoots [min, max] of the surrounding anchors.
for (size_t i = 0; i + 1 < n; ++i) {
if (d[i] == 0.0) {
m[i] = 0.0;
m[i + 1] = 0.0;
continue;
}
const double a = m[i] / d[i];
const double b = m[i + 1] / d[i];
const double s = a * a + b * b;
if (s > 9.0) {
const double tau = 3.0 / std::sqrt(s);
m[i] = tau * a * d[i];
m[i + 1] = tau * b * d[i];
}
}
return m;
}
GradientCurve parse_gradient_curve(const std::string& s)
{
GradientCurve curve;
if (s.empty())
return curve;
CNumericLocalesSetter c_locale_setter;
std::istringstream ss(s);
std::string segment;
while (std::getline(ss, segment, '|')) {
if (segment.empty())
continue;
const auto fields = split_commas(segment);
// 2-field legacy form -> (x, y), tangents stay NaN.
// 4-field form -> (x, y, m_in, m_out), empty / "nan" tokens preserved as NaN.
if (fields.size() != 2 && fields.size() != 4) {
BOOST_LOG_TRIVIAL(warning) << "parse_gradient_curve: ignoring malformed segment \""
<< segment << "\" (expected 2 or 4 comma-separated fields, got "
<< fields.size() << ")";
continue;
}
try {
double x = std::stod(fields[0]);
double y = std::stod(fields[1]);
x = std::max(0.0, std::min(1.0, x));
y = std::max(kGradientMinRatio, std::min(kGradientMaxRatio, y));
GradientAnchor a;
a.x = x;
a.y = y;
if (fields.size() == 4) {
a.m_in = parse_tangent_token(fields[2]);
a.m_out = parse_tangent_token(fields[3]);
}
curve.points.push_back(a);
} catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(warning) << "parse_gradient_curve: ignoring unparseable segment \""
<< segment << "\": " << e.what();
}
}
if (curve.points.size() < 2) {
if (!curve.points.empty())
BOOST_LOG_TRIVIAL(warning) << "parse_gradient_curve: only "
<< curve.points.size() << " valid point(s), need at least 2; discarding";
curve.points.clear();
return curve;
}
std::sort(curve.points.begin(), curve.points.end(),
[](const GradientAnchor& a, const GradientAnchor& b) {
return a.x < b.x;
});
return curve;
}
std::string serialize_gradient_curve(const GradientCurve& c)
{
if (c.points.empty())
return std::string{};
CNumericLocalesSetter c_locale_setter;
std::string out;
char buf[128];
for (size_t i = 0; i < c.points.size(); ++i) {
if (i > 0) out += '|';
const auto& a = c.points[i];
const bool has_in = std::isfinite(a.m_in);
const bool has_out = std::isfinite(a.m_out);
if (has_in || has_out) {
// Emit empty tokens for NaN slots so the legacy parser would still split
// four fields; the new parser interprets empty tokens as "use PCHIP default".
char in_buf[32] = {0};
char out_buf[32] = {0};
if (has_in) std::snprintf(in_buf, sizeof(in_buf), "%.4f", a.m_in);
if (has_out) std::snprintf(out_buf, sizeof(out_buf), "%.4f", a.m_out);
std::snprintf(buf, sizeof(buf), "%.4f,%.4f,%s,%s",
a.x, a.y, in_buf, out_buf);
} else {
// 4-field form is only emitted when at least one tangent is finite; the
// 2-field form is emitted otherwise so the JSON payload stays minimal
// and remains readable by older clients that only know (x, y) pairs.
std::snprintf(buf, sizeof(buf), "%.4f,%.4f", a.x, a.y);
}
out += buf;
}
return out;
}
double sample_gradient_curve(const GradientCurve& c, double t)
{
const auto& pts = c.points;
if (pts.size() < 2)
return 0.5;
if (t <= pts.front().x)
return pts.front().y;
if (t >= pts.back().x)
return pts.back().y;
// PCHIP defaults are computed for every call; control point counts are typically
// tiny (< 16) so the allocation cost is negligible compared to any actual rendering
// or G-code work that drives the sampler.
const std::vector<double> m_def = compute_pchip_default_tangents(pts);
const size_t n = pts.size();
// Linear scan to locate the interval [pts[i].x, pts[i+1].x] containing t. Cheap
// and avoids the upper_bound boilerplate; n is small.
for (size_t i = 1; i < n; ++i) {
const double x0 = pts[i - 1].x;
const double x1 = pts[i].x;
if (t > x1) continue;
const double y0 = pts[i - 1].y;
const double y1 = pts[i].y;
const double h = std::max(1e-12, x1 - x0);
const double m_left = std::isfinite(pts[i - 1].m_out) ? pts[i - 1].m_out : m_def[i - 1];
const double m_right = std::isfinite(pts[i].m_in) ? pts[i].m_in : m_def[i];
const double u = (t - x0) / h;
const double u2 = u * u;
const double u3 = u2 * u;
const double h00 = 2.0 * u3 - 3.0 * u2 + 1.0;
const double h10 = u3 - 2.0 * u2 + u;
const double h01 = -2.0 * u3 + 3.0 * u2;
const double h11 = u3 - u2;
double y = h00 * y0 + h10 * h * m_left
+ h01 * y1 + h11 * h * m_right;
// Defensive clamp in case tangent overrides on legacy curves push the
// single-segment Hermite slightly outside the anchor band.
if (y < kGradientMinRatio) y = kGradientMinRatio;
if (y > kGradientMaxRatio) y = kGradientMaxRatio;
return y;
}
return pts.back().y;
}
std::vector<double> parse_mixed_ratios(const std::string &str, size_t n_components)
{
CNumericLocalesSetter c_locale_setter;
std::vector<double> ratios;
if (!str.empty()) {
std::istringstream ss(str);
std::string token;
while (std::getline(ss, token, ',')) {
try {
double val = std::stod(token);
if (val > 0.0)
ratios.push_back(val);
} catch (...) {}
}
}
if (ratios.size() != n_components || n_components == 0) {
ratios.assign(n_components, n_components > 0 ? 1.0 / n_components : 0.0);
return ratios;
}
double sum = std::accumulate(ratios.begin(), ratios.end(), 0.0);
if (sum > 0.0 && std::abs(sum - 1.0) > 1e-6) {
for (double &r : ratios)
r /= sum;
}
return ratios;
}
bool has_any_mixed_filament(const std::vector<unsigned char> &is_mixed)
{
for (unsigned char v : is_mixed)
if (v) return true;
return false;
}
std::vector<size_t> check_mixed_filament_integrity(
const std::vector<unsigned char> &is_mixed,
const std::vector<std::string> &comp_strs,
size_t num_physical)
{
std::vector<size_t> broken;
for (size_t i = 0; i < is_mixed.size(); ++i) {
if (!is_mixed[i]) continue;
if (i >= comp_strs.size() || comp_strs[i].empty()) {
broken.push_back(i);
continue;
}
auto comps = parse_mixed_components(comp_strs[i]);
if (comps.size() < 2) {
broken.push_back(i);
continue;
}
for (unsigned int c : comps) {
if (c < 1 || c > num_physical) {
broken.push_back(i);
break;
}
}
}
return broken;
}
std::vector<unsigned int> expand_mixed_filaments(
const std::vector<unsigned int> &extruders_0based,
const std::vector<unsigned char> &is_mixed,
const std::vector<std::string> &comp_strs)
{
std::vector<unsigned int> result;
for (unsigned int ext : extruders_0based) {
if (ext < is_mixed.size() && is_mixed[ext] && ext < comp_strs.size()) {
auto comps = parse_mixed_components(comp_strs[ext]);
for (unsigned int c : comps)
if (c >= 1) result.push_back(c - 1);
} else {
result.push_back(ext);
}
}
std::sort(result.begin(), result.end());
result.erase(std::unique(result.begin(), result.end()), result.end());
return result;
}
void remap_mixed_components_on_delete(
const std::vector<unsigned char> &is_mixed,
std::vector<std::string> &comp_strs,
unsigned int del_1based)
{
for (size_t i = 0; i < is_mixed.size(); ++i) {
if (!is_mixed[i]) continue;
if (i >= comp_strs.size() || comp_strs[i].empty()) continue;
auto comps = parse_mixed_components(comp_strs[i]);
std::ostringstream ss;
for (size_t j = 0; j < comps.size(); ++j) {
if (j > 0) ss << ',';
if (comps[j] == del_1based)
ss << 0;
else if (comps[j] > del_1based)
ss << (comps[j] - 1);
else
ss << comps[j];
}
comp_strs[i] = ss.str();
}
}
std::vector<size_t> check_mixed_filament_type_consistency(
const std::vector<unsigned char> &is_mixed,
const std::vector<std::string> &comp_strs,
const std::vector<std::string> &filament_types)
{
std::vector<size_t> result;
for (size_t i = 0; i < is_mixed.size(); ++i) {
if (!is_mixed[i]) continue;
if (i >= comp_strs.size() || comp_strs[i].empty()) continue;
auto comps = parse_mixed_components(comp_strs[i]);
if (comps.size() < 2) continue;
std::string ref_type;
bool mismatch = false;
for (unsigned int c : comps) {
if (c == 0) continue; // sentinel for deleted component
size_t idx = static_cast<size_t>(c) - 1; // 1-based -> 0-based
if (idx >= filament_types.size()) continue;
if (ref_type.empty())
ref_type = filament_types[idx];
else if (filament_types[idx] != ref_type) {
mismatch = true;
break;
}
}
if (mismatch)
result.push_back(i);
}
return result;
}
void expand_mixed_slots_in_unprintables(
std::vector<std::set<int>> &unprintables,
const std::vector<unsigned char> &is_mixed,
const std::vector<std::string> &comp_strs)
{
for (auto &unprintable_set : unprintables) {
std::set<int> expanded;
for (int fid : unprintable_set) {
if (fid >= 0 && (size_t)fid < is_mixed.size() && is_mixed[fid]
&& (size_t)fid < comp_strs.size()) {
auto comps = parse_mixed_components(comp_strs[fid]);
for (unsigned int c : comps)
if (c >= 1) expanded.insert((int)(c - 1));
} else {
expanded.insert(fid);
}
}
unprintable_set = std::move(expanded);
}
}
void sanitize_mixed_gradient_curve_array(std::vector<std::string>& vals)
{
for (size_t i = 0; i < vals.size(); ++i) {
if (vals[i].empty())
continue;
// parse_gradient_curve returns empty for both "empty input" and "<2 valid points";
// we already skipped empty, so an empty result means a corrupted single-point slot.
if (parse_gradient_curve(vals[i]).empty()) {
BOOST_LOG_TRIVIAL(warning) << "sanitize_mixed_gradient_curve_array: slot "
<< i << " curve \"" << vals[i]
<< "\" has fewer than 2 valid points; clearing to linear";
vals[i].clear();
}
}
}
bool try_parse_mixed_components_strict(const std::string &str,
std::vector<unsigned int> &components,
std::string &err)
{
components.clear();
if (str.empty()) {
err = "empty component list";
return false;
}
std::istringstream ss(str);
std::string token;
while (std::getline(ss, token, ',')) {
if (token.empty()) {
err = "empty component index";
return false;
}
try {
const long val = std::stol(token);
if (val < 1) {
err = "component index must be >= 1 (got " + token + ")";
return false;
}
components.push_back(static_cast<unsigned int>(val));
} catch (...) {
err = "invalid component index \"" + token + "\"";
return false;
}
}
if (components.size() < 2) {
err = "at least 2 components required (got " + std::to_string(components.size()) + ")";
return false;
}
std::set<unsigned int> seen;
for (unsigned int c : components) {
if (!seen.insert(c).second) {
err = "duplicate component index " + std::to_string(c);
return false;
}
}
return true;
}
bool try_parse_mixed_ratios_strict(const std::string &str,
size_t n_components,
std::string &err)
{
if (str.empty())
return true;
CNumericLocalesSetter c_locale_setter;
std::vector<double> ratios;
std::istringstream ss(str);
std::string token;
while (std::getline(ss, token, ',')) {
if (token.empty()) {
err = "empty ratio value";
return false;
}
try {
const double val = std::stod(token);
if (!(val > 0.0)) {
err = "ratio must be positive (got " + token + ")";
return false;
}
ratios.push_back(val);
} catch (...) {
err = "invalid ratio \"" + token + "\"";
return false;
}
}
if (ratios.size() != n_components) {
err = "expected " + std::to_string(n_components) + " ratio(s), got "
+ std::to_string(ratios.size());
return false;
}
return true;
}
bool validate_gradient_range_strict(const std::string &str, std::string &err)
{
if (str.empty())
return true;
CNumericLocalesSetter c_locale_setter;
float v0 = 0.f, v1 = 0.f;
if (std::sscanf(str.c_str(), "%f,%f", &v0, &v1) != 2) {
err = "expected two comma-separated floats, e.g. \"0.10,0.90\"";
return false;
}
if (!(v0 > 0.f && v0 < 1.f && v1 > 0.f && v1 < 1.f)) {
err = "start and end ratios must be in (0, 1)";
return false;
}
return true;
}
static void append_error(std::map<std::string, std::string> &errors,
const std::string &key,
const std::string &msg)
{
auto it = errors.find(key);
if (it == errors.end())
errors.emplace(key, msg);
else
it->second += "; " + msg;
}
static bool has_mixed_sub_params_specified(
const std::vector<std::string> &comp_strs,
const std::vector<std::string> &ratio_strs,
const std::vector<unsigned char> &gradient_flags)
{
for (const std::string &s : comp_strs)
if (!s.empty()) return true;
for (const std::string &s : ratio_strs)
if (!s.empty()) return true;
for (unsigned char g : gradient_flags)
if (g) return true;
return false;
}
static bool mixed_string_array_was_specified(const std::vector<std::string> &vals)
{
for (const std::string &s : vals)
if (!s.empty())
return true;
return false;
}
static bool mixed_bool_array_was_specified(const std::vector<unsigned char> &vals)
{
for (unsigned char v : vals)
if (v)
return true;
return false;
}
static void check_mixed_array_size_required(std::map<std::string, std::string> &errors,
const std::string &opt_key,
size_t actual_size,
size_t expected_size)
{
if (actual_size != expected_size) {
append_error(errors, opt_key,
"array size " + std::to_string(actual_size)
+ " does not match filament slot count " + std::to_string(expected_size));
}
}
std::map<std::string, std::string> validate_mixed_filament_params(
const std::vector<unsigned char> &is_mixed,
const std::vector<std::string> &comp_strs,
const std::vector<std::string> &ratio_strs,
const std::vector<unsigned char> &gradient_flags,
const std::vector<std::string> &gradient_range_strs,
const std::vector<std::string> &gradient_curve_strs)
{
std::map<std::string, std::string> errors;
if (has_mixed_sub_params_specified(comp_strs, ratio_strs, gradient_flags)
&& !has_any_mixed_filament(is_mixed)) {
append_error(errors, "filament_is_mixed",
"must be set when mixed filament parameters are specified");
return errors;
}
if (!has_any_mixed_filament(is_mixed))
return errors;
const size_t slot_count = is_mixed.size();
// Rule 1: mixed filament model → components & ratios arrays must cover every slot.
check_mixed_array_size_required(errors, "filament_mixed_components", comp_strs.size(), slot_count);
check_mixed_array_size_required(errors, "filament_mixed_sublayer_ratios", ratio_strs.size(), slot_count);
// Rule 2: gradient passed (any slot true) → gradient & range arrays must cover every slot.
const bool gradient_specified = mixed_bool_array_was_specified(gradient_flags);
if (gradient_specified) {
check_mixed_array_size_required(errors, "filament_mixed_gradient", gradient_flags.size(), slot_count);
check_mixed_array_size_required(errors, "filament_mixed_gradient_range", gradient_range_strs.size(), slot_count);
}
// Rule 3: curve passed (any non-empty entry) → curve array must cover every slot.
const bool curve_specified = mixed_string_array_was_specified(gradient_curve_strs);
if (curve_specified)
check_mixed_array_size_required(errors, "filament_mixed_gradient_curve", gradient_curve_strs.size(), slot_count);
size_t num_physical = 0;
for (unsigned char v : is_mixed)
if (!v) ++num_physical;
for (size_t i = 0; i < is_mixed.size(); ++i) {
if (!is_mixed[i])
continue;
const std::string slot = "slot " + std::to_string(i + 1);
const std::string comp_str = i < comp_strs.size() ? comp_strs[i] : "";
std::vector<unsigned int> components;
std::string comp_err;
if (!try_parse_mixed_components_strict(comp_str, components, comp_err)) {
append_error(errors, "filament_mixed_components", slot + ": " + comp_err);
continue;
}
for (unsigned int c : components) {
if (c > num_physical) {
append_error(errors, "filament_mixed_components",
slot + ": component " + std::to_string(c)
+ " out of range (max physical filament index is "
+ std::to_string(num_physical) + ")");
break;
}
if (c == i + 1) {
append_error(errors, "filament_mixed_components",
slot + ": cannot reference itself as a component");
break;
}
const size_t idx0 = static_cast<size_t>(c - 1);
if (idx0 < is_mixed.size() && is_mixed[idx0]) {
append_error(errors, "filament_mixed_components",
slot + ": component " + std::to_string(c)
+ " references a mixed filament slot");
break;
}
}
std::string ratio_err;
const std::string ratio_str = i < ratio_strs.size() ? ratio_strs[i] : "";
if (!try_parse_mixed_ratios_strict(ratio_str, components.size(), ratio_err))
append_error(errors, "filament_mixed_sublayer_ratios", slot + ": " + ratio_err);
const bool gradient_on = i < gradient_flags.size() && gradient_flags[i];
if (gradient_on) {
if (components.size() != 2) {
append_error(errors, "filament_mixed_gradient",
slot + ": gradient requires exactly 2 components");
}
if (gradient_specified) {
std::string range_err;
const std::string range_str = i < gradient_range_strs.size() ? gradient_range_strs[i] : "";
if (!validate_gradient_range_strict(range_str, range_err))
append_error(errors, "filament_mixed_gradient_range", slot + ": " + range_err);
}
if (curve_specified) {
const std::string curve_str = i < gradient_curve_strs.size() ? gradient_curve_strs[i] : "";
if (!curve_str.empty() && parse_gradient_curve(curve_str).empty())
append_error(errors, "filament_mixed_gradient_curve",
slot + ": invalid curve (need at least 2 valid control points)");
}
}
}
return errors;
}
} // namespace Slic3r
+164
View File
@@ -0,0 +1,164 @@
#ifndef SLIC3R_FILAMENT_MIXER_HPP
#define SLIC3R_FILAMENT_MIXER_HPP
#include <limits>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>
namespace Slic3r {
// Photoshop-style gradient curve control point in [0,1] x [0,1].
// (x, y) is the anchor position; (m_in, m_out) are optional cubic Hermite tangent
// overrides. NaN means "use the PCHIP-computed default", which is the case for plain
// anchors loaded from old 2-field 3MF projects or freshly added via a quick click.
// A press-and-drag on a curve segment populates m_out of its left anchor and m_in of
// its right anchor so the segment bends without inserting a new anchor.
struct GradientAnchor {
double x = 0.0;
double y = 0.0;
double m_in = std::numeric_limits<double>::quiet_NaN();
double m_out = std::numeric_limits<double>::quiet_NaN();
};
// Sorted list of GradientAnchor; x in [0,1], y in [kGradientMinRatio, kGradientMaxRatio].
// Empty means "no custom curve" (callers should fall back to the linear range).
struct GradientCurve {
std::vector<GradientAnchor> points;
bool empty() const { return points.empty(); }
};
// Reserved blend ratio range. Anchor y values (= component 0's ratio) are constrained
// to this band so the mixed filament never reaches pure 0% / 100% of either physical
// component, which keeps both extruders flowing and avoids degenerate transitions.
// Both the editor and the sampler enforce this clamp.
constexpr double kGradientMinRatio = 0.1;
constexpr double kGradientMaxRatio = 0.9;
// Parse "x0,y0[,m_in0,m_out0]|x1,y1[,m_in1,m_out1]|..." into a GradientCurve.
// (Anchors are pipe-separated; the fields within an anchor are comma-separated.)
// Accepts both the legacy 2-field form (tangents -> NaN) and the new 4-field form
// (empty token or "nan" preserved as NaN). Returns an empty curve when the input is
// empty or unparsable. Points are clamped to [0,1] for (x, y) and re-sorted by x.
GradientCurve parse_gradient_curve(const std::string& s);
// Serialize a GradientCurve back to a string. Emits 4 fields per anchor when any
// tangent override is finite; emits 2 fields when both tangents are NaN so unchanged
// projects stay byte-identical with the legacy format. Returns "" when empty.
std::string serialize_gradient_curve(const GradientCurve& c);
// Sample the curve at t in [0,1] using cubic Hermite with Fritsch-Carlson PCHIP
// default tangents, optionally overridden per anchor via m_in / m_out. Returns the
// clamped end values when t is outside the control point range. Returns 0.5 when the
// curve has fewer than 2 points (a safety fallback; callers should check empty()).
double sample_gradient_curve(const GradientCurve& c, double t);
// Compute Fritsch-Carlson PCHIP default tangents for a sorted-by-x anchor list.
// Result size == pts.size(). Useful for callers that need to know what tangent the
// sampler would synthesize when m_in / m_out are NaN (e.g. the GUI's segment-bend
// interaction that inserts a virtual anchor and reads back the surrounding tangents).
std::vector<double> compute_pchip_default_tangents(const std::vector<GradientAnchor>& pts);
void filament_mixer_lerp(unsigned char r1, unsigned char g1, unsigned char b1,
unsigned char r2, unsigned char g2, unsigned char b2,
float t,
unsigned char* out_r, unsigned char* out_g, unsigned char* out_b);
void filament_mixer_lerp_float(float r1, float g1, float b1,
float r2, float g2, float b2,
float t,
float* out_r, float* out_g, float* out_b);
void filament_mixer_lerp_linear_float(float r1, float g1, float b1,
float r2, float g2, float b2,
float t,
float* out_r, float* out_g, float* out_b);
// Blend two hex colors ("#RRGGBB") by ratio (0.0 ~ 1.0 for color_b).
// Returns "#RRGGBB" string.
std::string blend_color(const std::string& hex_a, const std::string& hex_b, float ratio_b);
// Blend N hex colors by integer weights using polynomial pigment mixing.
// Pairwise accumulation via filament_mixer_lerp. Returns "#RRGGBB".
std::string blend_color_multi(const std::vector<std::string> &hex_colors,
const std::vector<int> &weights);
// Parse comma-separated 1-based component IDs, e.g. "1,3" → {1, 3}.
std::vector<unsigned int> parse_mixed_components(const std::string &str);
// Parse comma-separated ratio values, e.g. "0.7,0.3" → {0.7, 0.3}.
// Returns equal ratios (1/n each) when str is empty or invalid.
// Normalizes so the sum equals 1.0.
std::vector<double> parse_mixed_ratios(const std::string &str, size_t n_components);
// Returns true if any element in is_mixed is true.
// ConfigOptionBools stores values as std::vector<unsigned char>.
bool has_any_mixed_filament(const std::vector<unsigned char> &is_mixed);
// Check which mixed filament slots have broken component references.
// Returns 0-based indices of mixed slots whose components reference
// filaments beyond num_physical (i.e., deleted filaments).
std::vector<size_t> check_mixed_filament_integrity(
const std::vector<unsigned char> &is_mixed,
const std::vector<std::string> &comp_strs,
size_t num_physical);
// Expand mixed filament slots in an extruder list to their physical components.
// Input/output are 0-based indices. Non-mixed slots pass through unchanged.
// Result is sorted and deduplicated.
std::vector<unsigned int> expand_mixed_filaments(
const std::vector<unsigned int> &extruders_0based,
const std::vector<unsigned char> &is_mixed,
const std::vector<std::string> &comp_strs);
// Remap mixed filament component references after a physical filament is deleted.
// del_1based: the 1-based index of the deleted physical filament.
// For each mixed slot:
// - if component == del_1based -> replace with 0 (sentinel for deleted/unselected)
// - if component > del_1based -> decrement by 1
void remap_mixed_components_on_delete(
const std::vector<unsigned char> &is_mixed,
std::vector<std::string> &comp_strs,
unsigned int del_1based);
// Check which mixed filament slots have type-mismatched components.
// filament_types: type strings for physical filaments (0-based, size == num_physical).
// Component IDs in comp_strs are 1-based; the function converts to 0-based to look up types.
// Returns 0-based config indices of mixed slots with mismatched component types.
std::vector<size_t> check_mixed_filament_type_consistency(
const std::vector<unsigned char> &is_mixed,
const std::vector<std::string> &comp_strs,
const std::vector<std::string> &filament_types);
// Expand mixed-slot IDs in geometric unprintable sets to their physical component IDs.
// Each set entry that corresponds to a mixed slot is replaced by the slot's component
// IDs (0-based). Non-mixed entries pass through unchanged.
void expand_mixed_slots_in_unprintables(
std::vector<std::set<int>> &unprintables,
const std::vector<unsigned char> &is_mixed,
const std::vector<std::string> &comp_strs);
// Clear any non-empty gradient-curve slot that parses to fewer than 2 control points.
// Heals per-slot arrays corrupted by the legacy "|" separator collision between
// PresetBundle::export_selections / load_selections (which used "|" as the inter-slot
// delimiter) and serialize_gradient_curve / parse_gradient_curve (which use "|" as the
// intra-slot control-point delimiter). Such a round-trip splits a multi-point curve
// across adjacent slots, leaving single-point entries that fail MakerWorld's strict
// "curve needs >= 2 points" check. Clearing them falls back to the linear range.
void sanitize_mixed_gradient_curve_array(std::vector<std::string>& vals);
// Validate mixed-color (混色) parameters. Returns error messages keyed by option name.
// Slot details are included in the message text (1-based slot index).
std::map<std::string, std::string> validate_mixed_filament_params(
const std::vector<unsigned char> &is_mixed,
const std::vector<std::string> &comp_strs,
const std::vector<std::string> &ratio_strs,
const std::vector<unsigned char> &gradient_flags,
const std::vector<std::string> &gradient_range_strs,
const std::vector<std::string> &gradient_curve_strs);
} // namespace Slic3r
#endif // SLIC3R_FILAMENT_MIXER_HPP
+819
View File
@@ -0,0 +1,819 @@
/*
* FilamentMixer Header-only C++ pigment color mixer
*
* Filament mixer implementation using a degree-4 polynomial regression
* trained to approximate Mixbox behavior (Mean Delta-E ~2.07).
* This library does not include Mixbox source code, binaries, or data files.
*
* Usage:
* #include "FilamentMixerModel.hpp"
*
* unsigned char r, g, b;
* filament_mixer::lerp(0, 33, 133, 252, 211, 0, 0.5f, &r, &g, &b);
* // r=47, g=141, b=56 (blue + yellow → green)
*
* No dependencies beyond the C++ standard library.
*
* MIT License
*
* Copyright (c) 2026 Justin Hayes
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef FILAMENT_MIXER_MODEL_HPP
#define FILAMENT_MIXER_MODEL_HPP
#include <algorithm>
#include <cmath>
#include <cstdint>
namespace filament_mixer {
namespace detail {
// BEGIN AUTO-GENERATED COEFFICIENTS
// Auto-generated by scripts/export_poly_coefficients.py
// Do not edit manually.
// Degree-4 polynomial, 330 features, 7 inputs
static const int POLY_DEGREE = 4;
static const int N_FEATURES = 330;
static const int N_INPUTS = 7;
static const int POWERS[330][7] = {
{0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 0, 0},
{0, 0, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 0, 0, 0},
{0, 0, 0, 0, 1, 0, 0},
{0, 0, 0, 0, 0, 1, 0},
{0, 0, 0, 0, 0, 0, 1},
{2, 0, 0, 0, 0, 0, 0},
{1, 1, 0, 0, 0, 0, 0},
{1, 0, 1, 0, 0, 0, 0},
{1, 0, 0, 1, 0, 0, 0},
{1, 0, 0, 0, 1, 0, 0},
{1, 0, 0, 0, 0, 1, 0},
{1, 0, 0, 0, 0, 0, 1},
{0, 2, 0, 0, 0, 0, 0},
{0, 1, 1, 0, 0, 0, 0},
{0, 1, 0, 1, 0, 0, 0},
{0, 1, 0, 0, 1, 0, 0},
{0, 1, 0, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1},
{0, 0, 2, 0, 0, 0, 0},
{0, 0, 1, 1, 0, 0, 0},
{0, 0, 1, 0, 1, 0, 0},
{0, 0, 1, 0, 0, 1, 0},
{0, 0, 1, 0, 0, 0, 1},
{0, 0, 0, 2, 0, 0, 0},
{0, 0, 0, 1, 1, 0, 0},
{0, 0, 0, 1, 0, 1, 0},
{0, 0, 0, 1, 0, 0, 1},
{0, 0, 0, 0, 2, 0, 0},
{0, 0, 0, 0, 1, 1, 0},
{0, 0, 0, 0, 1, 0, 1},
{0, 0, 0, 0, 0, 2, 0},
{0, 0, 0, 0, 0, 1, 1},
{0, 0, 0, 0, 0, 0, 2},
{3, 0, 0, 0, 0, 0, 0},
{2, 1, 0, 0, 0, 0, 0},
{2, 0, 1, 0, 0, 0, 0},
{2, 0, 0, 1, 0, 0, 0},
{2, 0, 0, 0, 1, 0, 0},
{2, 0, 0, 0, 0, 1, 0},
{2, 0, 0, 0, 0, 0, 1},
{1, 2, 0, 0, 0, 0, 0},
{1, 1, 1, 0, 0, 0, 0},
{1, 1, 0, 1, 0, 0, 0},
{1, 1, 0, 0, 1, 0, 0},
{1, 1, 0, 0, 0, 1, 0},
{1, 1, 0, 0, 0, 0, 1},
{1, 0, 2, 0, 0, 0, 0},
{1, 0, 1, 1, 0, 0, 0},
{1, 0, 1, 0, 1, 0, 0},
{1, 0, 1, 0, 0, 1, 0},
{1, 0, 1, 0, 0, 0, 1},
{1, 0, 0, 2, 0, 0, 0},
{1, 0, 0, 1, 1, 0, 0},
{1, 0, 0, 1, 0, 1, 0},
{1, 0, 0, 1, 0, 0, 1},
{1, 0, 0, 0, 2, 0, 0},
{1, 0, 0, 0, 1, 1, 0},
{1, 0, 0, 0, 1, 0, 1},
{1, 0, 0, 0, 0, 2, 0},
{1, 0, 0, 0, 0, 1, 1},
{1, 0, 0, 0, 0, 0, 2},
{0, 3, 0, 0, 0, 0, 0},
{0, 2, 1, 0, 0, 0, 0},
{0, 2, 0, 1, 0, 0, 0},
{0, 2, 0, 0, 1, 0, 0},
{0, 2, 0, 0, 0, 1, 0},
{0, 2, 0, 0, 0, 0, 1},
{0, 1, 2, 0, 0, 0, 0},
{0, 1, 1, 1, 0, 0, 0},
{0, 1, 1, 0, 1, 0, 0},
{0, 1, 1, 0, 0, 1, 0},
{0, 1, 1, 0, 0, 0, 1},
{0, 1, 0, 2, 0, 0, 0},
{0, 1, 0, 1, 1, 0, 0},
{0, 1, 0, 1, 0, 1, 0},
{0, 1, 0, 1, 0, 0, 1},
{0, 1, 0, 0, 2, 0, 0},
{0, 1, 0, 0, 1, 1, 0},
{0, 1, 0, 0, 1, 0, 1},
{0, 1, 0, 0, 0, 2, 0},
{0, 1, 0, 0, 0, 1, 1},
{0, 1, 0, 0, 0, 0, 2},
{0, 0, 3, 0, 0, 0, 0},
{0, 0, 2, 1, 0, 0, 0},
{0, 0, 2, 0, 1, 0, 0},
{0, 0, 2, 0, 0, 1, 0},
{0, 0, 2, 0, 0, 0, 1},
{0, 0, 1, 2, 0, 0, 0},
{0, 0, 1, 1, 1, 0, 0},
{0, 0, 1, 1, 0, 1, 0},
{0, 0, 1, 1, 0, 0, 1},
{0, 0, 1, 0, 2, 0, 0},
{0, 0, 1, 0, 1, 1, 0},
{0, 0, 1, 0, 1, 0, 1},
{0, 0, 1, 0, 0, 2, 0},
{0, 0, 1, 0, 0, 1, 1},
{0, 0, 1, 0, 0, 0, 2},
{0, 0, 0, 3, 0, 0, 0},
{0, 0, 0, 2, 1, 0, 0},
{0, 0, 0, 2, 0, 1, 0},
{0, 0, 0, 2, 0, 0, 1},
{0, 0, 0, 1, 2, 0, 0},
{0, 0, 0, 1, 1, 1, 0},
{0, 0, 0, 1, 1, 0, 1},
{0, 0, 0, 1, 0, 2, 0},
{0, 0, 0, 1, 0, 1, 1},
{0, 0, 0, 1, 0, 0, 2},
{0, 0, 0, 0, 3, 0, 0},
{0, 0, 0, 0, 2, 1, 0},
{0, 0, 0, 0, 2, 0, 1},
{0, 0, 0, 0, 1, 2, 0},
{0, 0, 0, 0, 1, 1, 1},
{0, 0, 0, 0, 1, 0, 2},
{0, 0, 0, 0, 0, 3, 0},
{0, 0, 0, 0, 0, 2, 1},
{0, 0, 0, 0, 0, 1, 2},
{0, 0, 0, 0, 0, 0, 3},
{4, 0, 0, 0, 0, 0, 0},
{3, 1, 0, 0, 0, 0, 0},
{3, 0, 1, 0, 0, 0, 0},
{3, 0, 0, 1, 0, 0, 0},
{3, 0, 0, 0, 1, 0, 0},
{3, 0, 0, 0, 0, 1, 0},
{3, 0, 0, 0, 0, 0, 1},
{2, 2, 0, 0, 0, 0, 0},
{2, 1, 1, 0, 0, 0, 0},
{2, 1, 0, 1, 0, 0, 0},
{2, 1, 0, 0, 1, 0, 0},
{2, 1, 0, 0, 0, 1, 0},
{2, 1, 0, 0, 0, 0, 1},
{2, 0, 2, 0, 0, 0, 0},
{2, 0, 1, 1, 0, 0, 0},
{2, 0, 1, 0, 1, 0, 0},
{2, 0, 1, 0, 0, 1, 0},
{2, 0, 1, 0, 0, 0, 1},
{2, 0, 0, 2, 0, 0, 0},
{2, 0, 0, 1, 1, 0, 0},
{2, 0, 0, 1, 0, 1, 0},
{2, 0, 0, 1, 0, 0, 1},
{2, 0, 0, 0, 2, 0, 0},
{2, 0, 0, 0, 1, 1, 0},
{2, 0, 0, 0, 1, 0, 1},
{2, 0, 0, 0, 0, 2, 0},
{2, 0, 0, 0, 0, 1, 1},
{2, 0, 0, 0, 0, 0, 2},
{1, 3, 0, 0, 0, 0, 0},
{1, 2, 1, 0, 0, 0, 0},
{1, 2, 0, 1, 0, 0, 0},
{1, 2, 0, 0, 1, 0, 0},
{1, 2, 0, 0, 0, 1, 0},
{1, 2, 0, 0, 0, 0, 1},
{1, 1, 2, 0, 0, 0, 0},
{1, 1, 1, 1, 0, 0, 0},
{1, 1, 1, 0, 1, 0, 0},
{1, 1, 1, 0, 0, 1, 0},
{1, 1, 1, 0, 0, 0, 1},
{1, 1, 0, 2, 0, 0, 0},
{1, 1, 0, 1, 1, 0, 0},
{1, 1, 0, 1, 0, 1, 0},
{1, 1, 0, 1, 0, 0, 1},
{1, 1, 0, 0, 2, 0, 0},
{1, 1, 0, 0, 1, 1, 0},
{1, 1, 0, 0, 1, 0, 1},
{1, 1, 0, 0, 0, 2, 0},
{1, 1, 0, 0, 0, 1, 1},
{1, 1, 0, 0, 0, 0, 2},
{1, 0, 3, 0, 0, 0, 0},
{1, 0, 2, 1, 0, 0, 0},
{1, 0, 2, 0, 1, 0, 0},
{1, 0, 2, 0, 0, 1, 0},
{1, 0, 2, 0, 0, 0, 1},
{1, 0, 1, 2, 0, 0, 0},
{1, 0, 1, 1, 1, 0, 0},
{1, 0, 1, 1, 0, 1, 0},
{1, 0, 1, 1, 0, 0, 1},
{1, 0, 1, 0, 2, 0, 0},
{1, 0, 1, 0, 1, 1, 0},
{1, 0, 1, 0, 1, 0, 1},
{1, 0, 1, 0, 0, 2, 0},
{1, 0, 1, 0, 0, 1, 1},
{1, 0, 1, 0, 0, 0, 2},
{1, 0, 0, 3, 0, 0, 0},
{1, 0, 0, 2, 1, 0, 0},
{1, 0, 0, 2, 0, 1, 0},
{1, 0, 0, 2, 0, 0, 1},
{1, 0, 0, 1, 2, 0, 0},
{1, 0, 0, 1, 1, 1, 0},
{1, 0, 0, 1, 1, 0, 1},
{1, 0, 0, 1, 0, 2, 0},
{1, 0, 0, 1, 0, 1, 1},
{1, 0, 0, 1, 0, 0, 2},
{1, 0, 0, 0, 3, 0, 0},
{1, 0, 0, 0, 2, 1, 0},
{1, 0, 0, 0, 2, 0, 1},
{1, 0, 0, 0, 1, 2, 0},
{1, 0, 0, 0, 1, 1, 1},
{1, 0, 0, 0, 1, 0, 2},
{1, 0, 0, 0, 0, 3, 0},
{1, 0, 0, 0, 0, 2, 1},
{1, 0, 0, 0, 0, 1, 2},
{1, 0, 0, 0, 0, 0, 3},
{0, 4, 0, 0, 0, 0, 0},
{0, 3, 1, 0, 0, 0, 0},
{0, 3, 0, 1, 0, 0, 0},
{0, 3, 0, 0, 1, 0, 0},
{0, 3, 0, 0, 0, 1, 0},
{0, 3, 0, 0, 0, 0, 1},
{0, 2, 2, 0, 0, 0, 0},
{0, 2, 1, 1, 0, 0, 0},
{0, 2, 1, 0, 1, 0, 0},
{0, 2, 1, 0, 0, 1, 0},
{0, 2, 1, 0, 0, 0, 1},
{0, 2, 0, 2, 0, 0, 0},
{0, 2, 0, 1, 1, 0, 0},
{0, 2, 0, 1, 0, 1, 0},
{0, 2, 0, 1, 0, 0, 1},
{0, 2, 0, 0, 2, 0, 0},
{0, 2, 0, 0, 1, 1, 0},
{0, 2, 0, 0, 1, 0, 1},
{0, 2, 0, 0, 0, 2, 0},
{0, 2, 0, 0, 0, 1, 1},
{0, 2, 0, 0, 0, 0, 2},
{0, 1, 3, 0, 0, 0, 0},
{0, 1, 2, 1, 0, 0, 0},
{0, 1, 2, 0, 1, 0, 0},
{0, 1, 2, 0, 0, 1, 0},
{0, 1, 2, 0, 0, 0, 1},
{0, 1, 1, 2, 0, 0, 0},
{0, 1, 1, 1, 1, 0, 0},
{0, 1, 1, 1, 0, 1, 0},
{0, 1, 1, 1, 0, 0, 1},
{0, 1, 1, 0, 2, 0, 0},
{0, 1, 1, 0, 1, 1, 0},
{0, 1, 1, 0, 1, 0, 1},
{0, 1, 1, 0, 0, 2, 0},
{0, 1, 1, 0, 0, 1, 1},
{0, 1, 1, 0, 0, 0, 2},
{0, 1, 0, 3, 0, 0, 0},
{0, 1, 0, 2, 1, 0, 0},
{0, 1, 0, 2, 0, 1, 0},
{0, 1, 0, 2, 0, 0, 1},
{0, 1, 0, 1, 2, 0, 0},
{0, 1, 0, 1, 1, 1, 0},
{0, 1, 0, 1, 1, 0, 1},
{0, 1, 0, 1, 0, 2, 0},
{0, 1, 0, 1, 0, 1, 1},
{0, 1, 0, 1, 0, 0, 2},
{0, 1, 0, 0, 3, 0, 0},
{0, 1, 0, 0, 2, 1, 0},
{0, 1, 0, 0, 2, 0, 1},
{0, 1, 0, 0, 1, 2, 0},
{0, 1, 0, 0, 1, 1, 1},
{0, 1, 0, 0, 1, 0, 2},
{0, 1, 0, 0, 0, 3, 0},
{0, 1, 0, 0, 0, 2, 1},
{0, 1, 0, 0, 0, 1, 2},
{0, 1, 0, 0, 0, 0, 3},
{0, 0, 4, 0, 0, 0, 0},
{0, 0, 3, 1, 0, 0, 0},
{0, 0, 3, 0, 1, 0, 0},
{0, 0, 3, 0, 0, 1, 0},
{0, 0, 3, 0, 0, 0, 1},
{0, 0, 2, 2, 0, 0, 0},
{0, 0, 2, 1, 1, 0, 0},
{0, 0, 2, 1, 0, 1, 0},
{0, 0, 2, 1, 0, 0, 1},
{0, 0, 2, 0, 2, 0, 0},
{0, 0, 2, 0, 1, 1, 0},
{0, 0, 2, 0, 1, 0, 1},
{0, 0, 2, 0, 0, 2, 0},
{0, 0, 2, 0, 0, 1, 1},
{0, 0, 2, 0, 0, 0, 2},
{0, 0, 1, 3, 0, 0, 0},
{0, 0, 1, 2, 1, 0, 0},
{0, 0, 1, 2, 0, 1, 0},
{0, 0, 1, 2, 0, 0, 1},
{0, 0, 1, 1, 2, 0, 0},
{0, 0, 1, 1, 1, 1, 0},
{0, 0, 1, 1, 1, 0, 1},
{0, 0, 1, 1, 0, 2, 0},
{0, 0, 1, 1, 0, 1, 1},
{0, 0, 1, 1, 0, 0, 2},
{0, 0, 1, 0, 3, 0, 0},
{0, 0, 1, 0, 2, 1, 0},
{0, 0, 1, 0, 2, 0, 1},
{0, 0, 1, 0, 1, 2, 0},
{0, 0, 1, 0, 1, 1, 1},
{0, 0, 1, 0, 1, 0, 2},
{0, 0, 1, 0, 0, 3, 0},
{0, 0, 1, 0, 0, 2, 1},
{0, 0, 1, 0, 0, 1, 2},
{0, 0, 1, 0, 0, 0, 3},
{0, 0, 0, 4, 0, 0, 0},
{0, 0, 0, 3, 1, 0, 0},
{0, 0, 0, 3, 0, 1, 0},
{0, 0, 0, 3, 0, 0, 1},
{0, 0, 0, 2, 2, 0, 0},
{0, 0, 0, 2, 1, 1, 0},
{0, 0, 0, 2, 1, 0, 1},
{0, 0, 0, 2, 0, 2, 0},
{0, 0, 0, 2, 0, 1, 1},
{0, 0, 0, 2, 0, 0, 2},
{0, 0, 0, 1, 3, 0, 0},
{0, 0, 0, 1, 2, 1, 0},
{0, 0, 0, 1, 2, 0, 1},
{0, 0, 0, 1, 1, 2, 0},
{0, 0, 0, 1, 1, 1, 1},
{0, 0, 0, 1, 1, 0, 2},
{0, 0, 0, 1, 0, 3, 0},
{0, 0, 0, 1, 0, 2, 1},
{0, 0, 0, 1, 0, 1, 2},
{0, 0, 0, 1, 0, 0, 3},
{0, 0, 0, 0, 4, 0, 0},
{0, 0, 0, 0, 3, 1, 0},
{0, 0, 0, 0, 3, 0, 1},
{0, 0, 0, 0, 2, 2, 0},
{0, 0, 0, 0, 2, 1, 1},
{0, 0, 0, 0, 2, 0, 2},
{0, 0, 0, 0, 1, 3, 0},
{0, 0, 0, 0, 1, 2, 1},
{0, 0, 0, 0, 1, 1, 2},
{0, 0, 0, 0, 1, 0, 3},
{0, 0, 0, 0, 0, 4, 0},
{0, 0, 0, 0, 0, 3, 1},
{0, 0, 0, 0, 0, 2, 2},
{0, 0, 0, 0, 0, 1, 3},
{0, 0, 0, 0, 0, 0, 4}
};
static const double COEF[330][3] = {
{8.70954844857314666e-12, 1.27926950848359881e-09, -2.06865474316332923e-09},
{1.05783308354771544e+00, -8.02119209663359686e-03, -7.88705651445470723e-02},
{1.35905954452774837e-02, 8.71267975138422468e-01, 1.04898760410704936e-01},
{-4.16452026099768252e-02, 1.75465381596434100e-02, 1.00224594702931546e+00},
{4.50321316661211821e-02, -7.11409155427628892e-02, 3.91232300778902690e-03},
{1.76675507851922452e-02, -1.32709276116036640e-01, 6.36935270589509828e-02},
{-5.23434830565911030e-02, 3.77681739012521722e-02, -2.08691145087504179e-02},
{-2.33722556520224792e-03, -1.57542611462692145e-03, -3.05158628452478807e-03},
{-8.87678609044812990e-04, 3.83194388837734693e-04, 1.37779212442523083e-03},
{-2.11519042076831979e-03, 5.82337362515735358e-04, 2.24055108941204821e-04},
{4.61545125563611917e-04, 7.72869451707915893e-04, -1.10800630143346882e-03},
{1.05937484157345879e-03, -3.14448681732842211e-04, -1.75129182446198098e-03},
{1.49045689016363055e-03, -2.09220860101674106e-04, 5.93100338908187697e-04},
{-3.51246656293852696e-04, -8.20743017485394289e-04, 5.71854064480802862e-04},
{-9.18204643629581319e-01, -2.27788122702773155e-01, 6.39980793022790623e-02},
{9.24243491377523679e-05, 7.32841332381495400e-04, -1.55219718415109450e-03},
{7.13695056804217989e-04, -8.46467621879685712e-05, 6.50202947442505750e-04},
{1.66640864747485983e-03, -1.24492362771216523e-04, 2.68236502346156410e-04},
{-7.20253644860527516e-04, 7.81434220384157334e-04, 1.12661089007361367e-03},
{-6.83033334365238206e-05, 7.27742627159490762e-04, -1.78048843835204584e-03},
{-3.13431571993316588e-02, -8.57604034845650287e-01, -2.57225920656276863e-01},
{-6.47867200595898341e-05, -1.16688982572457655e-03, 1.14174511750260031e-03},
{-5.00713925613324338e-04, -6.87598082111323477e-04, 6.20598069880440176e-04},
{-8.56716727659588957e-05, 9.74478786593559361e-04, -1.65892838405139512e-03},
{6.53468478750158263e-04, 7.51662000672516676e-04, -6.73196326298856570e-04},
{-4.42539011000103941e-02, -2.01965359697350230e-02, -9.94663493761314355e-01},
{-7.39107395392403087e-04, 5.28870828612476996e-04, 1.00947183860234540e-03},
{-2.06577300933763214e-03, 9.60215813758718011e-04, -3.27993888180819421e-04},
{3.47783280638377555e-04, 8.41824316850705743e-04, -8.87458944147930993e-04},
{1.20960551709587905e+00, -7.07660818059813873e-02, -8.56332806008946491e-03},
{2.11116509318935269e-04, 7.68490846994171776e-04, -1.63228995491542417e-03},
{6.47698075356516103e-04, -4.20589129268072884e-04, 1.18354001300614896e-03},
{-2.78795945253848716e-02, 1.22199201000304547e+00, -2.07383075858847743e-01},
{-5.32457386680677347e-05, -9.58027320315790677e-04, 9.89667309649038679e-04},
{-9.03932426306289782e-02, -4.00969232187064692e-02, 1.26285611182120072e+00},
{-2.19453630740322871e-03, -1.21893190049422620e-03, -1.92293368093085417e-03},
{1.72950845415964505e-06, -8.93952511560151819e-09, -6.14874900641340649e-06},
{8.02644554976326974e-06, -6.42543741723487294e-06, -6.07103419227907060e-06},
{3.20307552755319525e-06, -4.83533743093466500e-06, 9.13563764113473065e-07},
{-2.18105804067510178e-06, 6.19595552598436322e-07, 5.21392855381760945e-06},
{-2.43310123604345563e-06, 2.17201813434465818e-06, 1.94098874242362718e-07},
{-1.56293672065252465e-06, 3.95256011818110372e-06, 1.68792962079201969e-06},
{-1.37567295252127852e-03, 3.59746071987262106e-04, 7.38927139000157259e-05},
{4.27822004137219658e-06, -8.80187479967658548e-07, 2.29453131891411977e-06},
{7.68758937964332534e-06, 2.40909410585557829e-07, 4.69351234070854509e-06},
{-2.87166709944317033e-06, 7.60223902901142716e-07, 4.57864913314467992e-06},
{-4.01295140267654560e-06, 2.65929275888376483e-06, -2.36575067819565221e-06},
{2.32693030513910805e-07, 2.28814396769890308e-06, 1.83526107699893970e-07},
{-2.18213927011287265e-03, 1.65013083920367864e-03, 2.31992998847323087e-04},
{-7.70829764693697905e-06, 4.23888841240673345e-07, 7.30018322002944087e-06},
{-1.23111329452911533e-06, 1.50076529718910084e-06, -1.91139744928209288e-06},
{-1.68872756433485760e-06, 1.03254236824697979e-06, -1.72081108163607555e-06},
{1.64276928199709460e-06, -4.96350219553231067e-07, -1.46349385185670297e-06},
{1.12731767057843682e-03, 5.03104281148445223e-04, 1.36398977654308994e-03},
{-1.05449609518089293e-06, -4.06952115309007489e-07, 3.53062441379482783e-06},
{-1.98745923822574166e-06, 4.98021943693208180e-07, 3.92645061370218429e-06},
{-1.55569377977005097e-07, -4.00262856484093037e-07, -2.49609122397048688e-06},
{2.18005022830924673e-03, -4.10275057064835439e-05, -2.59776311836759947e-04},
{5.41337439827552225e-07, -1.88603932528607146e-06, -2.06428606152470051e-06},
{-6.03243799807140491e-06, -3.75067864464502022e-06, -3.05702776851046742e-06},
{2.30038011634901016e-03, -1.32581161861259635e-03, -1.07680096899188406e-03},
{4.46773877910556887e-06, 1.85008408528524772e-08, -2.72851357570281713e-06},
{-1.49177636513049289e-03, -1.91426739654176659e-04, -1.71206384332753194e-03},
{2.31661325589237743e-02, 2.26540538563063554e-01, 5.42330337046266139e-02},
{-1.40563059963100256e-06, -4.50551806294901061e-06, 8.87542894832671347e-06},
{-1.66780916452391459e-06, 4.12065434881171526e-06, -3.55865035776836702e-06},
{2.71536622051954390e-07, -3.08564858926584692e-06, -1.52164363662402047e-06},
{2.66659632027280158e-06, -1.19436686895073481e-06, -3.25738306279285683e-06},
{-1.43666282346327501e-06, -2.51923473623639690e-06, 5.21205120344175876e-06},
{2.82954522469612199e-04, -1.59147454710008968e-03, 1.27685773978167098e-03},
{-3.99471240294241303e-06, 9.97323772325767188e-08, -5.28196823261495307e-06},
{-6.39858432699424995e-06, -4.59897864440506933e-06, -2.39736149785715891e-06},
{2.89457420106498109e-06, -3.10427512149489757e-06, 9.75553221437691631e-07},
{-8.96518259720091581e-07, -5.53996694461914366e-06, 1.03733964032237669e-05},
{8.82130497168875905e-04, -2.33618402105562365e-03, 1.35100410641244379e-03},
{-2.14088521029685841e-06, 2.59005410360388117e-06, -9.78713171504927426e-08},
{-4.50668337071552516e-06, 3.58808570076458002e-06, -1.56159349007541082e-06},
{-1.52345101244247272e-06, 2.21066768791959578e-06, -2.19555898547246775e-06},
{2.07334042074768356e-03, -1.56333498489329517e-03, -5.53762940364141767e-04},
{2.22151748134440108e-06, -4.74729938900429749e-07, -3.46744150304684889e-06},
{2.95389009221172505e-06, -2.96312023445686329e-06, -9.00385068308695580e-07},
{-6.47780848348620771e-04, 2.38772263398574292e-03, -8.93908589731968019e-04},
{9.69501567645025819e-07, 2.41432205872957328e-06, 5.56908291093893837e-07},
{-6.33392066185247586e-04, 2.38613844267241120e-03, -1.05383725637261472e-03},
{6.76250135616376785e-02, -5.57799579151454852e-02, 1.83393652374666566e-01},
{3.53986894266120067e-06, 5.92996717102502093e-06, -7.32378536156402804e-06},
{5.69667193362453916e-06, 1.20219201908705218e-06, -4.56663805956276925e-06},
{7.11494218295222192e-07, 2.93069858359131137e-06, 1.23210839732268429e-07},
{-3.41917893741799928e-06, -1.47435291776966751e-06, 1.07397354370819542e-06},
{7.30931882734254710e-04, 1.15433149094644884e-03, -2.40026982569019722e-03},
{-1.22780859907432871e-06, 2.29287908084027789e-06, 1.84270754640877832e-06},
{7.71579140080615178e-07, 2.92378122615943208e-06, -1.91800935486416413e-07},
{-3.76107279903559188e-07, -1.83159743461489867e-06, 8.17089655984204466e-07},
{-1.10830882430058061e-03, -5.10908079549339251e-04, -1.77835176235151705e-03},
{-1.26839781743699406e-06, -2.86942252006448415e-06, 4.47464983859263005e-06},
{-1.44518716284694482e-06, -7.03360635528004451e-06, 1.04898109513258675e-05},
{-4.98687888007460470e-04, 1.86990180752567262e-03, -1.24341018156770089e-03},
{-2.90479801332704790e-06, -9.24272269110706229e-07, 7.56354222045119151e-07},
{-1.16451534008294149e-03, -2.34216801827852273e-03, 4.91479264672447288e-03},
{-7.70970926241258958e-02, 9.35855573900774423e-02, 1.50623807158846906e-01},
{1.14039905307547484e-06, -1.80664235182388840e-07, -5.15527441317074897e-06},
{7.50559587697416375e-06, -6.23982034686780714e-06, -5.01245198064126721e-06},
{2.37840954889385892e-06, -4.15663063190341991e-06, 1.93118829429697603e-06},
{-1.54903048110950777e-03, 2.65832194444263125e-04, 5.34401520444913940e-04},
{4.00040634507183718e-06, -2.43965474694277443e-06, 2.88683251413283937e-06},
{7.72301916160400559e-06, -9.54300275625495457e-07, 5.50777546561020959e-06},
{-2.28103126593574368e-03, 1.02658341009706066e-03, 1.22010567464172614e-03},
{-6.32818026002207601e-06, 9.83088209200334157e-07, 5.24316808343458507e-06},
{1.37175660779395581e-03, 4.01188715721313943e-04, 7.59370199245276625e-04},
{-3.33184694847917573e-01, 7.82846225823195241e-02, -9.94270054263078074e-02},
{-1.70108770909324636e-06, -5.10749831734438279e-06, 9.80267482880020635e-06},
{-1.79301365419055891e-06, 4.44839673308561508e-06, -3.83837422072638712e-06},
{1.71911692904483371e-04, -1.56077480341044431e-03, 1.30725115579017584e-03},
{-3.55763938679129477e-06, 1.20558966207589408e-06, -5.94340114624253291e-06},
{1.02325453537648178e-03, -1.52640960762801372e-03, 3.10973117856692537e-04},
{3.81842873295820109e-03, -3.02114884453467680e-01, 2.78264587142456665e-01},
{3.46123498726202961e-06, 5.05929187103208375e-06, -6.85764673719752027e-06},
{4.47228353489932293e-04, 9.60672217798415784e-04, -2.19382758010531077e-03},
{2.22711833124298791e-01, -4.14141995162802465e-02, -4.27998216564745015e-01},
{-1.78271151817048783e-03, -9.81039111371464307e-04, -1.37513011841553174e-03},
{3.35305394560947434e-10, -1.26710751613412498e-09, 3.54248685940916630e-09},
{-9.26917423371698135e-09, 6.21190912597491263e-09, 1.86942252233812667e-08},
{-1.56687696151180944e-09, -5.44315731376698864e-09, 1.93822974337010123e-09},
{7.52897716393974292e-10, -3.48923168136394679e-10, -5.94217786087369859e-10},
{2.52116855170569920e-10, -2.48216903975251313e-09, 1.01699001303634518e-09},
{3.72215577457146729e-09, 4.51910314724912610e-10, -6.15361639422218332e-09},
{-2.62088816666700142e-07, 3.23631086683010168e-07, 8.85302852722882894e-07},
{-1.30537319842360944e-08, 1.46808588619151692e-08, 2.67574040702101001e-09},
{-1.23991327621864045e-08, 2.61298349069072344e-08, -4.58919307373337193e-09},
{5.03079244928983371e-09, -6.73783119575777079e-10, -1.13935871848269699e-08},
{9.09065785148488459e-09, -1.04304054004966673e-08, -3.23123813816827976e-09},
{9.55627910137479830e-10, -1.41129563591135820e-08, -1.75594400131373618e-09},
{-1.05549669436946769e-07, 8.47284096194811896e-08, 6.70761880091491625e-07},
{-5.92079330008488114e-10, 6.31702118392141188e-09, -4.51534448719925763e-09},
{-1.04033970327321867e-09, 4.67775485013532943e-09, 2.79348504744758586e-09},
{5.38758108958869997e-09, -9.55380699552144108e-09, 6.16488249338686956e-11},
{1.12057409185073453e-09, -3.00645183748393663e-09, -2.14940637510707688e-09},
{-6.27004681934967278e-07, 8.59159786402940127e-07, 2.73192537668387470e-07},
{7.36784189214745311e-10, -8.12761968838060511e-10, -2.43226564583531868e-09},
{1.25546123497244366e-09, -6.98609614602219153e-10, -5.29894812750786315e-09},
{-8.88351475714088679e-10, 1.37132565025677167e-09, 1.92497813869541012e-09},
{6.10992637326349119e-07, -6.13496367368217277e-07, -2.19901889726877020e-06},
{-8.59090437677068053e-11, 2.72772732179404898e-09, 1.54554039011323141e-09},
{-4.58798915525804318e-10, 4.54384851966693759e-09, 3.63189350816028877e-09},
{9.93115786933340683e-08, 1.63700862245048928e-07, -1.71397937400244449e-07},
{-1.62985361318312982e-09, -3.10762126448649312e-09, 1.76193495557419588e-09},
{6.27207737564569601e-07, -1.49343052365004934e-06, 8.16168870109573730e-08},
{1.42518738380244172e-03, -3.47531891583186285e-04, -2.98661838800559913e-04},
{8.98157254125564464e-09, -8.24242643235328920e-09, -5.34769730234363472e-09},
{-2.17776999489327494e-08, -4.47141107473569832e-09, -1.10218517090920898e-08},
{3.19614509858290319e-09, -3.32861183754973311e-09, 9.92016746526047655e-11},
{-2.91660393059167689e-09, 5.59829099744391101e-09, 1.70080685646389895e-09},
{1.22479524179014421e-09, 9.20737683318684219e-09, -1.10618757209746121e-10},
{7.70594587548882257e-09, -1.33267446898667659e-06, 4.52812675308736368e-07},
{9.46080642993951670e-09, -1.95483249032513129e-08, -1.23592694620255905e-08},
{-2.02330094345448686e-09, 1.18198534293512125e-10, 2.34746776184291406e-09},
{4.00839940406516604e-09, -4.80716730311137042e-09, 5.25802457129742606e-09},
{-2.53115202408782380e-09, 2.05563177591017165e-10, 5.46003270374129102e-09},
{3.24841319972028232e-08, -1.24284705839720552e-06, 4.97326549863015555e-07},
{1.37729661009444726e-09, -1.67903983772088594e-09, -5.62083748989472554e-09},
{-3.53256937590806785e-10, 4.49320892992322030e-09, -4.02300486673778934e-09},
{2.48976475547557641e-09, -6.97256366533061112e-09, 1.43185084622299286e-09},
{-4.38617299338556199e-09, 9.45081248826811111e-08, -2.91197460585562728e-07},
{3.24429103026879773e-09, -1.71647943601749287e-09, 2.71076100455402980e-09},
{3.86933235105302309e-09, -2.82628156988984358e-09, 8.24455756442965537e-09},
{-7.46614068323353530e-07, 1.27696340529665289e-06, 6.88413034833322557e-07},
{-5.78118683480788320e-09, 1.34319005917760137e-09, -1.15898873831454807e-09},
{4.42686972671260670e-07, 6.41810588767341775e-07, -1.16058405342719939e-08},
{2.24399192788231686e-03, -1.35129336477888174e-03, -7.39944244498236844e-04},
{7.47869199901884940e-09, -2.68762612165573955e-09, -7.41584788022109365e-09},
{1.80867308283150230e-09, -2.21500551234043996e-09, 1.86995768869380186e-09},
{-5.05514829302056157e-09, 4.74048706539109688e-09, 2.52998993977016085e-09},
{1.32441967115592973e-09, 5.70339246663831290e-09, 7.13448300437846683e-10},
{1.19767475292940212e-06, 6.72445227582811568e-07, -1.97500319605841551e-06},
{-1.70612399208458498e-09, 1.07145120553653328e-09, 1.73225882249550267e-09},
{1.15369127445807962e-09, -5.80362996549510513e-09, 9.33515653667171819e-10},
{3.38692740520230018e-09, 3.72531013675958533e-09, -3.18062756687886861e-09},
{1.14787653780236421e-06, -1.84917201319622368e-06, -2.44834286920736499e-07},
{1.45558928799083276e-09, 1.12720083267348059e-09, 9.00940544390493869e-10},
{2.09654001104286891e-09, 4.92913422578400429e-09, 3.04938074791039071e-10},
{3.54033623213741155e-07, 1.07259516691213860e-06, -6.03027205987524684e-07},
{-2.72038239157446071e-09, -1.60070143945256760e-09, 6.03853855807301443e-10},
{-2.03235662485238069e-06, -1.03151962834260348e-06, 1.99637918628457062e-06},
{-1.26261175077493210e-03, -4.98503988506484859e-04, -1.03875859619143593e-03},
{6.43182729298530376e-10, 8.01776645076301975e-10, -1.83589794755523172e-09},
{4.01805119037978997e-09, -5.63673552278487477e-10, -1.09102650663883693e-08},
{-1.48648961195707585e-09, 5.01067861508053269e-09, 2.99132781045319263e-09},
{-8.91404754824534629e-07, 7.49163968581634775e-07, 2.12542215183124383e-06},
{2.38642574451608525e-09, -3.47605810802065207e-09, 3.86935566920598717e-10},
{-2.80031986488182838e-09, -4.25160427697246490e-11, 2.24182921879090280e-09},
{-1.26991357818351247e-07, -1.45348284568834647e-07, 5.68792533226815389e-07},
{1.39227229745131353e-09, -1.84849578699353145e-09, 2.24967258190267305e-09},
{-1.15462500328497586e-06, 1.84347590761761086e-06, 3.64918716654494962e-07},
{-2.09357112083411985e-03, 1.60820400301404873e-05, 2.27418117008655948e-04},
{-1.04484803378768198e-08, 4.86043558178828050e-09, 2.00996588123336650e-09},
{1.44040971927772432e-08, 1.42223015309195233e-09, 1.99778974613318283e-09},
{-1.62414574166394599e-07, -1.31976785339561840e-06, 4.43918084507000099e-07},
{3.73061943836905385e-09, 1.00036822436866402e-08, -1.05450977117005351e-09},
{-2.06551932971539565e-07, -9.72167971235462190e-07, 4.28861904300768815e-07},
{-2.16051814014425313e-03, 1.48780488507118812e-03, 7.79940397419977911e-04},
{-4.80544204428667854e-09, -1.09870773590259319e-09, 6.58876991984844174e-09},
{1.31575045692056136e-06, 4.32430764481131318e-07, -1.55255090541518703e-06},
{1.28823975640215602e-03, 4.04521283440268135e-04, 1.76186984141882253e-03},
{-1.09767251093991436e-01, -4.94112205838347640e-02, -5.43102978164306804e-02},
{7.93691223854864347e-10, 1.54639511196208446e-08, -1.71518303448969789e-08},
{2.56523843833456056e-09, -2.31047392329486456e-09, -4.29758133398648601e-09},
{-9.87725901069325118e-09, 4.28127375218245732e-09, 2.02888056355376989e-09},
{3.21762172461603768e-10, -5.82937505211322815e-09, 3.88293127512318037e-09},
{1.63250610252241302e-09, -7.02161705168347083e-09, 3.46592492032893329e-09},
{-1.44272117683086343e-07, -4.40408510988914148e-07, 5.92746408872857344e-07},
{2.71961467235293242e-09, -1.47466668633244868e-08, 2.89637452632884873e-08},
{1.47637712476396399e-08, 1.16406781783262581e-09, 2.04904540557215853e-09},
{-5.53709807865621073e-09, 7.05512286092169205e-09, 1.56159114805820565e-09},
{5.29268649740455288e-09, 2.10616986628942016e-08, -3.03219004488264332e-08},
{1.79978890693655025e-07, 7.95085399132693105e-07, -4.78366567607801940e-07},
{-4.03847393894152251e-10, 2.90357085597214848e-09, 1.12992165623992946e-09},
{2.99031871486832301e-09, -1.37951879780606745e-09, 2.41048263988075107e-09},
{1.26882357398550027e-09, 1.30631467101793852e-09, 7.99574240151201820e-10},
{-1.41169562567489137e-08, 1.27148955713198356e-06, -2.89386439707162157e-07},
{-2.68794415198003733e-09, 8.73673404455654889e-10, 2.89557382238125882e-09},
{-4.90264437380538709e-09, 1.89207244316591527e-09, 2.25393465003165261e-09},
{-3.58274654665979853e-08, 2.91386646529383231e-07, -4.98477764412919022e-08},
{1.65722165851311942e-09, -1.11673743863338615e-09, -4.14131162695952071e-09},
{-1.47751280626939874e-07, -2.41471865000848773e-07, -8.53552350049691100e-07},
{-2.24352957583577790e-04, 1.60900273524284708e-03, -1.32260753549593617e-03},
{2.05497643901431104e-09, 1.38702982710459111e-08, -3.09887516689033582e-09},
{3.39770491949997755e-09, 9.41613393506957053e-09, -7.09844738544518350e-10},
{7.86209687630989862e-10, 1.93556837224662104e-10, -6.58630930350234678e-09},
{-6.86841181152253455e-10, -5.57194149153339424e-09, 1.41214109156129197e-09},
{2.59516074158083754e-07, 1.30703181255419770e-06, -4.02454784192984860e-07},
{-5.79425202262839889e-10, 4.05071760856134944e-09, 3.02384985106929349e-09},
{4.00677924866643664e-09, -2.25614611715219127e-09, 7.52819043214891792e-09},
{2.34003759425061020e-09, 5.27462258592681366e-09, -2.05723854618256041e-10},
{2.29340174767722615e-07, 1.05507868574435809e-06, -4.45904844964539748e-07},
{-3.91634245866523401e-09, 1.07849931763048801e-09, 1.85542686770290288e-09},
{-6.62166513287765213e-09, 3.86355018811013196e-09, -1.87861701195224384e-09},
{1.32112240848469842e-07, 4.39339645861430705e-08, -1.59384598983486336e-06},
{2.02488462108796341e-09, -1.48427112267590644e-09, -4.32055485832805175e-09},
{-4.27701540045566375e-07, -1.46229443391283215e-06, -2.38186369433401879e-07},
{-9.86744509368740232e-04, 1.91104095070606826e-03, -8.17774843405986713e-04},
{2.06891823117949514e-10, -2.64060942556376688e-09, 1.86419366055012858e-09},
{8.33785634979378187e-09, -1.00697171434571686e-08, -2.84106664583116952e-09},
{5.07057938692323518e-09, -9.56246298811080919e-09, -6.33399999117045809e-11},
{-6.78808357162941078e-08, -2.21612941845184680e-07, 9.42031624998063144e-08},
{-3.04300065007145903e-09, 5.64120231083542478e-09, 1.65718606892628628e-09},
{3.76240642807612602e-09, -4.58941407446844529e-09, 5.06162500801821125e-09},
{7.25149885354159363e-07, -1.18149759075966698e-06, -6.82406347277120240e-07},
{-4.84358128605144600e-09, 4.56893046833772853e-09, 2.67044331092591847e-09},
{-2.54939737986958903e-07, -1.06106228658746360e-06, 5.04013386790069795e-07},
{-2.17097468872509735e-03, 1.41624400187313607e-03, 8.11305605779899562e-04},
{2.24635331169675823e-10, -6.02144184513875302e-09, 4.15827878380570226e-09},
{-4.55408258326350790e-09, 6.20319154376325343e-09, 2.08760821823750220e-09},
{2.10871853867367065e-07, -4.29346688506603014e-07, 1.15683623843482186e-07},
{1.00732072683129559e-09, 3.88267751283422058e-11, -6.73798626615873530e-09},
{5.34506627847264326e-09, -8.01262819982717645e-08, 1.60888846226225901e-06},
{5.83419066552946048e-04, -2.36474094848551555e-03, 8.79373865688287898e-04},
{-4.85158746510450101e-10, -6.78789624508624456e-09, 4.95385649168511577e-09},
{3.47485142271342085e-07, 5.60944792101468470e-07, -4.35887910682497548e-07},
{5.75824910919892421e-04, -2.18618554413632388e-03, 1.22736498224538170e-03},
{-2.51838883195707221e-02, -8.23487774284355212e-02, 3.33658831723806573e-02},
{-8.70167529698484543e-09, -1.37080219501928280e-08, 1.80728228771354082e-08},
{-4.67111571644807100e-09, -2.72041008123058425e-09, 7.06648883852523113e-09},
{7.26183221906172727e-10, -6.77816339167414128e-09, 4.52883232651690726e-09},
{5.28852302228433047e-09, 6.47161005340457507e-09, -8.67298467766008940e-09},
{-2.25465519365641853e-07, -6.46057585221293529e-07, 3.48151143400587948e-07},
{-1.30051025504229756e-09, -3.25062288891730944e-09, 2.01775679498084060e-09},
{-5.12724809831333062e-09, 9.33902577666956280e-10, -6.96327353416625883e-10},
{-3.10810940873373909e-09, -7.49756534634826721e-10, 6.87357185058523612e-10},
{-1.52109221995821997e-06, -4.22908767925417317e-07, 1.38629667568307413e-06},
{1.42955317028459206e-09, -7.02968461219199980e-10, -3.81617160094549490e-09},
{2.53707400921232562e-09, -1.60727622877665510e-09, -4.18765366827500429e-09},
{-2.14750738948554787e-07, -6.40554276953864132e-07, 3.76128531993924486e-07},
{3.83073214815787821e-09, 4.50296289838947317e-10, 2.29523194894554194e-09},
{4.76340728555735282e-07, 6.83235613037347367e-07, -4.72205395646296822e-07},
{-6.10651996176347607e-04, -1.06790499934057291e-03, 2.29083496655867842e-03},
{3.95497823379997726e-09, 1.38236928154400474e-09, -6.26218820548585242e-09},
{1.11904936705986557e-09, -1.37869946362223494e-08, -9.34049783699042457e-10},
{1.25499246411697740e-09, -2.73635453185150368e-09, -2.91506864740637139e-09},
{-3.59882924006599270e-07, 1.32511373732895413e-06, -1.55110207063907657e-07},
{1.07068498511608823e-09, 8.92087770321126072e-09, 2.62826524433101838e-10},
{-2.69316546841480431e-09, 9.61138280075601870e-10, 5.19946977139973399e-09},
{-5.92563579700916554e-07, -1.05071339539294234e-06, 1.56249964602256375e-07},
{1.32198180180509439e-09, 5.16087961255351502e-09, 8.46339526239248130e-10},
{2.07323220008381881e-06, 1.02309267446332522e-06, -2.07661522726165781e-06},
{1.31402366846389393e-03, 3.78229792813366064e-04, 1.77496793932758741e-03},
{8.59301428624004160e-10, -6.83071707530125138e-09, 3.36249680876754553e-09},
{5.27310424491833629e-09, 2.09999085065692981e-08, -3.10459945807028959e-08},
{-8.88666080375855039e-08, 4.60897593930476024e-07, 7.41576575386676540e-07},
{-4.85540663230921155e-10, -5.58243438975036810e-09, 7.40450811775872353e-10},
{4.03141117225058743e-07, 1.52035531639227450e-06, 9.06206514897367477e-08},
{5.61075629915620496e-04, -2.05847905628765053e-03, 1.12849817492909434e-03},
{5.11216541321246609e-09, 7.26292920250060092e-09, -8.97145741030058730e-09},
{-4.26211688914213127e-07, -7.03366608210270750e-07, 6.27995585866791828e-07},
{1.15309052943982646e-03, 2.34474318844151959e-03, -4.91856748507475423e-03},
{1.01104427799588961e-01, -4.22361682938472982e-02, -1.88750007538552200e-01},
{3.94738332298860684e-10, -7.81372397340440727e-10, 4.06815717224340290e-09},
{-8.61483928638051566e-09, 5.37427180535843263e-09, 1.81738104426676372e-08},
{-8.48011268844706123e-10, -5.33803143354383280e-09, 2.99703953494934172e-10},
{3.89154099408092063e-07, -2.44166311268514957e-07, -8.03240371135063858e-07},
{-1.20249536439409610e-08, 1.48908931921210019e-08, 1.88292573199966284e-09},
{-1.16401289163015065e-08, 2.57866422936903206e-08, -5.27022399332555125e-09},
{1.37065399911928676e-07, 2.16494406102361175e-08, -7.63924557662179482e-07},
{-6.94754161319199870e-10, 6.65038621394664631e-09, -4.31779645371221932e-09},
{4.72542155592614588e-07, -7.58546986886782931e-07, -2.35913417925837088e-07},
{1.46133817312113241e-03, -3.25193103208258009e-04, -3.06625181254991741e-04},
{9.35794082672593210e-09, -7.92923574022275091e-09, -5.41426242728348939e-09},
{-2.15279239157428748e-08, -4.16754339024882903e-09, -1.12896482995505920e-08},
{2.60645369870582400e-10, 1.44616071127263122e-06, -3.63334053799999057e-07},
{9.17105741349288905e-09, -2.02295233654725681e-08, -1.20002956877085509e-08},
{-1.27759226226098477e-07, 1.28193771791124470e-06, -5.83097827522305323e-07},
{2.26880791869919426e-03, -1.34042850080092401e-03, -7.65092051285704835e-04},
{7.03374036792325796e-09, -2.53508958270032281e-09, -7.66132998708535240e-09},
{-9.71978722189015265e-07, -5.57836512454779054e-07, 1.96329328074063003e-06},
{-1.26115140811304343e-03, -4.81792074617704632e-04, -1.06803272537897391e-03},
{1.19419564863885497e-01, 5.07766738901840875e-02, 4.87642090320925953e-02},
{1.14090414893297520e-09, 1.56073433760228752e-08, -1.78054684078429726e-08},
{3.03285130343056153e-09, -1.58615337531031741e-09, -4.94928394101368241e-09},
{2.64483280249840080e-07, 2.97155396291660413e-07, -5.41608085095034164e-07},
{2.68757552324139226e-09, -1.41400907649469332e-08, 2.93255796729452456e-08},
{-2.11094617584561828e-07, -6.56355695552793272e-07, 3.72180321686621518e-07},
{-2.55073452371079590e-04, 1.57943859317488818e-03, -1.29154484940938240e-03},
{1.40049266628139435e-09, 1.40747080656922208e-08, -2.58792021839981956e-09},
{-2.12330362681090179e-07, -1.30522733223815968e-06, 5.84417623253341567e-07},
{-9.33144849909676392e-04, 1.90305575962152547e-03, -8.35564417983726418e-04},
{1.81624805201406961e-02, 6.84911174969819458e-02, -2.28291882522520390e-02},
{-8.25231299961259879e-09, -1.40227519596081152e-08, 1.78809529925716415e-08},
{1.90689491530449118e-07, 7.01057736002264065e-07, -4.26430629252294580e-07},
{-5.85146839837499930e-04, -1.07311215649546045e-03, 2.31986890222730339e-03},
{-1.05962397073886522e-01, 5.51532131360410807e-02, 1.87542648909451215e-01},
{-1.37499370823599516e-03, -8.49619409242363438e-04, -1.18180356709159952e-03}
};
static const double INTERCEPT[3] = {
-1.29208772400146188e+00,
6.62251952866635918e+00,
-1.35908984683965173e-01
};
// END AUTO-GENERATED COEFFICIENTS
inline void compute_poly_features(const double x[7], double out[330]) {
for (int i = 0; i < N_FEATURES; ++i) {
double val = 1.0;
for (int j = 0; j < N_INPUTS; ++j) {
if (POWERS[i][j] != 0) {
double base = x[j];
int exp = POWERS[i][j];
// Fast integer exponentiation (max exp = 4)
double p = 1.0;
for (int e = 0; e < exp; ++e)
p *= base;
val *= p;
}
}
out[i] = val;
}
}
} // namespace detail
struct RGB {
unsigned char r, g, b;
};
/**
* Mix two RGB colors using polynomial pigment mixing.
*
* This performs polynomial pigment-style RGB interpolation.
*
* @param r1,g1,b1 First color (0-255)
* @param r2,g2,b2 Second color (0-255)
* @param t Mixing ratio: 0.0 = all color1, 1.0 = all color2
* @param out_r,out_g,out_b Output color (0-255)
*/
inline void lerp(unsigned char r1, unsigned char g1, unsigned char b1,
unsigned char r2, unsigned char g2, unsigned char b2,
float t,
unsigned char* out_r, unsigned char* out_g, unsigned char* out_b) {
// Clamp t
if (t <= 0.0f) {
*out_r = r1; *out_g = g1; *out_b = b1;
return;
}
if (t >= 1.0f) {
*out_r = r2; *out_g = g2; *out_b = b2;
return;
}
double x[7] = {
static_cast<double>(r1), static_cast<double>(g1), static_cast<double>(b1),
static_cast<double>(r2), static_cast<double>(g2), static_cast<double>(b2),
static_cast<double>(t)
};
double features[330];
detail::compute_poly_features(x, features);
// Dot product: features @ COEF + INTERCEPT
for (int c = 0; c < 3; ++c) {
double sum = detail::INTERCEPT[c];
for (int i = 0; i < detail::N_FEATURES; ++i) {
sum += features[i] * detail::COEF[i][c];
}
// Clamp to [0, 255] and truncate (matches numpy astype(int) behavior)
int val = static_cast<int>(sum);
if (val < 0) val = 0;
if (val > 255) val = 255;
if (c == 0) *out_r = static_cast<unsigned char>(val);
else if (c == 1) *out_g = static_cast<unsigned char>(val);
else *out_b = static_cast<unsigned char>(val);
}
}
/**
* Convenience overload returning an RGB struct.
*/
inline RGB lerp(unsigned char r1, unsigned char g1, unsigned char b1,
unsigned char r2, unsigned char g2, unsigned char b2,
float t) {
RGB result;
lerp(r1, g1, b1, r2, g2, b2, t, &result.r, &result.g, &result.b);
return result;
}
} // namespace filament_mixer
#endif // FILAMENT_MIXER_MODEL_HPP
@@ -108,6 +108,22 @@ const std::vector<Vec2d>& CornerSmoother::curve_coefficients(
return m_cached_coefficients;
}
bool CornerSmoother::is_on_straight_run(const Vec2d &previous, const Vec2d &vertex, const Vec2d &next)
{
const Vec2d incoming_leg = vertex - previous;
const Vec2d outgoing_leg = next - vertex;
const double incoming_length = incoming_leg.norm();
const double outgoing_length = outgoing_leg.norm();
// A vertex repeating one of its neighbours carries no direction of its own.
if (incoming_length < EPSILON || outgoing_length < EPSILON)
return true;
const Vec2d incoming = incoming_leg / incoming_length;
const Vec2d outgoing = outgoing_leg / outgoing_length;
return incoming.dot(outgoing) > 0. &&
std::abs(incoming.x() * outgoing.y() - incoming.y() * outgoing.x()) < EPSILON;
}
void CornerSmoother::round_corner(const Vec2d &previous, const Vec2d &corner, const Vec2d &next)
{
m_corner_points.clear();
+41 -18
View File
@@ -1,6 +1,7 @@
#pragma once
#include <algorithm>
#include <array>
#include <cmath>
#include <functional>
#include <vector>
@@ -47,36 +48,57 @@ public:
template<typename Emit> void push(const Vec2d &point, Emit &emit)
{
if (m_pending == 0) {
if (m_held == 0) {
// The first point of a path is an end, not a corner, and stays where it is.
emit(point);
m_previous = point;
} else if (m_pending > 1) {
round_corner(m_previous, m_corner, point);
for (const Vec2d &corner_point : m_corner_points)
emit(corner_point);
m_previous = m_corner;
m_window[m_held++] = point;
return;
}
m_corner = point;
m_pending = std::min(m_pending + 1, 2);
if (m_held > 1 && is_on_straight_run(m_window[m_held - 2], m_window[m_held - 1], point)) {
// The newest vertex only splits a straight leg, so the leg runs on to this point instead.
m_window[m_held - 1] = point;
return;
}
if (m_held < 3) {
m_window[m_held++] = point;
return;
}
// Both legs of the middle vertex are complete now, so its curve can no longer grow.
emit_corner(m_window[0], m_window[1], m_window[2], emit);
m_window[0] = m_window[1];
m_window[1] = m_window[2];
m_window[2] = point;
}
// Emits the last point of the path and prepares the smoother for a new one.
template<typename Emit> void flush(Emit &emit)
{
if (m_pending > 1)
emit(m_corner);
m_pending = 0;
if (m_held > 2)
emit_corner(m_window[0], m_window[1], m_window[2], emit);
if (m_held > 1)
emit(m_window[m_held - 1]);
m_held = 0;
}
private:
template<typename Emit> void emit_corner(const Vec2d &previous, const Vec2d &corner, const Vec2d &next, Emit &emit)
{
round_corner(previous, corner, next);
for (const Vec2d &corner_point : m_corner_points)
emit(corner_point);
}
// Tells a vertex that only continues a straight leg (or repeats its predecessor) from a corner.
// A path doubling back on itself is not one, that vertex is a hairpin and stays where it is.
static bool is_on_straight_run(const Vec2d &previous, const Vec2d &vertex, const Vec2d &next);
// Fills m_corner_points with the points replacing the corner vertex.
void round_corner(const Vec2d &previous, const Vec2d &corner, const Vec2d &next);
// Flattens the canonical corner curve of the given size and turn into coordinates of the
// (incoming, outgoing) basis of the corner. Cached, as an infill path repeats the same corner.
const std::vector<Vec2d>& curve_coefficients(double corner_distance, const Vec2d &incoming, const Vec2d &outgoing);
// Fraction of the shorter adjoining segment consumed on each side of a corner. Half of a segment
// is the maximum, otherwise the curves of two adjacent corners would overlap.
// Fraction of the shorter adjoining leg consumed on each side of a corner. Half of a leg is the
// maximum, otherwise the curves of two adjacent corners would overlap.
const double m_corner_distance_ratio;
const double m_tolerance;
const double m_max_corner_distance;
@@ -88,10 +110,11 @@ private:
double m_cached_cosine { 0. };
bool m_has_cached_coefficients { false };
Vec2d m_previous { Vec2d::Zero() };
Vec2d m_corner { Vec2d::Zero() };
// Number of points held back: none, the first point of a path, or a corner candidate.
int m_pending { 0 };
// The corners seen last, kept free of vertices that merely split a straight leg. The middle one
// is rounded once the third arrives, which is what makes its outgoing leg final.
std::array<Vec2d, 3> m_window { Vec2d::Zero(), Vec2d::Zero(), Vec2d::Zero() };
// How many of them are filled in.
int m_held { 0 };
};
// Rounds the corners of already scaled paths in place. Paths of less than three points are left alone.
+9 -5
View File
@@ -351,19 +351,23 @@ void Node::convertToPolylines(Polylines &output, const coord_t line_overlap) con
{
Polylines result;
result.emplace_back();
convertToPolylines(0, result);
// Orca: the layers are filled in parallel, so they would consume a shared generator in a
// different order every run, and a model would not slice the same way twice. Each tree seeds
// its own from where it is rooted; one constant seed would start them all on the same pick.
std::mt19937_64 rng { uint64_t(PointHash{}(m_p)) };
convertToPolylines(0, result, rng);
removeJunctionOverlap(result, line_overlap);
append(output, std::move(result));
}
void Node::convertToPolylines(size_t long_line_idx, Polylines &output) const
void Node::convertToPolylines(size_t long_line_idx, Polylines &output, std::mt19937_64 &rng) const
{
if (m_children.empty()) {
output[long_line_idx].points.push_back(m_p);
return;
}
size_t first_child_idx = rand() % m_children.size();
m_children[first_child_idx]->convertToPolylines(long_line_idx, output);
const size_t first_child_idx = rng() % m_children.size();
m_children[first_child_idx]->convertToPolylines(long_line_idx, output, rng);
output[long_line_idx].points.push_back(m_p);
for (size_t idx_offset = 1; idx_offset < m_children.size(); idx_offset++) {
@@ -371,7 +375,7 @@ void Node::convertToPolylines(size_t long_line_idx, Polylines &output) const
const Node& child = *m_children[child_idx];
output.emplace_back();
size_t child_line_idx = output.size() - 1;
child.convertToPolylines(child_line_idx, output);
child.convertToPolylines(child_line_idx, output, rng);
output[child_line_idx].points.emplace_back(m_p);
}
}
+3 -1
View File
@@ -7,6 +7,7 @@
#include <functional>
#include <memory>
#include <optional>
#include <random>
#include <vector>
#include "../../EdgeGrid.hpp"
@@ -259,8 +260,9 @@ protected:
*
* \param long_line a reference to a polyline in \p output which to continue building on in the recursion
* \param output all branches in this tree connected into polylines
* \param rng the generator the junctions draw from, carried through the recursion
*/
void convertToPolylines(size_t long_line_idx, Polylines &output) const;
void convertToPolylines(size_t long_line_idx, Polylines &output, std::mt19937_64 &rng) const;
void removeJunctionOverlap(Polylines &polylines, coord_t line_overlap) const;
+327
View File
@@ -0,0 +1,327 @@
#include "AssimpImport.hpp"
#include "../TexturePainting.hpp"
#include "ResourcePathUtils.hpp"
#include <assimp/Importer.hpp>
#include <assimp/config.h>
#include <assimp/material.h>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
#include <boost/log/trivial.hpp>
#include <boost/nowide/fstream.hpp>
#include <array>
#include <cstdint>
#include <limits>
#include <sstream>
#include <string>
#include <vector>
namespace Slic3r {
namespace {
void clear_textured_mesh(TexturedMesh& out)
{
out.vertices.clear();
out.indices.clear();
out.uvs.clear();
out.uv_coords.clear();
out.uv_indices.clear();
out.textures.clear();
out.material_ids.clear();
out.material_texture_map.clear();
out.material_colors.clear();
}
void set_error_message(std::string* error_message, const std::string& message)
{
if (error_message)
*error_message = message;
}
bool is_fbx_path(const std::string& path)
{
return boost::algorithm::iends_with(path, ".fbx");
}
bool should_flip_uvs(const std::string& path)
{
return boost::algorithm::iends_with(path, ".fbx") ||
boost::algorithm::iends_with(path, ".glb");
}
unsigned int assimp_import_flags(const std::string& path)
{
unsigned int flags = aiProcess_Triangulate
| aiProcess_GenNormals
| aiProcess_PreTransformVertices
| aiProcess_SortByPType;
if (should_flip_uvs(path))
flags |= aiProcess_FlipUVs;
return flags;
}
void configure_importer(Assimp::Importer& importer, const std::string& path, unsigned int flags)
{
importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,
aiPrimitiveType_POINT | aiPrimitiveType_LINE);
if (flags & aiProcess_PreTransformVertices)
importer.SetPropertyBool(AI_CONFIG_PP_PTV_KEEP_HIERARCHY, true);
if (is_fbx_path(path)) {
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, false);
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, false);
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, false);
}
}
bool read_external_texture_file(const boost::filesystem::path& path, TextureImage& out)
{
boost::nowide::ifstream file(path.string(), std::ios::binary | std::ios::ate);
if (!file.is_open())
return false;
const std::streamoff size = file.tellg();
if (size <= 0)
return false;
if (static_cast<uintmax_t>(size) > static_cast<uintmax_t>(std::numeric_limits<size_t>::max()))
return false;
file.seekg(0);
out.width = -1;
out.height = -1;
out.channels = 0;
out.data.resize(static_cast<size_t>(size));
file.read(reinterpret_cast<char*>(out.data.data()), size);
if (!file && !file.eof()) {
out.data.clear();
return false;
}
return true;
}
bool read_embedded_texture(const aiTexture& texture, TextureImage& out)
{
out.data.clear();
if (texture.mHeight == 0) {
if (texture.mWidth == 0)
return false;
out.width = -1;
out.height = -1;
out.channels = 0;
out.data.assign(
reinterpret_cast<const unsigned char*>(texture.pcData),
reinterpret_cast<const unsigned char*>(texture.pcData) + texture.mWidth);
return !out.data.empty();
}
if (texture.mWidth == 0 || texture.mHeight == 0)
return false;
if (texture.mWidth > static_cast<unsigned int>(std::numeric_limits<int>::max()) ||
texture.mHeight > static_cast<unsigned int>(std::numeric_limits<int>::max())) {
return false;
}
const size_t width = static_cast<size_t>(texture.mWidth);
const size_t height = static_cast<size_t>(texture.mHeight);
if (width > std::numeric_limits<size_t>::max() / height ||
width * height > std::numeric_limits<size_t>::max() / 4) {
return false;
}
out.width = static_cast<int>(texture.mWidth);
out.height = static_cast<int>(texture.mHeight);
out.channels = 4;
const size_t pixel_count = width * height;
out.data.resize(pixel_count * 4);
for (size_t i = 0; i < pixel_count; ++i) {
const aiTexel& texel = texture.pcData[i];
out.data[i * 4 + 0] = texel.r;
out.data[i * 4 + 1] = texel.g;
out.data[i * 4 + 2] = texel.b;
out.data[i * 4 + 3] = texel.a;
}
return !out.data.empty();
}
bool get_material_texture(const aiMaterial& material, aiString& texture_path)
{
if (material.GetTextureCount(aiTextureType_DIFFUSE) > 0 &&
material.GetTexture(aiTextureType_DIFFUSE, 0, &texture_path) == AI_SUCCESS) {
return true;
}
if (material.GetTextureCount(aiTextureType_BASE_COLOR) > 0 &&
material.GetTexture(aiTextureType_BASE_COLOR, 0, &texture_path) == AI_SUCCESS) {
return true;
}
return false;
}
std::array<float, 4> get_material_color(const aiMaterial& material)
{
aiColor4D color(1.f, 1.f, 1.f, 1.f);
if (material.Get(AI_MATKEY_BASE_COLOR, color) == AI_SUCCESS)
return {color.r, color.g, color.b, color.a};
if (material.Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS)
return {color.r, color.g, color.b, color.a};
return {1.f, 1.f, 1.f, 1.f};
}
bool collect_mesh(const aiMesh& mesh, size_t& vertex_offset, TexturedMesh& out, std::string& error)
{
if (mesh.mNumVertices > static_cast<size_t>(std::numeric_limits<int>::max()) - vertex_offset) {
error = "Assimp mesh has too many vertices for TexturedMesh indices";
return false;
}
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
const aiVector3D& v = mesh.mVertices[i];
out.vertices.push_back({v.x, v.y, v.z});
if (mesh.HasTextureCoords(0)) {
const aiVector3D& uv = mesh.mTextureCoords[0][i];
out.uvs.push_back({uv.x, uv.y});
} else {
out.uvs.push_back({0.f, 0.f});
}
}
const int material_index = static_cast<int>(mesh.mMaterialIndex);
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
const aiFace& face = mesh.mFaces[i];
if (face.mNumIndices != 3)
continue;
if (face.mIndices[0] >= mesh.mNumVertices ||
face.mIndices[1] >= mesh.mNumVertices ||
face.mIndices[2] >= mesh.mNumVertices) {
error = "Assimp mesh face index is out of bounds";
return false;
}
out.indices.push_back({
static_cast<int>(static_cast<size_t>(face.mIndices[0]) + vertex_offset),
static_cast<int>(static_cast<size_t>(face.mIndices[1]) + vertex_offset),
static_cast<int>(static_cast<size_t>(face.mIndices[2]) + vertex_offset)});
out.material_ids.push_back(material_index);
}
vertex_offset += mesh.mNumVertices;
return true;
}
void collect_materials(const aiScene& scene, const boost::filesystem::path& base_dir, TexturedMesh& out)
{
out.material_texture_map.assign(scene.mNumMaterials, -1);
out.material_colors.assign(scene.mNumMaterials, {1.f, 1.f, 1.f, 1.f});
for (unsigned int material_index = 0; material_index < scene.mNumMaterials; ++material_index) {
const aiMaterial* material = scene.mMaterials[material_index];
if (!material)
continue;
out.material_colors[material_index] = get_material_color(*material);
aiString texture_path;
if (!get_material_texture(*material, texture_path))
continue;
TextureImage image;
const aiTexture* embedded_texture = scene.GetEmbeddedTexture(texture_path.C_Str());
if (embedded_texture) {
if (!read_embedded_texture(*embedded_texture, image))
continue;
} else {
const boost::filesystem::path resolved = resource_path::resolve_external_resource_path(
base_dir, texture_path.C_Str(), "Assimp texture");
if (resolved.empty()) {
BOOST_LOG_TRIVIAL(warning) << "AssimpImport: texture file not found: "
<< texture_path.C_Str();
continue;
}
if (!read_external_texture_file(resolved, image)) {
BOOST_LOG_TRIVIAL(warning) << "AssimpImport: failed to read texture: "
<< resolved;
continue;
}
}
out.material_texture_map[material_index] = static_cast<int>(out.textures.size());
out.textures.push_back(std::move(image));
}
}
std::string scene_failure_summary(const std::string& path, const char* assimp_error)
{
std::ostringstream ss;
ss << "Assimp failed to import " << path;
if (assimp_error && assimp_error[0] != '\0')
ss << ": " << assimp_error;
return ss.str();
}
} // namespace
bool load_assimp_textured_model(const std::string& path, TexturedMesh& out, std::string* error_message)
{
clear_textured_mesh(out);
Assimp::Importer importer;
const unsigned int flags = assimp_import_flags(path);
configure_importer(importer, path, flags);
const aiScene* scene = importer.ReadFile(path, flags);
if (!scene || (scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) || !scene->mRootNode) {
const std::string message = scene_failure_summary(path, importer.GetErrorString());
BOOST_LOG_TRIVIAL(error) << "AssimpImport: " << message;
set_error_message(error_message, message);
return false;
}
if (scene->mNumMeshes == 0) {
const std::string message = "Assimp scene has no meshes: " + path;
BOOST_LOG_TRIVIAL(error) << "AssimpImport: " << message;
set_error_message(error_message, message);
return false;
}
size_t vertex_offset = 0;
for (unsigned int mesh_index = 0; mesh_index < scene->mNumMeshes; ++mesh_index) {
const aiMesh* mesh = scene->mMeshes[mesh_index];
if (!mesh || !mesh->HasPositions())
continue;
std::string mesh_error;
if (!collect_mesh(*mesh, vertex_offset, out, mesh_error)) {
const std::string message = mesh_error + ": " + path;
BOOST_LOG_TRIVIAL(error) << "AssimpImport: " << message;
set_error_message(error_message, message);
clear_textured_mesh(out);
return false;
}
}
if (out.vertices.empty() || out.indices.empty()) {
const std::string message = "Assimp extracted no valid triangles: " + path;
BOOST_LOG_TRIVIAL(error) << "AssimpImport: " << message;
set_error_message(error_message, message);
clear_textured_mesh(out);
return false;
}
collect_materials(*scene, boost::filesystem::path(path).parent_path(), out);
BOOST_LOG_TRIVIAL(info) << "AssimpImport: loaded " << out.vertices.size()
<< " vertices, " << out.indices.size()
<< " triangles, " << out.textures.size()
<< " textures from " << path;
return true;
}
} // namespace Slic3r
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include <string>
namespace Slic3r {
struct TexturedMesh;
bool load_assimp_textured_model(const std::string& path, TexturedMesh& out, std::string* error_message = nullptr);
} // namespace Slic3r
+147 -3
View File
@@ -1,6 +1,8 @@
#include "../libslic3r.h"
#include "../Model.hpp"
#include "../TriangleMesh.hpp"
#include "../TexturePainting.hpp"
#include "ResourcePathUtils.hpp"
#include "OBJ.hpp"
#include "objparser.hpp"
@@ -21,7 +23,7 @@
namespace Slic3r {
bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::string &message)
bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::string &message, ObjParser::MtlData *out_mtl)
{
if (meshptr == nullptr)
return false;
@@ -98,6 +100,7 @@ bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::s
its.indices.reserve(num_faces + num_quads);
if (exist_mtl) {
obj_info.is_single_mtl = data.usemtls.size() == 1 && mtl_data.new_mtl_unmap.size() == 1;
obj_info.usemtls = data.usemtls;
obj_info.face_colors.reserve(num_faces + num_quads);
}
bool has_color = data.has_vertex_color;
@@ -210,14 +213,17 @@ bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::s
}
if (meshptr->volume() < 0)
meshptr->flip_triangles();
// Hand the parsed material table back so callers can build a TexturedMesh from it.
if (out_mtl)
*out_mtl = mtl_data;
return true;
}
bool load_obj(const char *path, Model *model, ObjInfo& obj_info, std::string &message, const char *object_name_in)
bool load_obj(const char *path, Model *model, ObjInfo& obj_info, std::string &message, const char *object_name_in, ObjParser::MtlData *out_mtl)
{
TriangleMesh mesh;
bool ret = load_obj(path, &mesh, obj_info, message);
bool ret = load_obj(path, &mesh, obj_info, message, out_mtl);
if (ret) {
std::string object_name;
@@ -232,6 +238,144 @@ bool load_obj(const char *path, Model *model, ObjInfo& obj_info, std::string &me
return ret;
}
bool obj_to_textured_mesh(
const ObjInfo& obj_info,
const indexed_triangle_set& its,
const ObjParser::MtlData& mtl_data,
const std::string& obj_directory,
TexturedMesh& out)
{
if (its.vertices.empty() || its.indices.empty() || !obj_info.has_uv_png)
return false;
const size_t nv = its.vertices.size();
const size_t nf = its.indices.size();
// 1. Copy vertices
out.vertices.resize(nv);
for (size_t i = 0; i < nv; ++i)
out.vertices[i] = {its.vertices[i].x(), its.vertices[i].y(), its.vertices[i].z()};
// 2. Copy face indices
out.indices.resize(nf);
for (size_t i = 0; i < nf; ++i)
out.indices[i] = {its.indices[i][0], its.indices[i][1], its.indices[i][2]};
// 3. Build per-face UV (uv_coords + uv_indices)
// OBJ UV convention: V=0 at bottom (OpenGL); texture sampling expects V=0 at top (like glTF/OpenCV).
// Flip V here so downstream code works uniformly.
if (!obj_info.uvs.empty()) {
const size_t uv_face_count = obj_info.uvs.size();
out.uv_coords.resize(uv_face_count * 3);
out.uv_indices.resize(nf);
for (size_t fi = 0; fi < nf; ++fi) {
if (fi < uv_face_count) {
int base = static_cast<int>(fi * 3);
out.uv_coords[base + 0] = {obj_info.uvs[fi][0].x(), 1.f - obj_info.uvs[fi][0].y()};
out.uv_coords[base + 1] = {obj_info.uvs[fi][1].x(), 1.f - obj_info.uvs[fi][1].y()};
out.uv_coords[base + 2] = {obj_info.uvs[fi][2].x(), 1.f - obj_info.uvs[fi][2].y()};
out.uv_indices[fi] = {base, base + 1, base + 2};
} else {
out.uv_indices[fi] = {0, 0, 0};
}
}
}
// 4. Build material list and load textures from disk
// Map: material name -> material index
std::map<std::string, int> mtl_name_to_idx;
for (size_t i = 0; i < mtl_data.mtl_orders.size(); ++i)
mtl_name_to_idx[mtl_data.mtl_orders[i]] = static_cast<int>(i);
const int num_materials = static_cast<int>(mtl_data.mtl_orders.size());
out.material_colors.resize(num_materials, {1.f, 1.f, 1.f, 1.f});
out.material_texture_map.resize(num_materials, -1);
// Map: texture filename -> index in out.textures
std::map<std::string, int> png_to_tex_idx;
for (int mi = 0; mi < num_materials; ++mi) {
const std::string& name = mtl_data.mtl_orders[mi];
auto it = mtl_data.new_mtl_unmap.find(name);
if (it == mtl_data.new_mtl_unmap.end())
continue;
const auto& mtl = *(it->second);
// Material color from Kd
out.material_colors[mi] = {mtl.Kd[0], mtl.Kd[1], mtl.Kd[2], mtl.Tr};
// Texture from map_Kd
if (mtl.map_Kd.empty())
continue;
auto tex_it = png_to_tex_idx.find(mtl.map_Kd);
if (tex_it != png_to_tex_idx.end()) {
out.material_texture_map[mi] = tex_it->second;
continue;
}
// Resolve texture file path.
const boost::filesystem::path requested_tex_path(mtl.map_Kd);
const boost::filesystem::path tex_path = requested_tex_path.is_absolute() ?
resource_path::resolve_existing_path_case_insensitive(requested_tex_path, "obj_to_textured_mesh: map_Kd") :
resource_path::resolve_existing_relative_path_case_insensitive(
boost::filesystem::path(obj_directory), requested_tex_path, "obj_to_textured_mesh: map_Kd");
if (tex_path.empty()) {
BOOST_LOG_TRIVIAL(warning) << "obj_to_textured_mesh: texture not found: " << requested_tex_path;
continue;
}
// Read raw file bytes
boost::nowide::ifstream file(tex_path.string(), std::ios::binary | std::ios::ate);
if (!file.is_open())
continue;
auto file_size = file.tellg();
if (file_size <= 0)
continue;
file.seekg(0, std::ios::beg);
TextureImage ti;
ti.data.resize(static_cast<size_t>(file_size));
file.read(reinterpret_cast<char*>(ti.data.data()), file_size);
ti.width = -1;
ti.height = -1;
ti.channels = 0;
int new_idx = static_cast<int>(out.textures.size());
out.textures.push_back(std::move(ti));
png_to_tex_idx[mtl.map_Kd] = new_idx;
out.material_texture_map[mi] = new_idx;
}
// 5. Build per-face material_ids from usemtls ranges
out.material_ids.resize(nf, -1);
if (!obj_info.usemtls.empty()) {
for (size_t fi = 0; fi < nf; ++fi) {
int face_idx = static_cast<int>(fi);
for (size_t k = 0; k < obj_info.usemtls.size(); ++k) {
const auto& um = obj_info.usemtls[k];
if (face_idx >= um.face_start && face_idx <= um.face_end) {
auto name_it = mtl_name_to_idx.find(um.name);
if (name_it != mtl_name_to_idx.end())
out.material_ids[fi] = name_it->second;
break;
}
}
}
}
if (out.textures.empty()) {
BOOST_LOG_TRIVIAL(warning) << "obj_to_textured_mesh: no textures loaded";
return false;
}
BOOST_LOG_TRIVIAL(info) << "obj_to_textured_mesh: " << nf << " faces, "
<< out.textures.size() << " textures, "
<< num_materials << " materials";
return true;
}
bool store_obj(const char *path, TriangleMesh *mesh)
{
//FIXME returning false even if write failed.
+14 -2
View File
@@ -1,6 +1,7 @@
#ifndef slic3r_Format_OBJ_hpp_
#define slic3r_Format_OBJ_hpp_
#include "libslic3r/Color.hpp"
#include "objparser.hpp"
#include <unordered_map>
namespace Slic3r {
@@ -18,6 +19,7 @@ struct ObjInfo {
std::map<std::string,bool> pngs;
std::unordered_map<int, std::string> uv_map_pngs;
bool has_uv_png{false};
std::vector<ObjParser::ObjUseMtl> usemtls; // material spans, for texture import
};
struct ObjDialogInOut
@@ -32,8 +34,18 @@ struct ObjDialogInOut
std::string lost_material_name{""};
};
typedef std::function<void(ObjDialogInOut &in_out)> ObjImportColorFn;
extern bool load_obj(const char *path, TriangleMesh *mesh, ObjInfo &vertex_colors, std::string &message);
extern bool load_obj(const char *path, Model *model, ObjInfo &vertex_colors, std::string &message, const char *object_name = nullptr);
extern bool load_obj(const char *path, TriangleMesh *mesh, ObjInfo &vertex_colors, std::string &message, ObjParser::MtlData *out_mtl = nullptr);
extern bool load_obj(const char *path, Model *model, ObjInfo &vertex_colors, std::string &message, const char *object_name = nullptr, ObjParser::MtlData *out_mtl = nullptr);
struct TexturedMesh;
// Build a TexturedMesh (vertices + per-face UVs + the texture files named by map_Kd) from a
// parsed OBJ plus its material table, so the texture-to-color importer can sample face colours.
extern bool obj_to_textured_mesh(
const ObjInfo& obj_info,
const indexed_triangle_set& its,
const ObjParser::MtlData& mtl_data,
const std::string& obj_directory,
TexturedMesh& out);
extern bool store_obj(const char *path, TriangleMesh *mesh);
extern bool store_obj(const char *path, ModelObject *model);
+240
View File
@@ -0,0 +1,240 @@
#ifndef slic3r_Format_ResourcePathUtils_hpp_
#define slic3r_Format_ResourcePathUtils_hpp_
#include <algorithm>
#include <cctype>
#include <cstddef>
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
#include <boost/log/trivial.hpp>
namespace Slic3r {
namespace resource_path {
inline std::string ascii_lower_copy(const std::string& value)
{
std::string lowered;
lowered.reserve(value.size());
for (unsigned char ch : value)
lowered.push_back(static_cast<char>(std::tolower(ch)));
return lowered;
}
inline boost::filesystem::path portable_path_copy(const boost::filesystem::path& value)
{
std::string portable = value.string();
std::replace(portable.begin(), portable.end(), '\\', '/');
return boost::filesystem::path(portable);
}
inline int hex_digit_value(char ch)
{
if (ch >= '0' && ch <= '9') return ch - '0';
if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10;
if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10;
return -1;
}
// Byte-level percent decoding. Per RFC 3986 the %XX byte stream is expected to be
// UTF-8 when produced from URIs / Assimp aiString; this function performs no
// transcoding, so callers must treat both input and output as raw UTF-8 bytes.
inline std::string percent_decode_copy(const std::string& value)
{
std::string decoded;
decoded.reserve(value.size());
for (std::size_t i = 0; i < value.size(); ++i) {
if (value[i] == '%' && i + 2 < value.size()) {
const int hi = hex_digit_value(value[i + 1]);
const int lo = hex_digit_value(value[i + 2]);
if (hi >= 0 && lo >= 0) {
decoded.push_back(static_cast<char>((hi << 4) | lo));
i += 2;
continue;
}
}
decoded.push_back(value[i]);
}
return decoded;
}
inline std::string strip_file_uri_prefix_copy(const std::string& value)
{
const std::string lower = ascii_lower_copy(value);
if (lower.rfind("file://", 0) != 0)
return value;
std::string path = value.substr(7);
if (ascii_lower_copy(path).rfind("localhost/", 0) == 0)
path.erase(0, std::string("localhost").size());
else if (!path.empty() && path.front() != '/')
path = "//" + path;
// file:///C:/... should become C:/..., while file:///tmp/... keeps /tmp/...
if (path.size() >= 3 && path[0] == '/' && std::isalpha(static_cast<unsigned char>(path[1])) && path[2] == ':')
path.erase(path.begin());
return path;
}
inline bool file_uri_has_remote_authority(const std::string& value)
{
const std::string lower = ascii_lower_copy(value);
if (lower.rfind("file://", 0) != 0)
return false;
const std::string path = value.substr(7);
if (path.empty() || path.front() == '/')
return false;
const std::size_t slash = path.find('/');
const std::string authority = path.substr(0, slash);
return ascii_lower_copy(authority) != "localhost";
}
inline bool looks_like_windows_absolute_path(const boost::filesystem::path& path)
{
const std::string portable = portable_path_copy(path).string();
return portable.size() >= 3
&& std::isalpha(static_cast<unsigned char>(portable[0]))
&& portable[1] == ':'
&& portable[2] == '/';
}
inline boost::filesystem::path filename_from_portable_path(const boost::filesystem::path& value)
{
const boost::filesystem::path portable = portable_path_copy(value);
return portable.filename();
}
inline boost::filesystem::path find_child_case_insensitive(
const boost::filesystem::path& directory,
const boost::filesystem::path& requested_name,
const char* context)
{
if (!boost::filesystem::exists(directory) || !boost::filesystem::is_directory(directory))
return {};
const std::string requested_lower = ascii_lower_copy(requested_name.filename().string());
std::vector<boost::filesystem::path> matches;
boost::system::error_code ec;
for (boost::filesystem::directory_iterator it(directory, ec), end; !ec && it != end; it.increment(ec)) {
if (ascii_lower_copy(it->path().filename().string()) == requested_lower)
matches.push_back(it->path());
}
if (matches.size() == 1)
return matches.front();
if (matches.size() > 1) {
BOOST_LOG_TRIVIAL(warning) << context << ": ambiguous case-insensitive resource match for "
<< requested_name << " in " << directory;
}
return {};
}
inline boost::filesystem::path resolve_existing_path_case_insensitive(
const boost::filesystem::path& requested_path,
const char* context = "resource_path")
{
const boost::filesystem::path normalized_path = portable_path_copy(requested_path);
if (normalized_path.empty())
return {};
if (boost::filesystem::exists(normalized_path))
return normalized_path;
boost::filesystem::path current;
bool initialized = false;
for (const boost::filesystem::path& part : normalized_path) {
if (part == normalized_path.root_name() || part == normalized_path.root_directory()) {
current /= part;
initialized = true;
continue;
}
if (!initialized) {
current = boost::filesystem::current_path();
initialized = true;
}
boost::filesystem::path exact = current / part;
if (boost::filesystem::exists(exact)) {
current = exact;
continue;
}
boost::filesystem::path matched = find_child_case_insensitive(current, part, context);
if (matched.empty())
return {};
BOOST_LOG_TRIVIAL(info) << context << ": resolved resource path case-insensitively from "
<< exact << " to " << matched;
current = matched;
}
return boost::filesystem::exists(current) ? current : boost::filesystem::path();
}
inline boost::filesystem::path resolve_existing_relative_path_case_insensitive(
const boost::filesystem::path& base_dir,
const boost::filesystem::path& resource_path,
const char* context = "resource_path")
{
const boost::filesystem::path requested = resource_path.is_absolute() ? resource_path : base_dir / resource_path;
return resolve_existing_path_case_insensitive(requested, context);
}
// Resolve a resource path that originated outside our own code (e.g. a glTF/FBX
// material texture reference or a file:// URI inside a 3MF descriptor).
//
// `raw_path` is expected to be UTF-8 regardless of host platform: file URIs are
// UTF-8 by spec, and Assimp aiString uses UTF-8 internally. Cross-platform
// correctness on Windows additionally relies on the process having called
// boost::nowide::nowide_filesystem() during startup (see src/BambuStudio.cpp),
// which imbues boost::filesystem::path with a UTF-8 codecvt so that
// `path(std::string)` constructs from UTF-8 byte sequences. Callers that bypass
// the main entry point (standalone CLI tools, unit tests) must reproduce that
// setup themselves before invoking this helper.
inline boost::filesystem::path resolve_external_resource_path(
const boost::filesystem::path& base_dir,
const std::string& raw_path,
const char* context = "resource_path",
bool allow_basename_fallback = true)
{
if (raw_path.empty())
return {};
const bool remote_file_uri = file_uri_has_remote_authority(raw_path);
const std::string decoded_path = percent_decode_copy(strip_file_uri_prefix_copy(raw_path));
const boost::filesystem::path requested = portable_path_copy(boost::filesystem::path(decoded_path));
boost::filesystem::path resolved = (requested.is_absolute() || looks_like_windows_absolute_path(requested)) ?
resolve_existing_path_case_insensitive(requested, context) :
resolve_existing_relative_path_case_insensitive(base_dir, requested, context);
if (!resolved.empty())
return resolved;
if (!allow_basename_fallback || remote_file_uri)
return {};
const boost::filesystem::path basename = filename_from_portable_path(requested);
if (basename.empty())
return {};
resolved = resolve_existing_relative_path_case_insensitive(base_dir, basename, context);
if (!resolved.empty()) {
BOOST_LOG_TRIVIAL(info) << context << ": resolved resource by basename from "
<< requested << " to " << resolved;
}
return resolved;
}
} // namespace resource_path
} // namespace Slic3r
#endif /* slic3r_Format_ResourcePathUtils_hpp_ */
+1 -1
View File
@@ -712,7 +712,7 @@ unsigned int Step::get_triangle_num(double linear_deflection, double angle_defle
return 0;
}
}
} catch(const Exception &e) {
} catch(const Exception &) {
return 0;
}
+42
View File
@@ -4,6 +4,7 @@
#include "../Preset.hpp"
#include "../Utils.hpp"
#include "../LocalesUtils.hpp"
#include "../FilamentMixer.hpp"
#include "../GCode.hpp"
#include "../Geometry.hpp"
#include "../GCode/ThumbnailData.hpp"
@@ -247,6 +248,8 @@ static constexpr const char* BUILD_TAG = "build";
static constexpr const char* ITEM_TAG = "item";
static constexpr const char* METADATA_TAG = "metadata";
static constexpr const char* FILAMENT_TAG = "filament";
static constexpr const char* MIXED_FILAMENT_TAG = "mixed_filament";
static constexpr const char* MIXED_FILAMENT_COMPONENTS_TAG = "components";
static constexpr const char* SLICE_WARNING_TAG = "warning";
static constexpr const char* WARNING_MSG_TAG = "msg";
static constexpr const char *FILAMENT_ID_TAG = "id";
@@ -1316,6 +1319,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
bool _handle_end_config_metadata();
bool _handle_start_config_filament(const char** attributes, unsigned int num_attributes);
bool _handle_start_config_mixed_filament(const char** attributes, unsigned int num_attributes);
bool _handle_end_config_filament();
bool _handle_start_config_warning(const char** attributes, unsigned int num_attributes);
@@ -2703,6 +2707,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return;
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", load project config file successfully from %1%\n") %dest_file;
// Heal any gradient-curve slots corrupted by the legacy "|" separator collision
// (see FilamentMixer::sanitize_mixed_gradient_curve_array). The 3MF JSON itself
// is safe (";" + C-style escape), but older projects saved through the buggy
// export_selections/load_selections path may already carry single-point entries
// that fail MakerWorld's "curve needs >= 2 points" check.
if (auto* curve_opt = config.option<ConfigOptionStrings>("filament_mixed_gradient_curve"))
Slic3r::sanitize_mixed_gradient_curve_array(curve_opt->values);
}
}
@@ -3520,6 +3532,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
res = _handle_start_config_plater_instance(attributes, num_attributes);
else if (::strcmp(FILAMENT_TAG, name) == 0)
res = _handle_start_config_filament(attributes, num_attributes);
else if (::strcmp(MIXED_FILAMENT_TAG, name) == 0)
res = _handle_start_config_mixed_filament(attributes, num_attributes);
else if (::strcmp(SLICE_WARNING_TAG, name) == 0)
res = _handle_start_config_warning(attributes, num_attributes);
else if (::strcmp(NOZZLE_TAG, name) == 0)
@@ -4693,6 +4707,23 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return true;
}
bool _BBS_3MF_Importer::_handle_start_config_mixed_filament(const char** attributes, unsigned int num_attributes)
{
if (m_curr_plater) {
std::string id = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_ID_TAG);
std::string type = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_TYPE_TAG);
std::string color = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_COLOR_TAG);
std::string components = bbs_get_attribute_value_string(attributes, num_attributes, MIXED_FILAMENT_COMPONENTS_TAG);
PlateMixedFilamentInfo mixed_info;
mixed_info.id = atoi(id.c_str());
mixed_info.type = type;
mixed_info.color = color;
mixed_info.components = components;
m_curr_plater->mixed_filaments_info.push_back(mixed_info);
}
return true;
}
bool _BBS_3MF_Importer::_handle_end_config_filament()
{
// do nothing
@@ -8516,6 +8547,17 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
<< FILAMENT_USED_FOR_SUPPORT << "=\"" << std::boolalpha << it->used_for_support << "\"/>\n";
}
// Mixed (virtual) filaments used by this plate. These are resolved to physical
// components before g-code statistics, so they are not present in the <filament>
// list above and are recorded separately here.
for (auto it = plate_data->mixed_filaments_info.begin(); it != plate_data->mixed_filaments_info.end(); it++)
{
stream << " <" << MIXED_FILAMENT_TAG << " " << FILAMENT_ID_TAG << "=\"" << std::to_string(it->id) << "\" "
<< FILAMENT_TYPE_TAG << "=\"" << it->type << "\" "
<< FILAMENT_COLOR_TAG << "=\"" << it->color << "\" "
<< MIXED_FILAMENT_COMPONENTS_TAG << "=\"" << it->components << "\"/>\n";
}
for (auto it = plate_data->warnings.begin(); it != plate_data->warnings.end(); it++) {
stream << " <" << SLICE_WARNING_TAG << " msg=\"" << it->msg << "\" level=\"" << std::to_string(it->level) << "\" error_code =\"" << it->error_code << "\" />\n";
}
+14
View File
@@ -48,6 +48,18 @@ public:
};
// Mixed (virtual) filament used by a plate. Mixed filaments are virtual slots that get
// resolved to their physical components before g-code statistics, so they never appear in
// slice_filaments_info. They are recorded here separately so a plate's mixed-color usage
// can be recovered from slice_info.
struct PlateMixedFilamentInfo
{
int id{0}; // 1-based virtual filament slot id
std::string type;
std::string color; // blended display color, "#RRGGBB"
std::string components; // 1-based physical component ids, comma separated, e.g. "1,3"
};
//BBS: define plate data list related structures
struct PlateData
{
@@ -89,6 +101,8 @@ struct PlateData
std::string first_layer_time;
std::string plate_name;
std::vector<FilamentInfo> slice_filaments_info;
// Mixed (virtual) filaments used by this plate; empty when no mixed filament is used.
std::vector<PlateMixedFilamentInfo> mixed_filaments_info;
std::vector<size_t> skipped_objects;
DynamicPrintConfig config;
bool is_support_used {false};
+106 -7
View File
@@ -262,12 +262,9 @@ static bool obj_parseline(const char *line, ObjData &data)
}
face_index_count++;
}
if (face_index_count == 3) {//tri
data.usemtls.back().face_end++;
} else if (face_index_count == 4) {//quad
data.usemtls.back().face_end++;
data.usemtls.back().face_end++;
}
if (face_index_count >= 3) {
data.usemtls.back().face_end += face_index_count - 2;
}
}
vertex.coordIdx = -1;
vertex.normalIdx = -1;
@@ -374,6 +371,107 @@ static bool obj_parseline(const char *line, ObjData &data)
return true;
}
static std::string cur_mtl_name = "";
static bool mtl_is_space(char c)
{
return c == ' ' || c == '\t' || c == '\r';
}
static const char* mtl_skip_ws(const char *line)
{
while (mtl_is_space(*line))
++line;
return line;
}
static const char* mtl_skip_token(const char *line)
{
while (*line != 0 && !mtl_is_space(*line))
++line;
return line;
}
static bool mtl_token_equals(const char *begin, const char *end, const char *token)
{
const size_t len = static_cast<size_t>(end - begin);
return strlen(token) == len && strncmp(begin, token, len) == 0;
}
static std::string mtl_trim_value(const char *line)
{
const char *begin = mtl_skip_ws(line);
const char *end = begin + strlen(begin);
while (end > begin && mtl_is_space(*(end - 1)))
--end;
return std::string(begin, end);
}
static bool mtl_skip_numeric_token(const char *&line)
{
const char *begin = mtl_skip_ws(line);
if (*begin == 0)
return false;
char *endptr = 0;
strtod(begin, &endptr);
if (endptr == begin || (!mtl_is_space(*endptr) && *endptr != 0))
return false;
line = mtl_skip_ws(endptr);
return true;
}
static bool mtl_skip_required_tokens(const char *&line, int count)
{
for (int i = 0; i < count; ++i) {
line = mtl_skip_ws(line);
if (*line == 0)
return false;
line = mtl_skip_token(line);
}
line = mtl_skip_ws(line);
return true;
}
static std::string mtl_parse_texture_name(const char *line)
{
const char *original = mtl_skip_ws(line);
const char *current = original;
while (*current == '-') {
const char *option_begin = current;
const char *option_end = mtl_skip_token(current);
current = option_end;
if (mtl_token_equals(option_begin, option_end, "-o") ||
mtl_token_equals(option_begin, option_end, "-s") ||
mtl_token_equals(option_begin, option_end, "-t")) {
int skipped = 0;
while (skipped < 3 && mtl_skip_numeric_token(current))
++skipped;
if (skipped == 0)
return mtl_trim_value(original);
continue;
}
int option_args = -1;
if (mtl_token_equals(option_begin, option_end, "-mm"))
option_args = 2;
else if (mtl_token_equals(option_begin, option_end, "-bm") ||
mtl_token_equals(option_begin, option_end, "-boost") ||
mtl_token_equals(option_begin, option_end, "-texres") ||
mtl_token_equals(option_begin, option_end, "-clamp") ||
mtl_token_equals(option_begin, option_end, "-blendu") ||
mtl_token_equals(option_begin, option_end, "-blendv") ||
mtl_token_equals(option_begin, option_end, "-cc") ||
mtl_token_equals(option_begin, option_end, "-imfchan") ||
mtl_token_equals(option_begin, option_end, "-type"))
option_args = 1;
if (option_args < 0 || !mtl_skip_required_tokens(current, option_args))
return mtl_trim_value(original);
}
return mtl_trim_value(current);
}
static bool mtl_parseline(const char *line, MtlData &data)
{
if (*line == 0) return true;
@@ -394,13 +492,14 @@ static bool mtl_parseline(const char *line, MtlData &data)
ObjNewMtl new_mtl;
cur_mtl_name = line;
data.new_mtl_unmap[cur_mtl_name] = std::make_shared<ObjNewMtl>();
data.mtl_orders.emplace_back(cur_mtl_name);
break;
}
case 'm': {
if (*(line++) != 'a' || *(line++) != 'p' || *(line++) != '_' || *(line++) != 'K' || *(line++) != 'd') return false;
EATWS();
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->map_Kd = line;
data.new_mtl_unmap[cur_mtl_name]->map_Kd = mtl_parse_texture_name(line);
}
break;
}
+3
View File
@@ -122,6 +122,9 @@ struct MtlData
// Version of the data structure for load / store in the private binary format.
int version;
std::unordered_map<std::string, std::shared_ptr<ObjNewMtl>> new_mtl_unmap;
// Material names in declaration order. new_mtl_unmap is unordered, but OBJ material
// indices are positional, so texture import needs the original order.
std::vector<std::string> mtl_orders;
};
extern bool objparse(const char *path, ObjData &data);
extern bool mtlparse(const char *path, MtlData &data);
+361 -8
View File
@@ -4195,6 +4195,8 @@ void GCode::export_layer_filaments(GCodeProcessorResult* result)
}
}
result->used_mixed_filaments = m_print->get_slice_used_mixed_filaments();
result->optimal_assignment.clear();
result->optimal_assignment.reserve(filament_map.size());
for (int nozzle_id : filament_map)
@@ -6004,9 +6006,16 @@ LayerResult GCode::process_layer(
const WipingExtrusions::ExtruderPerCopy *entity_overrides = nullptr;
if (! layer_tools.has_extruder(correct_extruder_id)) {
// this entity is not overridden, but its extruder is not in layer_tools - we'll print it
// by last extruder on this layer (could happen e.g. when a wiping object is taller than others - dontcare extruders are eradicated from layer_tools)
correct_extruder_id = layer_tools.extruders.back();
// A mixed-color slot is absent from layer_tools.extruders by design:
// resolve_mixed_filaments() replaced it with its physical components,
// and the sublayer block emits its geometry separately. Reassigning it
// to the last extruder here would print it in the wrong colour, so only
// fall back for genuinely stale (dontcare) extruders.
if (!layer_tools.is_mixed_slot(correct_extruder_id)) {
// this entity is not overridden, but its extruder is not in layer_tools - we'll print it
// by last extruder on this layer (could happen e.g. when a wiping object is taller than others - dontcare extruders are eradicated from layer_tools)
correct_extruder_id = layer_tools.extruders.back();
}
}
printing_extruders.clear();
if (is_anything_overridden && use_overrides) {
@@ -6094,7 +6103,16 @@ LayerResult GCode::process_layer(
const bool island_level_ordering = print.config().print_sequence != PrintSequence::ByObject &&
single_object_instance_idx == size_t(-1) &&
print.config().print_order != PrintOrder::AsObjectList;
for (unsigned int filament_id : layer_tools.extruders) {
// A mixed-color slot is absent from layer_tools.extruders by design: resolve_mixed_filaments()
// replaced it with its physical components. Its geometry is still keyed under the slot in
// by_extruder though, and the sublayer emitter looks the plan up by slot id, so append the
// slots here. Appending rather than merging leaves the flush-optimized order untouched.
std::vector<unsigned int> plan_filaments = layer_tools.extruders;
for (const auto &grp : layer_tools.mixed_sub_layer_groups)
if (std::find(plan_filaments.begin(), plan_filaments.end(), grp.mixed_slot_0based) == plan_filaments.end())
plan_filaments.push_back(grp.mixed_slot_0based);
for (unsigned int filament_id : plan_filaments) {
auto objects_by_extruder_it = by_extruder.find(filament_id);
if (objects_by_extruder_it == by_extruder.end()) continue;
@@ -6275,8 +6293,22 @@ LayerResult GCode::process_layer(
}
if (print.config().print_sequence == PrintSequence::ByLayer && m_enable_exclude_object && print.config().support_object_skip_flush.value) {
std::vector<size_t> filament_instances_id;
for (InstanceToPrint &instance : filament_to_print_instances[extruder_id].first) filament_instances_id.emplace_back(instance.label_object_id);
std::set<size_t> all_label_ids;
for (InstanceToPrint &instance : filament_to_print_instances[extruder_id].first)
all_label_ids.insert(instance.label_object_id);
// This extruder may also be printing sub-layers on behalf of a mixed slot, whose
// instances live under the slot id. Their labels belong in the same skip set, or
// exclude-object would not skip that geometry.
for (const auto &grp : layer_tools.mixed_sub_layer_groups)
for (unsigned int comp : grp.components_0based)
if (comp == extruder_id) {
auto mit = filament_to_print_instances.find(grp.mixed_slot_0based);
if (mit != filament_to_print_instances.end())
for (const InstanceToPrint &inst : mit->second.first)
all_label_ids.insert(inst.label_object_id);
break;
}
std::vector<size_t> filament_instances_id(all_label_ids.begin(), all_label_ids.end());
m_filament_instances_code = _encode_label_ids_to_base64(filament_instances_id);
}
@@ -6557,6 +6589,318 @@ LayerResult GCode::process_layer(
}
}
}
// Mixed-color sublayer extrusion: if this extruder is a component of a mixed sublayer
// group, extrude the mixed slot's geometry at the appropriate sub-Z with scaled flow.
// Ported from BambuStudio and adapted to Orca's instance loop and its finer-grained
// per-role region filament options.
for (const auto &grp : layer_tools.mixed_sub_layer_groups) {
int sub_idx = -1;
for (size_t k = 0; k < grp.components_0based.size(); ++k) {
if (grp.components_0based[k] == extruder_id) {
sub_idx = static_cast<int>(k);
break;
}
}
if (sub_idx < 0)
continue;
auto mixed_instances_it = filament_to_print_instances.find(grp.mixed_slot_0based);
if (mixed_instances_it == filament_to_print_instances.end() || mixed_instances_it->second.first.empty())
continue;
double lh = grp.layer_height > 0. ? grp.layer_height : static_cast<double>(height);
double cumulative_h = 0.0;
for (int i = 0; i < sub_idx; ++i)
cumulative_h += grp.sub_heights[i];
double default_sub_h = grp.sub_heights[sub_idx];
double default_sub_z = print_z - lh + cumulative_h + default_sub_h;
m_sub_layer_flow_ratio = default_sub_h / lh;
m_sub_layer_height = default_sub_h;
m_nominal_z = default_sub_z;
gcode += this->set_extruder(extruder_id, default_sub_z);
for (InstanceToPrint &instance_to_print : mixed_instances_it->second.first) {
const bool use_per_volume = grp.is_gradient
&& !grp.per_volume_gradient.empty()
&& std::any_of(grp.per_volume_gradient.begin(), grp.per_volume_gradient.end(),
[&](const auto &kv) { return kv.first.obj == &instance_to_print.print_object; });
// --- Shared instance preamble (mirrors Orca's main instance loop) ---
const LayerToPrint &layer_to_print = layers[instance_to_print.layer_id];
const auto &inst = instance_to_print.print_object.instances()[instance_to_print.instance_id];
bool object_layer_over_raft = layer_to_print.object_layer && layer_to_print.object_layer->id() > 0 &&
instance_to_print.print_object.slicing_parameters().raft_layers() == layer_to_print.object_layer->id();
m_config.apply(print.default_region_config());
m_config.apply(instance_to_print.print_object.config(), true);
m_layer = layer_to_print.layer();
m_object_layer_over_raft = object_layer_over_raft;
if (m_config.reduce_crossing_wall)
m_avoid_crossing_perimeters.init_layer(*m_layer);
if (this->config().gcode_label_objects) {
gcode += std::string("; printing object ") + instance_to_print.print_object.model_object()->name +
" id:" + std::to_string(instance_to_print.print_object.get_id()) + " copy " +
std::to_string(inst.id) + "\n";
}
if (m_enable_exclude_object) {
if (is_BBL_Printer()) {
m_writer.set_object_start_str(
std::string("; start printing object, unique label id: ") +
std::to_string(instance_to_print.label_object_id) + "\n" + "M624 " +
_encode_label_ids_to_base64({instance_to_print.label_object_id}) + "\n");
} else {
const auto gflavor = print.config().gcode_flavor.value;
if (gflavor == gcfKlipper) {
m_writer.set_object_start_str(std::string("EXCLUDE_OBJECT_START NAME=") +
get_instance_name(&instance_to_print.print_object, inst.id) + "\n");
} else if (gflavor == gcfMarlinLegacy || gflavor == gcfMarlinFirmware || gflavor == gcfRepRapFirmware) {
m_writer.set_object_start_str(std::string("M486 S") + std::to_string(inst.unique_id) + "\n");
}
}
}
m_extrusion_quality_estimator.set_current_object(&instance_to_print.print_object);
const Point &offset = inst.shift;
std::pair<const PrintObject*, Point> this_object_copy(&instance_to_print.print_object, offset);
if (m_last_obj_copy != this_object_copy)
m_avoid_crossing_perimeters.use_external_mp_once();
m_last_obj_copy = this_object_copy;
this->set_origin(unscale(offset));
// --- Build emission plan ---
// Each entry represents one travel_to_z + extrude pass. Per-object mode produces
// exactly 1 entry (all regions, single sub_z); per-volume mode produces N entries
// for tagged volumes plus an optional entry for untagged residue.
struct SubLayerEmitEntry {
double sub_h;
double sub_z;
std::function<bool(size_t region_idx)> region_filter;
bool skip = false;
};
std::vector<SubLayerEmitEntry> emit_plan;
auto compute_sub_zh = [&](double r1, double r2, double &out_sub_h, double &out_sub_z) {
std::vector<double> sub_heights_local(grp.components_0based.size());
for (size_t ci = 0; ci < grp.components_0based.size(); ++ci)
sub_heights_local[ci] = (static_cast<int>(ci) == grp.gradient_first_sorted_idx) ? r1 * lh : r2 * lh;
double cum = 0.0;
for (int ci = 0; ci < sub_idx; ++ci)
cum += sub_heights_local[ci];
out_sub_h = sub_heights_local[sub_idx];
out_sub_z = print_z - lh + cum + out_sub_h;
};
auto gradient_ratios = [](const auto &g) -> std::pair<double, double> {
double t = (g.total_layers > 0) ? (2.0 * g.current_idx + 1.0) / (2.0 * g.total_layers) : 0.5;
// Custom curve wins over linear range when present; OFF path stays bit-identical.
double r1 = g.curve.empty()
? (g.gradient_start + (g.gradient_end - g.gradient_start) * t)
: sample_gradient_curve(g.curve, t);
return {r1, 1.0 - r1};
};
// Orca splits BBS's three role filaments into five; a region belongs to the slot
// when any of its roles is assigned to it.
auto region_uses_slot = [](const PrintRegionConfig &rcfg, unsigned int slot_1b) {
return (unsigned int)rcfg.outer_wall_filament_id.value == slot_1b
|| (unsigned int)rcfg.inner_wall_filament_id.value == slot_1b
|| (unsigned int)rcfg.sparse_infill_filament_id.value == slot_1b
|| (unsigned int)rcfg.internal_solid_filament_id.value == slot_1b
|| (unsigned int)rcfg.top_surface_filament_id.value == slot_1b
|| (unsigned int)rcfg.bottom_surface_filament_id.value == slot_1b;
};
double obj_sub_z = default_sub_z;
if (use_per_volume) {
const PrintObject *po = &instance_to_print.print_object;
const unsigned int slot_1b = grp.mixed_slot_0based + 1;
// Discover tagged volumes and untagged presence for this instance.
std::set<ObjectID> tagged_volumes_present;
bool has_untagged_for_slot = false;
for (ObjectByExtruder::Island &island : instance_to_print.object_by_extruder.islands) {
for (size_t r = 0; r < island.by_region.size(); ++r) {
const auto &region = island.by_region[r];
if (region.perimeters.empty() && region.infills.empty())
continue;
const PrintRegion &pr = print.get_print_region(r);
if (!region_uses_slot(pr.config(), slot_1b))
continue;
ObjectID vid = pr.gradient_volume_id();
if (vid.valid())
tagged_volumes_present.insert(vid);
else
has_untagged_for_slot = true;
}
}
// One entry per tagged volume.
for (const ObjectID &target_vid : tagged_volumes_present) {
auto vg_it = grp.per_volume_gradient.find({po, target_vid});
if (vg_it == grp.per_volume_gradient.end())
continue;
const auto &vg = vg_it->second;
auto [r1, r2] = gradient_ratios(vg);
bool vol_no_split = false;
bool skip_entry = false;
const size_t n = grp.components_0based.size();
if (n == 2 && vg.current_idx + 1 == vg.total_layers) {
const size_t dom_idx = (r1 >= r2) ? 0 : 1;
const unsigned int first_sorted_comp = grp.components_0based[grp.gradient_first_sorted_idx];
const unsigned int other_comp = grp.components_0based[1 - grp.gradient_first_sorted_idx];
const unsigned int dom_0b = (dom_idx == 0) ? first_sorted_comp : other_comp;
const unsigned int oth_0b = (dom_idx == 0) ? other_comp : first_sorted_comp;
if (dom_0b < oth_0b) {
vol_no_split = true;
if (extruder_id != dom_0b)
skip_entry = true;
}
}
double vol_sub_h = default_sub_h;
double vol_sub_z = default_sub_z;
if (vol_no_split) {
vol_sub_h = lh;
vol_sub_z = print_z;
} else {
compute_sub_zh(r1, r2, vol_sub_h, vol_sub_z);
}
emit_plan.push_back({vol_sub_h, vol_sub_z,
[target_vid, &print](size_t r) {
return print.get_print_region(r).gradient_volume_id() == target_vid;
},
skip_entry});
}
// Optional entry for untagged regions (modifier / painted / fuzzy_skin).
if (has_untagged_for_slot) {
double obj_sub_h = default_sub_h;
auto og_it = grp.per_object_gradient.find(po);
if (og_it != grp.per_object_gradient.end()) {
auto [r1, r2] = gradient_ratios(og_it->second);
compute_sub_zh(r1, r2, obj_sub_h, obj_sub_z);
}
emit_plan.push_back({obj_sub_h, obj_sub_z,
[&print](size_t r) {
return !print.get_print_region(r).gradient_volume_id().valid();
},
false});
}
} else {
// Legacy per-object path: single entry, no region filter.
double legacy_sub_h = default_sub_h;
obj_sub_z = default_sub_z;
if (grp.is_gradient) {
auto og_it = grp.per_object_gradient.find(&instance_to_print.print_object);
if (og_it != grp.per_object_gradient.end()) {
auto [r1, r2] = gradient_ratios(og_it->second);
compute_sub_zh(r1, r2, legacy_sub_h, obj_sub_z);
}
}
emit_plan.push_back({legacy_sub_h, obj_sub_z, nullptr, false});
}
// --- Unified emission loop ---
auto plan_has_infill = [](const std::vector<ObjectByExtruder::Island::Region> &by_region) {
for (const auto &r : by_region)
if (!r.infills.empty())
return true;
return false;
};
for (auto &entry : emit_plan) {
if (entry.skip)
continue;
m_sub_layer_flow_ratio = entry.sub_h / lh;
m_sub_layer_height = entry.sub_h;
m_nominal_z = entry.sub_z;
// Use the same lazy-Z mechanism as change_layer(): set the flag so travel_to
// fires even when m_last_pos coincides with the first extrusion point,
// ensuring Z reaches sub_z via the combined XY+Z move.
m_need_change_layer_lift_z = true;
for (ObjectByExtruder::Island &island : instance_to_print.object_by_extruder.islands) {
const auto &src = island.by_region;
std::vector<ObjectByExtruder::Island::Region> subset_storage;
if (entry.region_filter) {
subset_storage.resize(src.size());
for (size_t r = 0; r < src.size(); ++r)
if (entry.region_filter(r))
subset_storage[r] = src[r];
}
const auto &by_region_specific = entry.region_filter ? subset_storage : src;
// Orca resolves infill-first per region inside extrude_perimeters()
// (unlike BBS, which branches on a single global flag), so mirror the
// main instance loop's ordering exactly.
gcode += this->extrude_perimeters(print, by_region_specific, first_layer, false);
if (!has_wipe_tower && need_insert_timelapse_gcode_for_traditional
&& printer_structure == PrinterStructure::psI3
&& !has_insert_timelapse_gcode && plan_has_infill(by_region_specific)) {
gcode += this->retract(false, false, auto_lift_type, true);
gcode += insert_timelapse_gcode();
has_insert_timelapse_gcode = true;
}
gcode += this->extrude_infill(print, by_region_specific, false);
gcode += this->extrude_perimeters(print, by_region_specific, first_layer, true);
// ironing
gcode += this->extrude_infill(print, by_region_specific, true);
}
}
// --- Shared support ---
if (instance_to_print.object_by_extruder.support && !instance_to_print.object_by_extruder.support->empty()) {
if (use_per_volume) {
m_nominal_z = obj_sub_z;
m_need_change_layer_lift_z = true;
}
ExtrusionRole support_role = instance_to_print.object_by_extruder.support_extrusion_role;
gcode += this->extrude_support(*instance_to_print.object_by_extruder.support, support_role);
// Make sure ironing is the last (Orca names this role erIroning, not erSupportIroning).
if (support_role == erMixed || support_role == erSupportMaterialInterface)
gcode += this->extrude_support(*instance_to_print.object_by_extruder.support, erIroning);
}
// --- Shared instance footer (mirrors Orca's main instance loop) ---
if (!m_writer.is_object_start_str_empty()) {
m_writer.set_object_start_str("");
} else if (m_enable_exclude_object) {
if (is_BBL_Printer()) {
m_writer.set_object_end_str(std::string("; stop printing object, unique label id: ") +
std::to_string(instance_to_print.label_object_id) + "\n" +
"M625\n");
} else {
const auto gflavor = print.config().gcode_flavor.value;
if (gflavor == gcfKlipper) {
m_writer.set_object_end_str(std::string("EXCLUDE_OBJECT_END NAME=") +
get_instance_name(&instance_to_print.print_object, inst.id) + "\n");
} else if (gflavor == gcfMarlinLegacy || gflavor == gcfMarlinFirmware || gflavor == gcfRepRapFirmware) {
m_writer.set_object_end_str(std::string("M486 S-1\n"));
}
}
}
}
m_sub_layer_flow_ratio = 0.0;
m_sub_layer_height = 0.0;
}
// Flush any pending object end label before leaving the sublayer block, otherwise the
// wipe tower's add_object_end_labels may consume it into a local temp string and the
// M625 would be lost for BBL printers.
if (!layer_tools.mixed_sub_layer_groups.empty()) {
m_writer.add_object_end_labels(gcode);
m_nominal_z = print_z;
m_need_change_layer_lift_z = true;
}
}
if (first_layer) {
for (auto iter = by_extruder.begin(); iter != by_extruder.end(); ++iter) {
@@ -7634,6 +7978,15 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
}
}
// Mixed-color sublayer: this path belongs to one sub-layer of a split layer, so scale the
// flow down to that sub-layer's share of the nominal layer height and report the sub-height
// as the effective extrusion height. Inert (ratio == 0) outside the sublayer emission block.
float effective_height = path.height;
if (m_sub_layer_flow_ratio > 0.0) {
_mm3_per_mm *= m_sub_layer_flow_ratio;
effective_height = static_cast<float>(m_sub_layer_height);
}
// Effective extrusion length per distance unit = (filament_flow_ratio/cross_section) * mm3_per_mm / print flow ratio
// m_writer.extruder()->e_per_mm3() below is (filament flow ratio / cross-sectional area)
double e_per_mm = m_writer.filament()->e_per_mm3() * _mm3_per_mm;
@@ -7933,8 +8286,8 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
gcode += buf;
}
if (last_was_wipe_tower || std::abs(m_last_height - path.height) > EPSILON) {
m_last_height = path.height;
if (last_was_wipe_tower || std::abs(m_last_height - effective_height) > EPSILON) {
m_last_height = effective_height;
sprintf(buf, ";%s%g\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height).c_str(), m_last_height);
gcode += buf;
}
+5
View File
@@ -747,6 +747,11 @@ private:
Print* m_curr_print = nullptr;
unsigned int m_toolchange_count;
coordf_t m_nominal_z;
// Mixed-color sublayer state. Non-zero only while emitting a mixed slot's sub-layer:
// scales extrusion flow to the sub-layer's share of the nominal layer height, and
// reports that sub-height as the effective extrusion height. Reset to 0 afterwards.
double m_sub_layer_flow_ratio = 0.0;
double m_sub_layer_height = 0.0;
bool m_need_change_layer_lift_z = false;
int m_start_gcode_filament = -1;
std::string m_filament_instances_code;
+135 -20
View File
@@ -298,6 +298,7 @@ void GCodeProcessor::TimeMachine::State::reset()
//BBS
enter_direction = { 0.0f, 0.0f, 0.0f };
exit_direction = { 0.0f, 0.0f, 0.0f };
jd_unit_vec = { 0.0f, 0.0f, 0.0f, 0.0f };
}
void GCodeProcessor::TimeMachine::CustomGCodeTime::reset()
@@ -2542,6 +2543,7 @@ void GCodeProcessorResult::reset() {
spiral_vase_mode = false;
layer_filaments.clear();
filament_change_sequence.clear();
used_mixed_filaments.clear();
nozzle_change_sequence.clear();
optimal_assignment.clear();
filament_change_count_map.clear();
@@ -5036,6 +5038,10 @@ void GCodeProcessor::process_G1(const std::array<std::optional<double>, 4>& axes
if (!is_extrusion_only_move(delta_pos))
curr.enter_direction = curr.enter_direction / norm;
curr.exit_direction = curr.enter_direction;
curr.jd_unit_vec = Vec4f(static_cast<float>(delta_pos[X]),
static_cast<float>(delta_pos[Y]),
static_cast<float>(delta_pos[Z]),
static_cast<float>(delta_pos[E])).normalized();
TimeBlock block;
block.move_type = type;
@@ -5118,22 +5124,32 @@ void GCodeProcessor::process_G1(const std::array<std::optional<double>, 4>& axes
block.acceleration = acceleration;
// calculates block exit feedrate
curr.safe_feedrate = block.feedrate_profile.cruise;
static const float PREVIOUS_FEEDRATE_THRESHOLD = 0.0001f;
const bool has_prev_move = !blocks.empty() && prev.feedrate > PREVIOUS_FEEDRATE_THRESHOLD;
for (unsigned char a = X; a <= E; ++a) {
float axis_max_jerk = get_axis_max_jerk(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
if (curr.abs_axis_feedrate[a] > axis_max_jerk)
curr.safe_feedrate = std::min(curr.safe_feedrate, axis_max_jerk);
// Orca: junction deviation where the firmware uses it (Klipper always, Marlin 2 with M205 J).
// Negative leaves the classic jerk path below unchanged.
const float vmax_junction_jd = calc_vmax_junction_deviation(block, prev, curr, has_prev_move,
static_cast<PrintEstimatedStatistics::ETimeMode>(i));
const bool use_junction_deviation = vmax_junction_jd >= 0.0f;
// calculates block exit feedrate. Junction deviation has no per axis jerk floor, so a move is
// free to start from rest.
curr.safe_feedrate = use_junction_deviation ? 0.0f : block.feedrate_profile.cruise;
if (!use_junction_deviation) {
for (unsigned char a = X; a <= E; ++a) {
float axis_max_jerk = get_axis_max_jerk(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
if (curr.abs_axis_feedrate[a] > axis_max_jerk)
curr.safe_feedrate = std::min(curr.safe_feedrate, axis_max_jerk);
}
}
block.feedrate_profile.exit = curr.safe_feedrate;
static const float PREVIOUS_FEEDRATE_THRESHOLD = 0.0001f;
// calculates block entry feedrate
float vmax_junction = curr.safe_feedrate;
if (!blocks.empty() && prev.feedrate > PREVIOUS_FEEDRATE_THRESHOLD) {
float vmax_junction = use_junction_deviation ? vmax_junction_jd : curr.safe_feedrate;
if (!use_junction_deviation && has_prev_move) {
bool prev_speed_larger = prev.feedrate > block.feedrate_profile.cruise;
float smaller_speed_factor = prev_speed_larger ? (block.feedrate_profile.cruise / prev.feedrate) : (prev.feedrate / block.feedrate_profile.cruise);
// Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting.
@@ -5400,6 +5416,10 @@ void GCodeProcessor::process_VG1(const GCodeReader::GCodeLine& line)
if (!is_extrusion_only_move(delta_pos))
curr.enter_direction = curr.enter_direction / norm;
curr.exit_direction = curr.enter_direction;
curr.jd_unit_vec = Vec4f(static_cast<float>(delta_pos[X]),
static_cast<float>(delta_pos[Y]),
static_cast<float>(delta_pos[Z]),
static_cast<float>(delta_pos[E])).normalized();
TimeBlock block;
block.move_type = type;
@@ -5480,22 +5500,32 @@ void GCodeProcessor::process_VG1(const GCodeReader::GCodeLine& line)
block.acceleration = acceleration;
// calculates block exit feedrate
curr.safe_feedrate = block.feedrate_profile.cruise;
static const float PREVIOUS_FEEDRATE_THRESHOLD = 0.0001f;
const bool has_prev_move = !blocks.empty() && prev.feedrate > PREVIOUS_FEEDRATE_THRESHOLD;
for (unsigned char a = X; a <= E; ++a) {
float axis_max_jerk = get_axis_max_jerk(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
if (curr.abs_axis_feedrate[a] > axis_max_jerk)
curr.safe_feedrate = std::min(curr.safe_feedrate, axis_max_jerk);
// Orca: junction deviation where the firmware uses it (Klipper always, Marlin 2 with M205 J).
// Negative leaves the classic jerk path below unchanged.
const float vmax_junction_jd = calc_vmax_junction_deviation(block, prev, curr, has_prev_move,
static_cast<PrintEstimatedStatistics::ETimeMode>(i));
const bool use_junction_deviation = vmax_junction_jd >= 0.0f;
// calculates block exit feedrate. Junction deviation has no per axis jerk floor, so a move is
// free to start from rest.
curr.safe_feedrate = use_junction_deviation ? 0.0f : block.feedrate_profile.cruise;
if (!use_junction_deviation) {
for (unsigned char a = X; a <= E; ++a) {
float axis_max_jerk = get_axis_max_jerk(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
if (curr.abs_axis_feedrate[a] > axis_max_jerk)
curr.safe_feedrate = std::min(curr.safe_feedrate, axis_max_jerk);
}
}
block.feedrate_profile.exit = curr.safe_feedrate;
static const float PREVIOUS_FEEDRATE_THRESHOLD = 0.0001f;
// calculates block entry feedrate
float vmax_junction = curr.safe_feedrate;
if (!blocks.empty() && prev.feedrate > PREVIOUS_FEEDRATE_THRESHOLD) {
float vmax_junction = use_junction_deviation ? vmax_junction_jd : curr.safe_feedrate;
if (!use_junction_deviation && has_prev_move) {
bool prev_speed_larger = prev.feedrate > block.feedrate_profile.cruise;
float smaller_speed_factor = prev_speed_larger ? (block.feedrate_profile.cruise / prev.feedrate) : (prev.feedrate / block.feedrate_profile.cruise);
// Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting.
@@ -7168,6 +7198,91 @@ float GCodeProcessor::get_axis_max_jerk_with_jd(PrintEstimatedStatistics::ETimeM
return get_axis_max_jerk_with_jd(mode, axis, get_acceleration(mode));
}
float GCodeProcessor::get_junction_deviation(PrintEstimatedStatistics::ETimeMode mode, float acceleration) const
{
const size_t id = static_cast<size_t>(mode);
// Klipper has no classic jerk: jd = scv^2 * (sqrt(2) - 1) / max_accel
// (toolhead.py::_calc_junction_deviation). Passing the block acceleration back in makes it cancel
// in calc_vmax_junction_deviation(), leaving the identity v == scv at a 90 degree corner.
if (m_flavor == gcfKlipper) {
// machine_max_jerk_x holds the square corner velocity; process_SET_VELOCITY_LIMIT() writes it.
const float scv = get_option_value(m_time_processor.machine_limits.machine_max_jerk_x, id);
if (scv <= 0.0f || acceleration <= 0.0f)
return 0.0f;
return sqr(scv) * (std::sqrt(2.0f) - 1.0f) / acceleration;
}
// Marlin 2 plans with junction deviation only when M205 J > 0; classic jerk leaves it at 0.
if (m_flavor == gcfMarlinFirmware)
return get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, id);
return 0.0f;
}
float GCodeProcessor::calc_junction_acceleration(const TimeBlock& block, const Vec4f& junction_unit_vec,
PrintEstimatedStatistics::ETimeMode mode) const
{
float junction_acceleration = block.acceleration;
for (unsigned char a = X; a <= E; ++a) {
if (junction_unit_vec[a] == 0.0f)
continue;
const float axis_max_acceleration = get_axis_max_acceleration(mode, static_cast<Axis>(a), m_machine_config_idx);
if (axis_max_acceleration > 0.0f)
junction_acceleration = std::min(junction_acceleration, std::abs(axis_max_acceleration / junction_unit_vec[a]));
}
return junction_acceleration;
}
// Ported from PrusaSlicer (src/libslic3r/GCode/GCodeProcessor.cpp).
float GCodeProcessor::calc_vmax_junction_deviation(const TimeBlock& block, const TimeMachine::State& prev,
const TimeMachine::State& curr, bool has_prev_move,
PrintEstimatedStatistics::ETimeMode mode) const
{
const float junction_deviation = get_junction_deviation(mode, block.acceleration);
if (junction_deviation <= 0.0f)
return -1.0f; // classic jerk machine, the caller keeps its own computation
if (!has_prev_move)
return 0.0f; // starts from rest, the planner raises this on the reverse pass
// -1 for a straight continuation, +1 for a full reversal. Half angle identity, no acos()/sin().
// Both vectors are unit length over XYZE, so this really is a cosine: scaling by 1 / distance
// instead, as PrusaSlicer does, leaves an E term that makes extruding corners look straighter
// than they are. Marlin normalizes over XYZE for any extruding move (planner.cpp, esteps > 0)
// and Klipper keeps E out of the cosine entirely (toolhead.py::Move.calc_junction); both agree
// that the corner is planned by its geometry, and normalizing matches them to within 1e-5.
float junction_cos_theta = (-prev.jd_unit_vec).dot(curr.jd_unit_vec);
if (junction_cos_theta > 0.999999f)
return 0.0f; // the path doubles back, the machine has to stop
junction_cos_theta = std::max(junction_cos_theta, -0.999999f); // guards the division below
const float sin_theta_d2 = std::sqrt(0.5f * (1.0f - junction_cos_theta)); // always positive
const Vec4f junction_vec = curr.jd_unit_vec - prev.jd_unit_vec;
const float junction_vec_norm = junction_vec.norm();
const Vec4f junction_unit_vec = (junction_vec_norm > 0.0f) ? Vec4f(junction_vec / junction_vec_norm)
: Vec4f(0.0f, 0.0f, 0.0f, 0.0f);
const float junction_acceleration = calc_junction_acceleration(block, junction_unit_vec, mode);
float vmax_junction_sqr = (junction_acceleration * junction_deviation * sin_theta_d2) / (1.0f - sin_theta_d2);
// Marlin's JD_HANDLE_SMALL_SEGMENTS: a short move through a shallow corner is treated as an arc and
// capped by the centripetal acceleration it needs. Klipper has no equivalent.
if (m_flavor != gcfKlipper && block.distance < 1.0f && junction_cos_theta < -0.7071067812f) {
// Fast acos(-t), max. error +-0.033rad. MinMax polynomial by W. Randolph Franklin:
// https://wrf.ecse.rpi.edu/Research/Short_Notes/arcsin/onlyelem.html
const float neg = junction_cos_theta < 0.0f ? -1.0f : 1.0f;
const float t = neg * junction_cos_theta;
const float asinx = 0.032843707f + t * (-1.451838349f + t * (29.66153956f + t * (-131.1123477f +
t * (262.8130562f + t * (-242.7199627f + t * (84.31466202f))))));
const float junction_theta = float(0.5 * M_PI) + neg * asinx; // acos(-t), bottoms out at 0.033
vmax_junction_sqr = std::min(vmax_junction_sqr, (block.distance * junction_acceleration) / junction_theta);
}
// Never faster than either of the two moves the junction joins.
vmax_junction_sqr = std::min(vmax_junction_sqr, std::min(sqr(block.feedrate_profile.cruise), sqr(prev.feedrate)));
return std::sqrt(vmax_junction_sqr);
}
float GCodeProcessor::get_axis_max_jerk(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
{
const size_t id = static_cast<size_t>(mode);
+17
View File
@@ -306,6 +306,9 @@ class Print;
std::unordered_map<std::vector<unsigned int>, std::vector<std::pair<int, int>>,FilamentSequenceHash> layer_filaments;
std::vector<unsigned int> nozzle_change_sequence;
std::vector<unsigned int> filament_change_sequence;
// 0-based mixed (virtual) filament slots actually used on this plate.
// Recorded before resolve_mixed_filaments expands them to physical components.
std::vector<unsigned int> used_mixed_filaments;
std::vector<int> optimal_assignment;
// first key stores `from` filament, second keys stores the `to` filament
std::map<std::pair<int,int>, int > filament_change_count_map;
@@ -357,6 +360,7 @@ class Print;
printer_extruder_id = other.printer_extruder_id;
layer_filaments = other.layer_filaments;
filament_change_sequence = other.filament_change_sequence;
used_mixed_filaments = other.used_mixed_filaments;
nozzle_change_sequence = other.nozzle_change_sequence;
optimal_assignment = other.optimal_assignment;
filament_change_count_map = other.filament_change_count_map;
@@ -637,6 +641,9 @@ class Print;
//For line move, there are same. For arc move, there are different.
Vec3f enter_direction;
Vec3f exit_direction;
// Orca: move direction over all four axes, unit length. Used by
// calc_vmax_junction_deviation(); see there for why E is normalized in.
Vec4f jd_unit_vec;
void reset();
};
@@ -1488,6 +1495,16 @@ class Print;
float get_axis_max_acceleration(PrintEstimatedStatistics::ETimeMode mode, Axis axis, int machine_idx) const;
float get_axis_max_jerk_with_jd(PrintEstimatedStatistics::ETimeMode mode, Axis axis, float acceleration) const;
float get_axis_max_jerk_with_jd(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
// Orca: junction deviation for a block at the given acceleration, 0 for a classic jerk machine.
float get_junction_deviation(PrintEstimatedStatistics::ETimeMode mode, float acceleration) const;
// Orca: acceleration along the junction direction, clamped by the per axis limits.
float calc_junction_acceleration(const TimeBlock& block, const Vec4f& junction_unit_vec,
PrintEstimatedStatistics::ETimeMode mode) const;
// Orca: entry speed from the junction deviation model, which limits a corner by its angle alone
// and is therefore isotropic, unlike per axis jerk. Negative means classic jerk applies instead.
float calc_vmax_junction_deviation(const TimeBlock& block, const TimeMachine::State& prev,
const TimeMachine::State& curr, bool has_prev_move,
PrintEstimatedStatistics::ETimeMode mode) const;
float get_axis_max_jerk(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
Vec3f get_xyz_max_jerk(PrintEstimatedStatistics::ETimeMode mode) const;
float get_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode) const;
+1 -1
View File
@@ -32,7 +32,7 @@ using ThumbnailsList = std::vector<ThumbnailData>;
struct ThumbnailsParams
{
const Vec2ds sizes;
const Vec2ds sizes{};
bool printable_only;
bool parts_only;
bool show_bed;
+803 -5
View File
@@ -7,6 +7,8 @@
#include "GCode/ToolOrderUtils.hpp"
#include "FilamentGroupUtils.hpp"
#include "MultiNozzleUtils.hpp"
#include "FilamentMixer.hpp"
#include "LocalesUtils.hpp"
#include "Utils.hpp"
#include "I18N.hpp"
@@ -22,8 +24,13 @@
#endif
#include <cassert>
#include <cstdio>
#include <limits>
#include <algorithm>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <unordered_map>
#include <libslic3r.h>
@@ -84,22 +91,28 @@ bool check_filament_printable_after_group(const std::vector<unsigned int> &used_
}
// Return a zero based extruder from the region, or extruder_override if overriden.
// The region accessors below resolve mixed-color slots to the physical filament chosen for this
// layer by resolve_mixed_filaments(), because a virtual slot id is never a real tool. resolve_mixed()
// returns its argument unchanged for every filament that is not a mixed slot.
unsigned int LayerTools::wall_extruder_id(const PrintRegion &region) const
{
assert(region.config().outer_wall_filament_id.value > 0);
return ((this->extruder_override == 0) ? region.config().outer_wall_filament_id.value : this->extruder_override) - 1;
unsigned int result = ((this->extruder_override == 0) ? region.config().outer_wall_filament_id.value : this->extruder_override) - 1;
return resolve_mixed(result);
}
unsigned int LayerTools::sparse_infill_filament_id(const PrintRegion &region) const
{
assert(region.config().sparse_infill_filament_id.value > 0);
return ((this->extruder_override == 0) ? region.config().sparse_infill_filament_id.value : this->extruder_override) - 1;
unsigned int result = ((this->extruder_override == 0) ? region.config().sparse_infill_filament_id.value : this->extruder_override) - 1;
return resolve_mixed(result);
}
unsigned int LayerTools::internal_solid_filament_id(const PrintRegion &region) const
{
assert(region.config().internal_solid_filament_id.value > 0);
return ((this->extruder_override == 0) ? region.config().internal_solid_filament_id.value : this->extruder_override) - 1;
unsigned int result = ((this->extruder_override == 0) ? region.config().internal_solid_filament_id.value : this->extruder_override) - 1;
return resolve_mixed(result);
}
// Returns a zero based extruder this eec should be printed with, according to PrintRegion config or extruder_override if overriden.
@@ -135,7 +148,8 @@ unsigned int LayerTools::extruder(const ExtrusionEntityCollection &extrusions, c
} else
extruder = this->extruder_override;
return (extruder == 0) ? 0 : extruder - 1;
unsigned int result = (extruder == 0) ? 0 : extruder - 1;
return resolve_mixed(result);
}
static double calc_max_layer_height(const PrintConfig &config, double max_object_layer_height)
@@ -402,7 +416,9 @@ void ToolOrdering::sort_and_build_data(const Print& print, unsigned int first_ex
// if first extruder is -1, we can decide the first layer tool order before doing reorder function
// so we shouldn't reorder first layer in reorder function
bool reorder_first_layer = (first_extruder != (unsigned int)(-1));
this->resolve_mixed_filaments(print.config());
reorder_extruders_for_minimum_flush_volume(reorder_first_layer);
this->enforce_mixed_component_order();
m_sorted = true;
double max_layer_height = 0.;
@@ -422,6 +438,9 @@ void ToolOrdering::sort_and_build_data(const Print& print, unsigned int first_ex
this->fill_wipe_tower_partitions(print.config(), object_bottom_z, max_layer_height);
if (this->insert_wipe_tower_extruder()) {
reorder_extruders_for_minimum_flush_volume(reorder_first_layer);
// Orca reorders a second time here (BBS has no such path); re-enforce so the
// mixed sub-layer component order survives the extra pass.
this->enforce_mixed_component_order();
this->fill_wipe_tower_partitions(print.config(), object_bottom_z, max_layer_height);
}
@@ -433,7 +452,9 @@ void ToolOrdering::sort_and_build_data(const PrintObject& object , unsigned int
// if first extruder is -1, we can decide the first layer tool order before doing reorder function
// so we shouldn't reorder first layer in reorder function
bool reorder_first_layer = (first_extruder != (unsigned int)(-1));
this->resolve_mixed_filaments(object.print()->config());
reorder_extruders_for_minimum_flush_volume(reorder_first_layer);
this->enforce_mixed_component_order();
m_sorted = true;
double max_layer_height = calc_max_layer_height(object.print()->config(), object.config().layer_height);
@@ -441,6 +462,9 @@ void ToolOrdering::sort_and_build_data(const PrintObject& object , unsigned int
this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height, max_layer_height);
if (this->insert_wipe_tower_extruder()) {
reorder_extruders_for_minimum_flush_volume(reorder_first_layer);
// Orca reorders a second time here (BBS has no such path); re-enforce so the
// mixed sub-layer component order survives the extra pass.
this->enforce_mixed_component_order();
this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height, max_layer_height);
}
@@ -723,6 +747,38 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
it_per_layer_extruder_override = per_layer_extruder_switches.begin();
unsigned int extruder_override = 0;
// Pre-compute 1-based IDs of mixed filament slots for per-object tracking.
// mixed_slots_1based covers ALL mixed slots (needed by calc_slot_lh for
// accurate layer height when a slot skips layers). gradient_slots_1based
// and per_part_slots_1based are subsets for gradient-specific logic.
std::set<unsigned int> mixed_slots_1based;
std::set<unsigned int> gradient_slots_1based;
std::set<unsigned int> per_part_slots_1based;
{
const PrintConfig &cfg = object.print()->config();
const auto &is_mixed = cfg.filament_is_mixed.values;
const auto &grad_flags = cfg.filament_mixed_gradient.values;
const auto &per_part_flags = cfg.filament_mixed_gradient_per_part.values;
const auto &comp_strs = cfg.filament_mixed_components.values;
for (size_t i = 0; i < is_mixed.size(); ++i) {
if (!is_mixed[i])
continue;
auto comps = parse_mixed_components(i < comp_strs.size() ? comp_strs[i] : "");
if (comps.size() < 2)
continue;
mixed_slots_1based.insert(static_cast<unsigned int>(i + 1));
// Gradient/per-part are only defined for 2-component slots; keep their
// tracking limited to them (mirrors the is_gradient guard at resolve time).
if (comps.size() != 2)
continue;
if (i >= grad_flags.size() || !grad_flags[i])
continue;
gradient_slots_1based.insert(static_cast<unsigned int>(i + 1));
if (i < per_part_flags.size() && per_part_flags[i])
per_part_slots_1based.insert(static_cast<unsigned int>(i + 1));
}
}
// BBS: collect first layer extruders of an object's wall, which will be used by brim generator
int layerCount = 0;
std::vector<int> firstLayerExtruders;
@@ -732,6 +788,9 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
for (auto layer : object.layers()) {
LayerTools &layer_tools = this->tools_for_layer(layer->print_z);
m_object_all_layer_indices[&object].push_back(
static_cast<size_t>(&layer_tools - m_layer_tools.data()));
// Override extruder with the next
for (; it_per_layer_extruder_override != per_layer_extruder_switches.end() && it_per_layer_extruder_override->first < layer->print_z + EPSILON; ++ it_per_layer_extruder_override)
extruder_override = (int)it_per_layer_extruder_override->second;
@@ -739,6 +798,9 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
// Store the current extruder override (set to zero if no overriden), so that layer_tools.wiping_extrusions().is_overridable_and_mark() will use it.
layer_tools.extruder_override = extruder_override;
// Snapshot extruders before this object's regions to track new additions.
const size_t ext_snapshot = layer_tools.extruders.size();
// What extruders are required to print this object layer?
for (const LayerRegion *layerm : layer->regions()) {
const PrintRegion &region = layerm->region();
@@ -805,6 +867,54 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
if (has_internal_solid || has_top_solid_surface || has_bottom_surface || has_infill)
layer_tools.has_object = true;
}
// Record mixed slot usage for this object at this layer.
// All mixed slots are tracked (not just gradient) so that calc_slot_lh
// can compute accurate layer heights even when a slot skips layers.
if (!mixed_slots_1based.empty()) {
size_t layer_idx = static_cast<size_t>(&layer_tools - m_layer_tools.data());
std::set<unsigned int> seen;
for (size_t ei = ext_snapshot; ei < layer_tools.extruders.size(); ++ei) {
unsigned int ext_1based = layer_tools.extruders[ei];
if (mixed_slots_1based.count(ext_1based) && seen.insert(ext_1based).second)
m_mixed_object_layers[ext_1based - 1][&object].push_back(layer_idx);
}
}
// Per-part gradient: walk LayerRegions and record which (slot, ModelVolume) pairs
// contributed to this layer. Only regions tagged by PrintApply.cpp's get_create_region
// (i.e. gradient_volume_id().valid()) are considered, so this loop is a strict no-op
// unless per_part_gradient is enabled for at least one slot AND the corresponding
// ModelObject has >=2 model-part volumes using that slot. The per-object pass above is
// unaffected — both run the same layer's data through orthogonal containers.
if (!per_part_slots_1based.empty()) {
size_t layer_idx = static_cast<size_t>(&layer_tools - m_layer_tools.data());
std::set<std::pair<unsigned int, ObjectID>> vol_seen;
for (const LayerRegion *layerm : layer->regions()) {
if (layerm->slices.empty())
continue;
const PrintRegion &region = layerm->region();
ObjectID vol_id = region.gradient_volume_id();
if (! vol_id.valid())
continue;
const PrintRegionConfig &rcfg = region.config();
// Orca splits BBS's three role slots into five; cover them all so a mixed
// slot used by any role is tracked.
const unsigned int role_slots[5] = {
static_cast<unsigned int>(rcfg.outer_wall_filament_id.value),
static_cast<unsigned int>(rcfg.inner_wall_filament_id.value),
static_cast<unsigned int>(rcfg.sparse_infill_filament_id.value),
static_cast<unsigned int>(rcfg.top_surface_filament_id.value),
static_cast<unsigned int>(rcfg.bottom_surface_filament_id.value),
};
for (unsigned int ext_1based : role_slots) {
if (ext_1based >= 1
&& per_part_slots_1based.count(ext_1based)
&& vol_seen.insert({ext_1based, vol_id}).second)
m_gradient_volume_layers[ext_1based - 1][{&object, vol_id}].push_back(layer_idx);
}
}
}
layerCount++;
}
@@ -903,7 +1013,7 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_
//FIXME this is a hack to get the ball rolling.
for (LayerTools &lt : m_layer_tools)
lt.has_wipe_tower |= (lt.has_object && (config.timelapse_type == TimelapseType::tlSmooth || lt.wipe_tower_partitions > 0))
lt.has_wipe_tower |= ((lt.has_object || lt.has_support) && (config.timelapse_type == TimelapseType::tlSmooth || lt.wipe_tower_partitions > 0))
|| lt.print_z < object_bottom_z + EPSILON;
// Test for a raft, insert additional wipe tower layer to fill in the raft separation gap.
@@ -944,6 +1054,84 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_
}
}
// Ensure wipe tower vertical continuity:
//
// (1) Any existing LayerTools sandwiched between two has_wipe_tower layers must itself be a
// wipe-tower layer. The LayerTools entry already exists, but it has neither object nor
// support geometry (has_object == false && has_support == false), so the marking pass
// above leaves has_wipe_tower == false. Happens e.g. when one object is fully floating
// above another and the support_top_z_distance / support_bottom_z_distance gap leaves an
// interior layer with no object and no support (e.g. B top z=20.4, A first layer z=20.8,
// the z=20.6 LayerTools entry exists but stays unmarked).
//
// (2) When two adjacent has_wipe_tower layers are farther apart than max_layer_height and no
// LayerTools entry exists between them, insert virtual wipe-tower-only layers to bridge
// the gap. Happens with raft: BambuStudio's raft contact layer can be thicker than
// max_layer_height (e.g. raft base top z=0.2, raft contact top z=0.5 — gap 0.3 > 0.28),
// and there is no LayerTools entry between those two z values.
//
// wipe_tower_partitions has already been max-propagated downward above, so partition counts
// on the filled-in / inserted layers stay consistent.
{
int first_wt_idx = -1;
int last_wt_idx = -1;
for (int i = 0; i < (int)m_layer_tools.size(); ++i)
if (m_layer_tools[i].has_wipe_tower) {
if (first_wt_idx < 0) first_wt_idx = i;
last_wt_idx = i;
}
for (int i = first_wt_idx + 1; i < last_wt_idx; ++i) {
LayerTools &lt = m_layer_tools[i];
lt.has_wipe_tower = true;
// GCode::process_layer emits wipe-tower G-code inside `for (extruder_id : layer_tools.extruders)`.
// An empty extruders vector here would silently skip wipe tower output, leaving the tower
// physically floating. Seed from the nearest non-empty neighbor so the loop actually runs.
if (lt.extruders.empty()) {
unsigned int seed_extruder = 0;
bool found_seed = false;
for (int j = i - 1; j >= 0; --j)
if (!m_layer_tools[j].extruders.empty()) {
seed_extruder = m_layer_tools[j].extruders.back();
found_seed = true;
break;
}
if (!found_seed)
for (int j = i + 1; j < (int)m_layer_tools.size(); ++j)
if (!m_layer_tools[j].extruders.empty()) {
seed_extruder = m_layer_tools[j].extruders.front();
found_seed = true;
break;
}
if (found_seed)
lt.extruders.push_back(seed_extruder);
}
}
// Walk adjacent has_wipe_tower pairs and split oversized gaps. Re-evaluate the same i
// after each insertion so very large gaps get split into multiple layers.
for (int i = 0; i + 1 < (int)m_layer_tools.size(); ) {
LayerTools &lt = m_layer_tools[i];
LayerTools &lt_next = m_layer_tools[i + 1];
if (!lt.has_wipe_tower || !lt_next.has_wipe_tower) {
++i;
continue;
}
coordf_t gap = lt_next.print_z - lt.print_z;
if (gap <= max_layer_height + EPSILON) {
++i;
continue;
}
LayerTools lt_new(0.5 * (lt.print_z + lt_next.print_z));
lt_new.has_wipe_tower = true;
if (!lt_next.extruders.empty())
lt_new.extruders.push_back(lt_next.extruders.front());
else if (!lt.extruders.empty())
lt_new.extruders.push_back(lt.extruders.back());
lt_new.wipe_tower_partitions = lt_next.wipe_tower_partitions;
m_layer_tools.insert(m_layer_tools.begin() + i + 1, lt_new);
}
}
// If the model contains empty layers (such as https://github.com/prusa3d/Slic3r/issues/1266), there might be layers
// that were not marked as has_wipe_tower, even when they should have been. This produces a crash with soluble supports
// and maybe other problems. We will therefore go through layer_tools and detect and fix this.
@@ -1945,6 +2133,605 @@ MultiNozzleUtils::LayeredNozzleGroupResult ToolOrdering::build_sequential_group_
return result ? *result : MultiNozzleUtils::LayeredNozzleGroupResult();
}
static double snap_to_simple_fraction(double r, int max_denom = 10)
{
double best_r = r;
double best_err = 1.0;
for (int q = 1; q <= max_denom; ++q) {
int p = (int)std::round(r * q);
if (p < 0) p = 0;
if (p > q) p = q;
double candidate = (double)p / q;
double err = std::abs(candidate - r);
if (err < best_err) {
best_err = err;
best_r = candidate;
}
}
return best_r;
}
void ToolOrdering::resolve_mixed_filaments(const PrintConfig &config)
{
const auto &is_mixed = config.filament_is_mixed.values;
const auto &comp_strs = config.filament_mixed_components.values;
const auto &ratio_strs = config.filament_mixed_sublayer_ratios.values;
// Capture mixed slots that actually appear on layers before they are expanded to
// physical components. Assigned-but-unused mixed slots never enter layer_tools.
m_used_mixed_filaments.clear();
if (has_any_mixed_filament(is_mixed)) {
std::set<unsigned int> used;
for (const LayerTools &lt : m_layer_tools)
for (unsigned int ext : lt.extruders)
if (ext < is_mixed.size() && is_mixed[ext])
used.insert(ext);
m_used_mixed_filaments.assign(used.begin(), used.end());
}
if (!has_any_mixed_filament(is_mixed))
return;
const bool sublayer_enabled = config.enable_mixed_color_sublayer.value;
struct SlotInfo {
std::vector<unsigned int> components; // 1-based
std::vector<double> ratios;
std::vector<long long> accum; // deficit accumulator (integer, unit: 1e-6 mm)
};
std::vector<SlotInfo> slots(is_mixed.size());
for (size_t i = 0; i < is_mixed.size(); ++i) {
if (!is_mixed[i])
continue;
slots[i].components = parse_mixed_components(i < comp_strs.size() ? comp_strs[i] : "");
if (slots[i].components.size() < 2) {
slots[i].components.clear();
continue;
}
for (unsigned int cid : slots[i].components) {
unsigned int idx0 = cid - 1;
if (idx0 >= is_mixed.size() || (idx0 < is_mixed.size() && is_mixed[idx0])) {
slots[i].components.clear();
break;
}
}
if (slots[i].components.empty())
continue;
slots[i].ratios = parse_mixed_ratios(
i < ratio_strs.size() ? ratio_strs[i] : "", slots[i].components.size());
if (!sublayer_enabled) {
for (double &r : slots[i].ratios)
r = snap_to_simple_fraction(r);
double sum = 0;
for (double r : slots[i].ratios) sum += r;
if (sum > 0)
for (double &r : slots[i].ratios) r /= sum;
}
slots[i].accum.assign(slots[i].components.size(), 0LL);
}
// Parse gradient settings per slot
const auto &gradient_flags = config.filament_mixed_gradient.values;
const auto &gradient_range_strs = config.filament_mixed_gradient_range.values;
const auto &gradient_curve_strs = config.filament_mixed_gradient_curve.values;
struct GradientInfo {
double start = 0.10;
double end_val = 0.90;
GradientCurve curve; // empty -> use linear (start, end_val); non-empty wins
};
std::vector<bool> is_gradient(is_mixed.size(), false);
std::vector<GradientInfo> gradient_info(is_mixed.size());
for (size_t i = 0; i < is_mixed.size(); ++i) {
if (!is_mixed[i] || slots[i].components.size() != 2)
continue;
if (i >= gradient_flags.size() || !gradient_flags[i])
continue;
is_gradient[i] = true;
if (i < gradient_range_strs.size() && !gradient_range_strs[i].empty()) {
CNumericLocalesSetter c_locale_setter;
float v0 = 0, v1 = 0;
if (std::sscanf(gradient_range_strs[i].c_str(), "%f,%f", &v0, &v1) == 2 &&
v0 > 0 && v0 < 1.0 && v1 > 0 && v1 < 1.0) {
gradient_info[i].start = v0;
gradient_info[i].end_val = v1;
}
}
if (i < gradient_curve_strs.size() && !gradient_curve_strs[i].empty())
gradient_info[i].curve = parse_gradient_curve(gradient_curve_strs[i]);
}
// Pass 1: identify continuous runs for each gradient slot (Per-Run).
// A "run" is a maximal sequence of consecutive layers where the slot appears.
struct GradientRunInfo {
std::vector<size_t> run_lengths;
int current_run = -1;
size_t current_idx = 0;
bool prev_appeared = false;
bool last_absent_was_relevant = false;
};
std::map<unsigned int, GradientRunInfo> gradient_runs;
for (size_t i = 0; i < is_mixed.size(); ++i)
if (is_gradient[i]) gradient_runs[static_cast<unsigned int>(i)] = {};
// Build per-slot sets of all layer indices where any slot-owning object has a
// layer. Used by gradient run detection (a gap is real only if the slot is
// absent at a layer belonging to one of its own objects) and by calc_slot_lh
// to keep prev_relevant_z_for_slot current even when a slot skips many layers.
std::map<unsigned int, std::set<size_t>> slot_relevant_layers;
for (auto &[slot_idx, obj_map] : m_mixed_object_layers) {
for (auto &[obj, _] : obj_map) {
auto it = m_object_all_layer_indices.find(obj);
if (it != m_object_all_layer_indices.end())
slot_relevant_layers[slot_idx].insert(it->second.begin(), it->second.end());
}
}
if (!gradient_runs.empty()) {
for (size_t li = 0; li < m_layer_tools.size(); ++li) {
if (li == 0) continue;
const auto &lt = m_layer_tools[li];
for (auto &[slot, run] : gradient_runs) {
bool here = std::find(lt.extruders.begin(), lt.extruders.end(), slot) != lt.extruders.end();
if (here) {
bool real_gap = false;
if (!run.prev_appeared && !run.run_lengths.empty()) {
real_gap = run.last_absent_was_relevant;
}
if (run.run_lengths.empty() || real_gap)
run.run_lengths.push_back(0);
run.run_lengths.back()++;
run.last_absent_was_relevant = false;
} else if (!run.run_lengths.empty()) {
auto rel_it = slot_relevant_layers.find(slot);
if (rel_it != slot_relevant_layers.end() && rel_it->second.count(li))
run.last_absent_was_relevant = true;
}
run.prev_appeared = here;
}
}
for (auto &[slot, run] : gradient_runs) {
run.current_run = -1;
run.current_idx = 0;
run.prev_appeared = false;
run.last_absent_was_relevant = false;
}
}
// Per-object gradient: pre-compute per-object runs (respecting Z gaps within each object).
struct PerObjRunState {
std::vector<size_t> run_start_offsets; // index into layer_indices where each run starts
std::vector<size_t> run_lengths;
int current_run = -1;
size_t current_idx = 0;
};
// Detect whether a gap between two consecutive gradient-slot appearances is a
// real run break. A gap is real only if the object has its own layer inside the
// gap that does NOT use the gradient slot (i.e. the slot was genuinely absent).
// Uses lower_bound to skip global indices that don't belong to the object.
auto has_real_gap = [](size_t prev_idx, size_t cur_idx,
const std::set<size_t>& obj_set,
const std::set<size_t>& slot_set) -> bool {
for (auto it = obj_set.lower_bound(prev_idx + 1);
it != obj_set.end() && *it < cur_idx; ++it) {
if (!slot_set.count(*it))
return true;
}
return false;
};
// Segment a sorted list of layer indices into runs, using has_real_gap to decide
// where to break. Shared by the per-object and per-volume paths below.
auto segment_runs = [&](const std::vector<size_t>& layer_indices,
const std::set<size_t>& obj_set,
const std::set<size_t>& slot_set) -> PerObjRunState {
PerObjRunState st;
for (size_t i = 0; i < layer_indices.size(); ++i) {
bool new_run = (i == 0) ||
has_real_gap(layer_indices[i - 1], layer_indices[i], obj_set, slot_set);
if (new_run) {
st.run_start_offsets.push_back(i);
st.run_lengths.push_back(0);
}
st.run_lengths.back()++;
}
return st;
};
std::map<unsigned int, std::map<const PrintObject*, PerObjRunState>> per_obj_runs;
for (auto &[slot, obj_map] : m_mixed_object_layers) {
if (slot >= is_gradient.size() || !is_gradient[slot])
continue;
for (auto &[obj, layer_indices] : obj_map) {
sort_remove_duplicates(layer_indices);
// Erase layer 0 — this mutation is also relied upon by the Pass 2 binary_search below.
if (!layer_indices.empty() && layer_indices.front() == 0)
layer_indices.erase(layer_indices.begin());
const auto &all_obj_layers = m_object_all_layer_indices[obj];
std::set<size_t> all_obj_set(all_obj_layers.begin(), all_obj_layers.end());
std::set<size_t> grad_set(layer_indices.begin(), layer_indices.end());
per_obj_runs[slot][obj] = segment_runs(layer_indices, all_obj_set, grad_set);
}
}
// Per-volume gradient: mirror the per-object run-segmentation logic above for
// m_gradient_volume_layers. When per_part_gradient is off (or no qualifying volume exists),
// m_gradient_volume_layers is empty and per_vol_runs ends up empty too — so all subsequent
// checks of `per_vol_runs.find(slot) != end()` will fail and the legacy per-object path
// remains the only path taken.
using VolumeKey = LayerTools::MixedSubLayerGroup::VolumeKey;
std::map<unsigned int, std::map<VolumeKey, PerObjRunState>> per_vol_runs;
for (auto &[slot, vol_map] : m_gradient_volume_layers) {
if (slot >= is_gradient.size() || !is_gradient[slot])
continue;
for (auto &[vkey, layer_indices] : vol_map) {
sort_remove_duplicates(layer_indices);
if (!layer_indices.empty() && layer_indices.front() == 0)
layer_indices.erase(layer_indices.begin());
const auto &all_obj_layers = m_object_all_layer_indices[vkey.obj];
std::set<size_t> all_obj_set(all_obj_layers.begin(), all_obj_layers.end());
std::set<size_t> vol_grad_set(layer_indices.begin(), layer_indices.end());
per_vol_runs[slot][vkey] = segment_runs(layer_indices, all_obj_set, vol_grad_set);
}
}
// Pass 2: resolve per layer
coordf_t prev_print_z = 0.;
// Track last print_z per mixed slot so that layer height is computed from the
// slot's own previous appearance, not from a global Z that may include layers
// belonging only to other objects with different layer heights.
std::map<unsigned int, coordf_t> prev_print_z_for_slot;
// Track the last Z where a slot-owning object had ANY layer (regardless of
// whether the slot was present). Used to detect genuine gaps: if the slot was
// absent but its owner objects had layers, prev_relevant_z advances while
// prev_print_z_for_slot stays stale. Taking the max of both gives correct lh.
std::map<unsigned int, coordf_t> prev_relevant_z_for_slot;
// Compute the effective layer height for a mixed slot by choosing the best
// reference Z among: (1) the slot's own last Z, (2) the last Z where the
// slot's owning object had any layer, (3) the global previous Z as fallback
// when the slot appears for the first time.
auto calc_slot_lh = [&](unsigned int ext, coordf_t print_z) -> double {
auto slot_pz_it = prev_print_z_for_slot.find(ext);
auto rel_pz_it = prev_relevant_z_for_slot.find(ext);
coordf_t base_z = prev_print_z;
if (slot_pz_it != prev_print_z_for_slot.end()) {
base_z = slot_pz_it->second;
if (rel_pz_it != prev_relevant_z_for_slot.end())
base_z = std::max(base_z, rel_pz_it->second);
}
double lh = print_z - base_z;
return (lh > 0.) ? lh : 0.2; // 0.2mm safety fallback; should not trigger in normal operation
};
for (LayerTools &lt : m_layer_tools) {
size_t layer_idx = static_cast<size_t>(&lt - m_layer_tools.data());
// Update gradient run state (skip first layer to match counting).
if (layer_idx > 0) {
for (auto &[slot, run] : gradient_runs) {
bool here = std::find(lt.extruders.begin(), lt.extruders.end(), slot) != lt.extruders.end();
if (here) {
if (!run.prev_appeared) {
if (run.last_absent_was_relevant || run.current_run < 0) {
run.current_run++;
run.current_idx = 0;
}
}
run.last_absent_was_relevant = false;
} else {
auto rel_it = slot_relevant_layers.find(slot);
if (rel_it != slot_relevant_layers.end() && rel_it->second.count(layer_idx))
run.last_absent_was_relevant = true;
}
run.prev_appeared = here;
}
}
std::vector<unsigned int> new_extruders;
for (unsigned int ext : lt.extruders) {
if (ext >= slots.size() || slots[ext].components.empty()) {
new_extruders.push_back(ext);
continue;
}
auto &s = slots[ext];
// Skip sublayer splitting for the first layer to preserve bed adhesion.
if (sublayer_enabled && layer_idx > 0) {
double lh = calc_slot_lh(ext, lt.print_z);
size_t n = s.components.size();
std::vector<double> sub_heights;
bool gradient_last_no_split = false;
unsigned int gradient_last_dominant_0b = 0;
if (is_gradient[ext] && n == 2) {
auto gr_it = gradient_runs.find(ext);
if (gr_it != gradient_runs.end() && gr_it->second.current_run >= 0 &&
static_cast<size_t>(gr_it->second.current_run) < gr_it->second.run_lengths.size()) {
auto &run = gr_it->second;
size_t N = run.run_lengths[run.current_run];
size_t idx = run.current_idx++;
double t = (N > 0) ? (2.0 * idx + 1.0) / (2.0 * N) : 0.5;
// Custom curve wins over linear range when present; OFF path stays bit-identical.
double r1 = gradient_info[ext].curve.empty()
? (gradient_info[ext].start + (gradient_info[ext].end_val - gradient_info[ext].start) * t)
: sample_gradient_curve(gradient_info[ext].curve, t);
double r2 = 1.0 - r1;
sub_heights.push_back(r1 * lh);
sub_heights.push_back(r2 * lh);
// The sublayer split path sorts components by physical ID ascending;
// the higher-ID component ends up on top (visible surface). If the
// gradient's dominant component has the lower physical ID, splitting
// would put the non-dominant color on the visible top surface. In
// that case, skip the split and print this final run-layer as pure
// dominant color to preserve the gradient appearance.
if (idx == N - 1) {
// When r1 == r2 (exactly 50/50), component[0] is treated as dominant.
size_t dominant = (r1 >= r2) ? 0 : 1;
unsigned int dom_0b = s.components[dominant] - 1;
unsigned int oth_0b = s.components[1 - dominant] - 1;
if (dom_0b < oth_0b) {
gradient_last_no_split = true;
gradient_last_dominant_0b = dom_0b;
}
}
} else {
for (double r : s.ratios)
sub_heights.push_back(r * lh);
}
} else {
for (double r : s.ratios)
sub_heights.push_back(r * lh);
}
// Per-part gradient: when this slot has any qualifying volume, the global
// no-split short-circuit must NOT bypass MixedSubLayerGroup creation — each
// volume needs its own no-split decision in GCode.cpp (a per-volume "last
// run-layer" can occur on a different layer index than the per-object one). We
// still keep the per-object short-circuit when per_vol_runs[ext] is empty, which
// covers the legacy path bit-identically.
bool per_vol_active_for_slot = per_vol_runs.find(ext) != per_vol_runs.end()
&& !per_vol_runs[ext].empty();
if (gradient_last_no_split && !per_vol_active_for_slot) {
lt.mixed_filament_resolution[ext] = gradient_last_dominant_0b;
new_extruders.push_back(gradient_last_dominant_0b);
prev_print_z_for_slot[ext] = lt.print_z;
continue;
}
LayerTools::MixedSubLayerGroup grp;
grp.mixed_slot_0based = ext;
grp.layer_height = lh;
grp.is_gradient = is_gradient[ext];
for (size_t k = 0; k < s.components.size(); ++k) {
unsigned int comp_0based = s.components[k] - 1;
grp.components_0based.push_back(comp_0based);
}
grp.sub_heights = sub_heights;
// Write gradient metadata (run-aware). Both per_object_gradient and
// per_volume_gradient are populated independently from their own run-state
// machines; the GCode emitter chooses per-region:
// - tagged region (gradient_volume_id valid) -> per_volume_gradient[{obj, vol}]
// - untagged region (modifier / painted / etc.) -> per_object_gradient[obj]
// Populating both keeps the per-object run state correct even when per-volume
// takes over for the same (slot, obj), and lets untagged geometry (which is
// never split per-volume) keep its per-object gradient ratios.
if (grp.is_gradient) {
auto vol_runs_slot_it = per_vol_runs.find(ext);
if (vol_runs_slot_it != per_vol_runs.end()) {
auto vol_slot_it = m_gradient_volume_layers.find(ext);
for (auto &[vkey, st] : vol_runs_slot_it->second) {
auto &layer_indices = vol_slot_it->second[vkey];
if (!std::binary_search(layer_indices.begin(), layer_indices.end(), layer_idx))
continue;
if (st.current_run < 0 ||
st.current_idx >= st.run_lengths[st.current_run]) {
st.current_run++;
st.current_idx = 0;
}
size_t run_N = st.run_lengths[st.current_run];
size_t run_idx = st.current_idx++;
grp.per_volume_gradient[vkey] = {
run_N,
run_idx,
gradient_info[ext].start,
gradient_info[ext].end_val,
gradient_info[ext].curve,
};
}
}
auto runs_slot_it = per_obj_runs.find(ext);
if (runs_slot_it != per_obj_runs.end()) {
auto slot_it = m_mixed_object_layers.find(ext);
for (auto &[obj, st] : runs_slot_it->second) {
auto &layer_indices = slot_it->second[obj];
if (!std::binary_search(layer_indices.begin(), layer_indices.end(), layer_idx))
continue;
if (st.current_run < 0 ||
st.current_idx >= st.run_lengths[st.current_run]) {
st.current_run++;
st.current_idx = 0;
}
size_t run_N = st.run_lengths[st.current_run];
size_t run_idx = st.current_idx++;
grp.per_object_gradient[obj] = {
run_N,
run_idx,
gradient_info[ext].start,
gradient_info[ext].end_val,
gradient_info[ext].curve,
};
}
}
}
if (grp.components_0based.size() > 1) {
unsigned int first_comp_0based = s.components[0] - 1;
std::vector<size_t> idx(grp.components_0based.size());
std::iota(idx.begin(), idx.end(), 0);
std::sort(idx.begin(), idx.end(), [&](size_t a, size_t b) {
return grp.components_0based[a] < grp.components_0based[b];
});
std::vector<unsigned int> sorted_comps;
std::vector<double> sorted_heights;
for (size_t i : idx) {
sorted_comps.push_back(grp.components_0based[i]);
sorted_heights.push_back(grp.sub_heights[i]);
}
grp.components_0based = std::move(sorted_comps);
grp.sub_heights = std::move(sorted_heights);
if (grp.is_gradient) {
for (size_t i = 0; i < grp.components_0based.size(); ++i) {
if (grp.components_0based[i] == first_comp_0based) {
grp.gradient_first_sorted_idx = static_cast<int>(i);
break;
}
}
}
}
for (unsigned int comp : grp.components_0based)
new_extruders.push_back(comp);
lt.mixed_sub_layer_groups.push_back(std::move(grp));
prev_print_z_for_slot[ext] = lt.print_z;
} else {
// Deficit Round-Robin: pick one component per layer.
// Weight by layer height so volume ratios stay accurate
// even with adaptive layer heights.
double lh = calc_slot_lh(ext, lt.print_z);
long long lh_i = std::llround(lh * 1e6);
// For 2-component gradient on the first layer, use the gradient's
// starting ratio instead of the configured mixing ratio so the
// selected filament matches the gradient's "from" end.
// Only affects the first layer; when sublayer splitting is enabled
// (required for gradient), layers 1+ take the sublayer path and
// do not touch the DRR accumulator.
if (layer_idx == 0 && is_gradient[ext] && s.components.size() == 2) {
double r0 = gradient_info[ext].start;
s.accum[0] += std::llround(r0 * lh_i);
s.accum[1] += std::llround((1.0 - r0) * lh_i);
} else {
for (size_t k = 0; k < s.ratios.size(); ++k)
s.accum[k] += std::llround(s.ratios[k] * lh_i);
}
size_t sel = 0;
for (size_t k = 1; k < s.accum.size(); ++k)
if (s.accum[k] > s.accum[sel])
sel = k;
s.accum[sel] -= lh_i;
unsigned int resolved = s.components[sel] - 1;
lt.mixed_filament_resolution[ext] = resolved;
new_extruders.push_back(resolved);
prev_print_z_for_slot[ext] = lt.print_z;
}
}
lt.extruders = new_extruders;
sort_remove_duplicates(lt.extruders);
// Update prev_relevant_z: for each slot that has relevant-layer tracking,
// advance if the current layer belongs to a slot-owning object.
for (auto &[slot, rel_set] : slot_relevant_layers) {
if (rel_set.count(layer_idx))
prev_relevant_z_for_slot[slot] = lt.print_z;
}
prev_print_z = lt.print_z;
}
}
void ToolOrdering::enforce_mixed_component_order()
{
for (LayerTools &lt : m_layer_tools) {
if (lt.mixed_sub_layer_groups.empty())
continue;
// Build a set of extruders present in lt.extruders for fast lookup.
std::set<unsigned int> ext_set(lt.extruders.begin(), lt.extruders.end());
// 1. Build DAG from mixed group constraints.
// For each group [c0, c1, c2, ...], add edges c0->c1, c1->c2, ...
// Only between components that are both present in lt.extruders.
// Use an edge set to avoid duplicate edges inflating in-degree.
std::map<unsigned int, std::vector<unsigned int>> adj;
std::map<unsigned int, int> in_degree;
std::set<std::pair<unsigned int, unsigned int>> edge_set;
for (unsigned int ext : lt.extruders)
in_degree[ext] = 0;
for (const auto &grp : lt.mixed_sub_layer_groups) {
for (size_t i = 0; i + 1 < grp.components_0based.size(); ++i) {
unsigned int a = grp.components_0based[i];
unsigned int b = grp.components_0based[i + 1];
if (!ext_set.count(a) || !ext_set.count(b))
continue;
if (edge_set.insert({a, b}).second) {
adj[a].push_back(b);
in_degree[b] += 1;
}
}
}
// 2. Record original position (from flush optimizer) as priority.
std::map<unsigned int, size_t> orig_pos;
for (size_t i = 0; i < lt.extruders.size(); ++i)
orig_pos[lt.extruders[i]] = i;
// 3. Kahn's topological sort with priority queue (prefer original position).
auto cmp = [&orig_pos](unsigned int lhs, unsigned int rhs) {
return orig_pos[lhs] > orig_pos[rhs]; // min-heap by orig_pos
};
std::priority_queue<unsigned int, std::vector<unsigned int>, decltype(cmp)> pq(cmp);
for (unsigned int ext : lt.extruders) {
if (in_degree[ext] == 0)
pq.push(ext);
}
std::vector<unsigned int> ordered;
ordered.reserve(lt.extruders.size());
while (!pq.empty()) {
unsigned int ext = pq.top();
pq.pop();
ordered.push_back(ext);
if (auto it = adj.find(ext); it != adj.end()) {
for (unsigned int next : it->second) {
if (--in_degree[next] == 0)
pq.push(next);
}
}
}
// Safety: if topological sort didn't produce all elements, keep original order.
if (ordered.size() != lt.extruders.size())
ordered = lt.extruders;
// 4. Verify: every mixed group's component order is preserved as subsequence.
for (const auto &grp : lt.mixed_sub_layer_groups) {
size_t prev_pos = 0;
bool valid = true;
for (unsigned int c : grp.components_0based) {
if (!ext_set.count(c))
continue;
auto it = std::find(ordered.begin() + prev_pos, ordered.end(), c);
if (it == ordered.end()) { valid = false; break; }
prev_pos = (it - ordered.begin()) + 1;
}
assert(valid && "enforce_mixed_component_order: mixed group subsequence violated");
(void)valid;
}
lt.extruders = ordered;
}
}
void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first_layer)
{
const PrintConfig* print_config = m_print_config_ptr;
@@ -1998,6 +2785,17 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first
std::vector<unsigned int> used_filaments = collect_sorted_used_filaments(layer_filaments);
std::vector<std::set<int>>geometric_unprintables = m_print->get_geometric_unprintable_filaments();
// Unprintable sets are keyed by filament id, but a mixed-color slot is virtual: what actually
// reaches the nozzle are its components. Expand the slot to those components so a geometric
// restriction is applied to the filaments really being printed. No-op without mixed filaments.
{
const auto &is_mixed = m_print->config().filament_is_mixed.values;
const auto &comp_strs = m_print->config().filament_mixed_components.values;
if (has_any_mixed_filament(is_mixed))
expand_mixed_slots_in_unprintables(geometric_unprintables, is_mixed, comp_strs);
}
std::vector<std::set<int>>physical_unprintables = m_print->get_physical_unprintable_filaments(used_filaments);
auto filament_unprintable_volumes = m_print->get_filament_unprintable_flow(used_filaments);
+86
View File
@@ -5,12 +5,16 @@
#include "../libslic3r.h"
#include <functional>
#include <map>
#include <utility>
#include <boost/container/small_vector.hpp>
#include "../FilamentGroup.hpp"
#include "../FilamentMixer.hpp"
#include "../MultiNozzleUtils.hpp"
#include "../ExtrusionEntity.hpp"
#include "../ObjectID.hpp"
#include "../PrintConfig.hpp"
namespace Slic3r {
@@ -172,6 +176,65 @@ public:
// Custom G-code (color change, extruder switch, pause) to be performed before this layer starts to print.
const CustomGCode::Item *custom_gcode = nullptr;
// 0-based mixed filament slot → 0-based resolved physical filament for this layer.
// Populated by ToolOrdering::resolve_mixed_filaments(). Empty when no mixed filaments.
std::map<unsigned int, unsigned int> mixed_filament_resolution;
unsigned int resolve_mixed(unsigned int filament_0based) const {
auto it = mixed_filament_resolution.find(filament_0based);
return (it != mixed_filament_resolution.end()) ? it->second : filament_0based;
}
struct MixedSubLayerGroup {
unsigned int mixed_slot_0based;
std::vector<unsigned int> components_0based;
std::vector<double> sub_heights; // per-component, sum ≈ layer_height
double layer_height = 0.; // the actual lh used to compute sub_heights
bool is_gradient = false;
int gradient_first_sorted_idx = 0; // index of "first" config component after sorting
struct ObjectGradient {
size_t total_layers;
size_t current_idx;
double gradient_start;
double gradient_end;
GradientCurve curve; // empty -> linear fallback (start, end); non-empty wins
};
std::map<const PrintObject*, ObjectGradient> per_object_gradient;
// Per-volume gradient: same metadata layout as ObjectGradient but keyed by
// (PrintObject*, ModelVolume id). Populated only when filament_mixed_gradient_per_part is
// enabled for this slot AND the corresponding ModelObject contains >=2 model-part volumes
// using this slot. When non-empty for a given (PrintObject*), GCode emission takes the
// per-volume path for tagged regions; untagged regions (modifier/painted/fuzzy_skin) still
// use per_object_gradient. Both maps are populated in parallel to keep run states correct.
struct VolumeKey {
const PrintObject* obj;
ObjectID volume_id;
bool operator<(const VolumeKey &o) const {
if (obj != o.obj) return std::less<const PrintObject*>{}(obj, o.obj);
return volume_id < o.volume_id;
}
bool operator==(const VolumeKey &o) const {
return obj == o.obj && volume_id == o.volume_id;
}
};
using VolumeGradient = ObjectGradient;
std::map<VolumeKey, VolumeGradient> per_volume_gradient;
};
std::vector<MixedSubLayerGroup> mixed_sub_layer_groups;
const MixedSubLayerGroup* mixed_group_by_slot(unsigned int slot_id) const {
for (const auto &g : mixed_sub_layer_groups)
if (g.mixed_slot_0based == slot_id)
return &g;
return nullptr;
}
bool is_mixed_slot(unsigned int slot_id) const {
return mixed_group_by_slot(slot_id) != nullptr;
}
WipingExtrusions& wiping_extrusions() {
m_wiping_extrusions.set_layer_tools_ptr(this);
return m_wiping_extrusions;
@@ -227,6 +290,9 @@ public:
// For a multi-material print, the printing extruders are ordered in the order they shall be primed.
const std::vector<unsigned int>& all_extruders() const { return m_all_printing_extruders; }
// 0-based mixed (virtual) slots that appeared on layers before resolve_mixed_filaments
// expanded them to physical components.
const std::vector<unsigned int>& used_mixed_filaments() const { return m_used_mixed_filaments; }
// Find LayerTools with the closest print_z.
const LayerTools& tools_for_layer(coordf_t print_z) const;
@@ -299,6 +365,8 @@ private:
void mark_skirt_layers(const PrintConfig &config, coordf_t max_layer_height);
void collect_extruder_statistics(bool prime_multi_material);
void reorder_extruders_for_minimum_flush_volume(bool reorder_first_layer);
void resolve_mixed_filaments(const PrintConfig &config);
void enforce_mixed_component_order();
// BBS
std::vector<unsigned int> generate_first_layer_tool_order(const Print& print);
@@ -311,8 +379,26 @@ private:
unsigned int m_last_printing_extruder = (unsigned int)-1;
// All extruders, which extrude some material over m_layer_tools.
std::vector<unsigned int> m_all_printing_extruders;
std::vector<unsigned int> m_used_mixed_filaments;
const DynamicPrintConfig* m_print_full_config = nullptr;
const PrintConfig* m_print_config_ptr = nullptr;
// Per-object gradient tracking: slot(0-based) -> PrintObject* -> list of layer indices
// where that object uses the slot. Populated by collect_extruders, consumed by resolve_mixed_filaments.
std::map<unsigned int, std::map<const PrintObject*, std::vector<size_t>>> m_mixed_object_layers;
// All layer indices (in m_layer_tools) where each object has any layer.
// Used by gradient run detection to distinguish real gaps (object has a layer
// that doesn't use the slot) from spurious gaps (another object's layer).
std::map<const PrintObject*, std::vector<size_t>> m_object_all_layer_indices;
// Per-volume gradient tracking: slot(0-based) -> (PrintObject*, ModelVolume id) -> list of
// layer indices where the given volume contributes to the slot. Populated by collect_extruders
// alongside m_mixed_object_layers when per_part gradient is enabled for the slot AND the
// ModelObject has >=2 model-part volumes using the slot. Empty for all other configurations,
// which keeps every legacy per-object code path bit-identical (loops over an empty map are
// no-ops; downstream emission falls through to the per-object branch).
std::map<unsigned int, std::map<LayerTools::MixedSubLayerGroup::VolumeKey, std::vector<size_t>>> m_gradient_volume_layers;
const PrintObject* m_print_object_ptr = nullptr;
Print* m_print;
bool m_sorted = false;
+6
View File
@@ -210,6 +210,12 @@ void Layer::make_perimeters()
if (! (*it)->slices.empty()) {
LayerRegion* other_layerm = *it;
const PrintRegion &other_region = other_layerm->region();
// Per-part gradient tags a region with its owning ModelVolume; merging two
// differently-tagged regions would collapse volumes that need independent
// gradient runs. Both tags are invalid unless per-part gradient is on, so
// this is a no-op for every other configuration.
if (this_region.gradient_volume_id() != other_region.gradient_volume_id())
continue;
if (is_perimeter_compatible(*m_object->print(), this_region, other_region))
{
other_layerm->perimeters.clear();
+1 -1
View File
@@ -53,7 +53,7 @@ bool is_decimal_separator_point()
double string_to_double_decimal_point(const std::string_view str, size_t* pos /* = nullptr*/)
{
double out;
double out = 0.;
size_t p = fast_float::from_chars(str.data(), str.data() + str.size(), out).ptr - str.data();
if (pos)
*pos = p;
+129 -26
View File
@@ -1,6 +1,8 @@
#include "Model.hpp"
#include "libslic3r.h"
#include "BuildVolume.hpp"
#include "TexturePainting.hpp"
#include "Format/AssimpImport.hpp"
#include "ClipperUtils.hpp"
#include "Exception.hpp"
#include "Model.hpp"
@@ -104,6 +106,7 @@ Model& Model::assign_copy(const Model &rhs)
this->mk_version = rhs.mk_version;
this->md_name = rhs.md_name;
this->md_value = rhs.md_value;
this->texture_mesh = rhs.texture_mesh;
this->cad_recipe = rhs.cad_recipe;
@@ -141,6 +144,7 @@ Model& Model::assign_copy(Model &&rhs)
this->mk_version = rhs.mk_version;
this->md_name = rhs.md_name;
this->md_value = rhs.md_value;
this->texture_mesh = std::move(rhs.texture_mesh);
this->backup_path = std::move(rhs.backup_path);
this->object_backup_id_map = std::move(rhs.object_backup_id_map);
this->next_object_backup_id = rhs.next_object_backup_id;
@@ -242,6 +246,27 @@ _finished:
// BBS: add part plate related logic
// BBS: backup & restore
// Loading model from a file, it may be a simple geometry file as STL or OBJ, however it may be a project file as well.
// Build a plain geometry ModelObject from a textured mesh. The texture itself is carried
// separately on Model::texture_mesh and consumed by the texture import dialog.
static void add_textured_mesh_to_model(Model& model, const TexturedMesh& tex_mesh, const std::string& input_file)
{
std::string object_name = boost::filesystem::path(input_file).filename().string();
indexed_triangle_set its;
its.vertices.resize(tex_mesh.vertices.size());
for (size_t i = 0; i < tex_mesh.vertices.size(); ++i)
its.vertices[i] = Vec3f(tex_mesh.vertices[i][0], tex_mesh.vertices[i][1], tex_mesh.vertices[i][2]);
its.indices.resize(tex_mesh.indices.size());
for (size_t i = 0; i < tex_mesh.indices.size(); ++i)
its.indices[i] = Vec3i32(tex_mesh.indices[i][0], tex_mesh.indices[i][1], tex_mesh.indices[i][2]);
its_merge_vertices(its);
its_remove_degenerate_faces(its);
its_compactify_vertices(its);
model.add_object(object_name.c_str(), input_file.c_str(), std::move(TriangleMesh(std::move(its))));
}
Model Model::read_from_file(const std::string& input_file,
DynamicPrintConfig* config,
ConfigSubstitutionContext* config_substitutions,
@@ -284,32 +309,85 @@ Model Model::read_from_file(const std::string&
result = load_stl(input_file.c_str(), &model, nullptr, stlFn,256);
else if (boost::algorithm::iends_with(input_file, ".obj")) {
ObjInfo obj_info;
result = load_obj(input_file.c_str(), &model, obj_info, message);
if (result){
ObjDialogInOut in_out;
in_out.model = &model;
in_out.lost_material_name = obj_info.lost_material_name;
ObjParser::MtlData mtl_data;
result = load_obj(input_file.c_str(), &model, obj_info, message, nullptr, &mtl_data);
if (result && obj_info.has_uv_png && !obj_info.uvs.empty() && !model.objects.empty()) {
// Textured OBJ: hand the mesh + materials to the texture-to-color importer
// instead of the flat per-face colour dialog.
auto tex_mesh = std::make_shared<TexturedMesh>();
std::string obj_dir = boost::filesystem::path(input_file).parent_path().string();
if (obj_to_textured_mesh(obj_info,
model.objects.back()->volumes[0]->mesh().its,
mtl_data, obj_dir, *tex_mesh)) {
model.texture_mesh = tex_mesh;
}
}
else if (result && !model.objects.empty() && !model.objects.back()->volumes.empty()) {
// Vertex-colour and MTL face-colour OBJs also go through the texture-to-color
// importer (as precomputed per-face colors) instead of the flat
// per-face colour dialog, matching the uv_png branch above.
auto build_tex_mesh_geometry = [&]() {
auto tex_mesh = std::make_shared<TexturedMesh>();
const auto& its = model.objects.back()->volumes[0]->mesh().its;
tex_mesh->vertices.resize(its.vertices.size());
for (size_t i = 0; i < its.vertices.size(); ++i)
tex_mesh->vertices[i] = {its.vertices[i].x(), its.vertices[i].y(), its.vertices[i].z()};
tex_mesh->indices.resize(its.indices.size());
for (size_t i = 0; i < its.indices.size(); ++i)
tex_mesh->indices[i] = {its.indices[i][0], its.indices[i][1], its.indices[i][2]};
return tex_mesh;
};
if (obj_info.vertex_colors.size() > 0) {
if (objFn) { // 1.result is ok and pop up a dialog
in_out.input_colors = std::move(obj_info.vertex_colors);
in_out.is_single_color = false;
in_out.deal_vertex_color = true;
objFn(in_out);
auto tex_mesh = build_tex_mesh_geometry();
const auto& its = model.objects.back()->volumes[0]->mesh().its;
tex_mesh->precomputed_face_colors.resize(its.indices.size());
for (size_t i = 0; i < its.indices.size(); ++i) {
const auto& f = its.indices[i];
auto avg = [&](int ch) -> std::size_t {
float v = (obj_info.vertex_colors[f[0]][ch]
+ obj_info.vertex_colors[f[1]][ch]
+ obj_info.vertex_colors[f[2]][ch]) / 3.0f * 255.0f;
return (std::size_t) std::clamp(v, 0.0f, 255.0f);
};
tex_mesh->precomputed_face_colors[i] = {avg(0), avg(1), avg(2)};
}
} else if (obj_info.face_colors.size() > 0 && obj_info.has_uv_png == false) { // mtl file
if (objFn) { // 1.result is ok and pop up a dialog
in_out.input_colors = std::move(obj_info.face_colors);
in_out.is_single_color = obj_info.is_single_mtl;
in_out.deal_vertex_color = false;
objFn(in_out);
tex_mesh->precomputed_vertex_colors = obj_info.vertex_colors;
model.texture_mesh = tex_mesh;
} else if (obj_info.face_colors.size() > 0 && obj_info.has_uv_png == false) {
auto tex_mesh = build_tex_mesh_geometry();
const size_t nf = tex_mesh->indices.size();
tex_mesh->precomputed_face_colors.resize(nf);
for (size_t i = 0; i < nf; ++i) {
if (i < obj_info.face_colors.size()) {
const auto& c = obj_info.face_colors[i];
tex_mesh->precomputed_face_colors[i] = {
(std::size_t) std::clamp(c[0] * 255.0f, 0.0f, 255.0f),
(std::size_t) std::clamp(c[1] * 255.0f, 0.0f, 255.0f),
(std::size_t) std::clamp(c[2] * 255.0f, 0.0f, 255.0f)
};
} else {
tex_mesh->precomputed_face_colors[i] = {128, 128, 128};
}
}
} /*else if (obj_info.has_uv_png && obj_info.uvs.size() > 0) {
boost::filesystem::path full_path(input_file);
std::string obj_directory = full_path.parent_path().string();
obj_info.obj_dircetory = obj_directory;
result = false;
message = _L("Importing obj with png function is developing.");
}*/
model.texture_mesh = tex_mesh;
}
}
}
else if (boost::algorithm::iends_with(input_file, ".glb") ||
boost::algorithm::iends_with(input_file, ".gltf") ||
boost::algorithm::iends_with(input_file, ".fbx")) {
// These formats can carry material/texture data, so they go through the textured
// import path: the geometry becomes a normal object and the texture is handed to the
// texture-to-color dialog via Model::texture_mesh.
auto tex_mesh = std::make_shared<TexturedMesh>();
result = load_assimp_textured_model(input_file, *tex_mesh, &message);
if (result) {
model.texture_mesh = tex_mesh;
add_textured_mesh_to_model(model, *tex_mesh, input_file);
} else if (!message.empty()) {
BOOST_LOG_TRIVIAL(error) << "Assimp: failed to load model: " << message
<< ", path=" << input_file;
message = _L("The file format is incompatible and cannot be parsed.");
}
}
else if (boost::algorithm::iends_with(input_file, ".svg"))
@@ -581,6 +659,7 @@ void Model::clear_objects()
this->objects.clear();
object_backup_id_map.clear();
next_object_backup_id = 1;
texture_mesh.reset();
}
// BBS: backup, reuse objects
@@ -2579,7 +2658,8 @@ void ModelVolume::update_extruder_count(size_t extruder_count)
}
}
void ModelVolume::update_extruder_count_when_delete_filament(size_t extruder_count, size_t filament_id, int replace_filament_id)
void ModelVolume::update_extruder_count_when_delete_filament(size_t extruder_count, size_t filament_id, int replace_filament_id,
const std::vector<unsigned char> &filament_is_mixed)
{
std::vector<int> used_extruders = get_extruders();
for (int extruder_id : used_extruders) {
@@ -2590,8 +2670,22 @@ void ModelVolume::update_extruder_count_when_delete_filament(size_t extruder_cou
}
// Same stale-assignment cleanup as update_extruder_count, for the filament-delete path.
// Ported from BambuStudio (STUDIO-15763).
if (extruder_id() > extruder_count) {
this->config.erase("extruder");
size_t eid = extruder_id();
// Judge out-of-range against the post-remap id, mirroring update_filament_values_for_items_when_delete_filament.
// Using the pre-remap eid would wrongly erase a high extruder that should remap (e.g. 5 -> 4 after
// deleting filament 1); update_filament_values_for_items_when_delete_filament would then skip it
// (!has("extruder")) and the volume would fall back to the object default color.
size_t remapped = eid;
if (eid == filament_id)
remapped = (replace_filament_id > 0) ? (size_t)replace_filament_id : 1;
else if (eid > filament_id)
remapped = eid - 1;
if (remapped > extruder_count) {
// filament_is_mixed is the pre-delete snapshot; index it with the ORIGINAL eid (1-based),
// not remapped, so we check whether this volume's current slot is a mixed slot.
bool is_mixed = !filament_is_mixed.empty() && eid >= 1 && (eid - 1) < filament_is_mixed.size() && filament_is_mixed[eid - 1];
if (!is_mixed)
this->config.erase("extruder");
}
}
@@ -3498,6 +3592,15 @@ void FacetsAnnotation::get_facets(const ModelVolume& mv, std::vector<indexed_tri
selector.get_facets(facets_per_type);
}
void FacetsAnnotation::shift_states_above(const ModelVolume &mv, EnforcerBlockerType threshold, int delta)
{
if (empty()) return;
TriangleSelector selector(mv.mesh());
selector.deserialize(m_data, false);
selector.shift_states_above(threshold, delta);
this->set(selector);
}
void FacetsAnnotation::set_enforcer_block_type_limit(const ModelVolume &mv,
EnforcerBlockerType max_type,
EnforcerBlockerType to_delete_filament,
+11 -1
View File
@@ -47,6 +47,8 @@ namespace cereal {
}
namespace Slic3r {
struct TexturedMesh;
enum class ConversionType;
class BuildVolume;
@@ -740,6 +742,9 @@ public:
EnforcerBlockerType max_type,
EnforcerBlockerType to_delete_filament = EnforcerBlockerType::NONE,
EnforcerBlockerType replace_filament = EnforcerBlockerType::NONE);
// Shift painted filament indices >= threshold by delta. Used when a physical filament is
// inserted ahead of existing slots (mixed-color slots are kept at the end of the list).
void shift_states_above(const ModelVolume &mv, EnforcerBlockerType threshold, int delta);
indexed_triangle_set get_facets_strict(const ModelVolume& mv, EnforcerBlockerType type) const;
bool has_facets(const ModelVolume& mv, EnforcerBlockerType type) const;
bool empty() const { return m_data.triangles_to_split.empty(); }
@@ -932,7 +937,8 @@ public:
// BBS
std::vector<int> get_extruders() const;
void update_extruder_count(size_t extruder_count);
void update_extruder_count_when_delete_filament(size_t extruder_count, size_t filament_id, int replace_filament_id = -1);
void update_extruder_count_when_delete_filament(size_t extruder_count, size_t filament_id, int replace_filament_id = -1,
const std::vector<unsigned char> &filament_is_mixed = {});
// Split this volume, append the result to the object owning this volume.
// Return the number of volumes created from this one.
@@ -1549,6 +1555,10 @@ public:
std::shared_ptr<ModelInfo> model_info = nullptr;
std::shared_ptr<ModelProfileInfo> profile_info = nullptr;
// Textured mesh data for texture-to-painting import. Populated by the loader when a mesh
// arrives with usable UVs and a texture map; consumed (and reset) by the import dialog.
std::shared_ptr<TexturedMesh> texture_mesh;
//makerlab information
std::string mk_name;
std::string mk_version;
+2
View File
@@ -1,4 +1,6 @@
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "OpenVDBUtils.hpp"
#ifdef _MSC_VER
+17 -1
View File
@@ -229,6 +229,22 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
// Append thin walls to the nearest-neighbor search (only for first iteration)
if (! thin_walls.empty()) {
// Orca: apply fuzzy skin to thin walls as well
for (auto& thin_wall : thin_walls) {
// First, we convert the ThickPolyline into Arachne::ExtrusionLine so we could reuse our existing fuzzy code
Arachne::ExtrusionLine el(0, true);
el.junctions.reserve(thin_wall.points.size());
for (int i = 0; i < thin_wall.points.size(); i++) {
el.junctions.emplace_back(thin_wall.points[i], thin_wall.width[i], 0);
}
// Then we fuzzy it
apply_fuzzy_skin(&el, perimeter_generator, true, thin_wall.is_closed());
// Then convert the result back to ThickPolyline
thin_wall = Arachne::to_thick_polyline(el);
}
variable_width(thin_walls, erExternalPerimeter, perimeter_generator.ext_perimeter_flow, coll.entities);
thin_walls.clear();
}
@@ -392,7 +408,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
ExtrusionRole role = is_external ? erExternalPerimeter : erPerimeter;
const bool is_contour = !extrusion->is_closed || pg_extrusion.is_contour;
apply_fuzzy_skin(extrusion, perimeter_generator, is_contour);
apply_fuzzy_skin(extrusion, perimeter_generator, is_contour, extrusion->is_closed);
ExtrusionPaths paths;
// detect overhanging/bridging perimeters
+27 -11
View File
@@ -8,7 +8,9 @@
#ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <Windows.h>
#endif /* _MSC_VER */
@@ -147,6 +149,9 @@ Semver get_version_from_json(std::string file_path)
return Semver();
//throw ConfigurationError(format("Failed loading configuration file \"%1%\": %2%", file_path, err.what()));
}
catch(...) {
return Semver();
}
}
//BBS: add a function to load the key-values from xxx.json
@@ -261,18 +266,28 @@ void extend_default_config_length(DynamicPrintConfig& config, const bool set_nil
}
};
// The four variant sets are immutable after static init and probed for every
// key of every preset loaded; one merged map makes that a single lookup.
// emplace keeps the first insertion, preserving the first-set-wins priority
// of the else-if chain this replaces.
static const std::unordered_map<std::string, int> variant_class = [] {
std::unordered_map<std::string, int> m;
for (const std::string& k : print_options_with_variant) m.emplace(k, 0);
for (const std::string& k : filament_options_with_variant) m.emplace(k, 1);
for (const std::string& k : printer_options_with_variant_1) m.emplace(k, 2);
for (const std::string& k : printer_options_with_variant_2) m.emplace(k, 3);
return m;
}();
for(auto& key :config.keys()){
if(auto iter = print_options_with_variant.find(key); iter != print_options_with_variant.end()){
replace_nil_and_resize(key, process_variant_length);
}
else if(auto iter = filament_options_with_variant.find(key); iter != filament_options_with_variant.end()){
replace_nil_and_resize(key, filament_variant_length);
}
else if(auto iter = printer_options_with_variant_1.find(key); iter != printer_options_with_variant_1.end()){
replace_nil_and_resize(key, machine_variant_length);
}
else if(auto iter = printer_options_with_variant_2.find(key); iter != printer_options_with_variant_2.end()){
replace_nil_and_resize(key, machine_variant_length * 2);
auto iter = variant_class.find(key);
if (iter == variant_class.end())
continue;
switch (iter->second) {
case 0: replace_nil_and_resize(key, process_variant_length); break;
case 1: replace_nil_and_resize(key, filament_variant_length); break;
case 2: replace_nil_and_resize(key, machine_variant_length); break;
case 3: replace_nil_and_resize(key, machine_variant_length * 2); break;
}
}
}
@@ -1170,6 +1185,7 @@ static std::vector<std::string> s_Preset_print_options{
"flush_into_infill",
"flush_into_objects",
"flush_into_support",
"enable_mixed_color_sublayer",
"tree_support_branch_angle",
"tree_support_angle_slow",
"tree_support_wall_count",
+26 -3
View File
@@ -131,6 +131,10 @@ public:
PrinterVariant() {}
PrinterVariant(const std::string &name) : name(name) {}
std::string name;
// All fields, declaration order — keep in sync; bump CACHE_VERSION on change.
template<class Archive>
void serialize(Archive& ar) { ar(name); } // PrinterVariant
};
struct PrinterModel {
@@ -139,7 +143,7 @@ public:
std::string name;
//BBS: this is internal id for the printer. Currently only used for searching in database
std::string model_id;
PrinterTechnology technology;
PrinterTechnology technology = ptFFF;
std::string family;
std::vector<PrinterVariant> variants;
std::vector<std::string> default_materials;
@@ -162,6 +166,17 @@ public:
}
const PrinterVariant* variant(const std::string &name) const { return const_cast<PrinterModel*>(this)->variant(name); }
// All fields, declaration order — keep in sync; bump CACHE_VERSION on change.
template<class Archive>
void serialize(Archive& ar) // PrinterModel
{
ar(id, name, model_id, technology, family, variants, default_materials,
not_support_bed_types, bed_model, bed_texture, image_bed_type,
bottom_texture_end_name, use_double_extruder_default_texture,
bottom_texture_rect, bottom_texture_rect_longer, middle_texture_rect,
hotend_model);
}
};
std::vector<PrinterModel> models;
@@ -173,6 +188,14 @@ public:
bool valid() const { return ! name.empty() && ! id.empty() && config_version.valid(); }
// All fields, declaration order — keep in sync; bump CACHE_VERSION on change.
template<class Archive>
void serialize(Archive& ar) // VendorProfile
{
ar(name, id, config_version, config_update_url, changelog_url,
models, default_filaments, default_sla_materials);
}
// Load VendorProfile from an ini file.
// If `load_all` is false, only the header with basic info (name, version, URLs) is loaded.
static VendorProfile from_ini(const boost::filesystem::path &path, bool load_all=true);
@@ -427,10 +450,10 @@ public:
Preset(Type type, const std::string &name, bool is_default = false) : type(type), is_default(is_default), name(name) {}
protected:
Preset() = default;
friend class PresetCollection;
friend class PresetBundle;
Preset() = default;
};
bool is_compatible_with_print (const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print, const PresetWithVendorProfile &active_printer);
File diff suppressed because it is too large Load Diff
+81 -5
View File
@@ -2,10 +2,12 @@
#define slic3r_PresetBundle_hpp_
#include "Preset.hpp"
#include "PresetCacheFormat.hpp"
#include "AppConfig.hpp"
#include "enum_bitmask.hpp"
#include <memory>
#include <set>
#include <shared_mutex>
#include <unordered_map>
#include <optional>
@@ -170,6 +172,31 @@ struct PresetBundleMetadata
class PresetBundle
{
public:
// ---- Per-vendor preset cache --------------------------------------------
// One cache file per vendor (plus the Orca filament library), stamped with
// the vendor's own profile version rather than a directory scan. The bytes
// on disk are VendorCacheFile's business (PresetCacheFormat.hpp); what
// lives here is how a cache's contents install into a bundle.
// The cache is not something a caller loads from: a vendor is loaded with
// load_vendor_configs_from_json, which comes from the cache whenever one covers
// it. What is public here is what the cache's own tests drive directly.
// Load a per-vendor cache into this bundle by installing its entries, with
// base_bundle's filament library as the inheritance base. Rejects (returns
// false, with this bundle left clean) unless VendorCacheFile::load accepts
// the file — see its contract for the version and identity checks — and
// every entry installs. Options this build no longer defines are dropped,
// not fatal — the payload names its own keys.
bool load_vendor_cache(const std::string& cache_path, const std::string& expected_vendor_name,
const Semver& expected_vendor_version, const PresetBundle* base_bundle = nullptr);
// Enable writing a per-vendor cache after a JSON parse (off by default). Cache
// content is pure parse output, so the guard is policy, not correctness: only
// the deliberate generators (load_system_presets_from_json, the cache build
// tool) write files, not every incidental load a dialog performs.
void set_generate_vendor_caches(bool enable) { m_generate_vendor_caches = enable; }
static DynamicPrintConfig construct_full_config(Preset &in_printer_preset,
Preset &in_print_preset,
const DynamicPrintConfig &project_config,
@@ -299,8 +326,9 @@ public:
// Export selections (current print, current filaments, current printer) into config.ini
void export_selections(AppConfig &config);
// BBS
void set_num_filaments(unsigned int n, std::vector<std::string> new_colors);
// n is the total slot count, and growth appends at the raw tail - which is where the mixed
// slots live. A caller adding physical filaments has to add num_mixed_filaments() on top and
// then move the new slots ahead of the mixed tail, as Sidebar::add_custom_filament does.
void set_num_filaments(unsigned int n, std::string new_col = "");
void update_num_filaments(unsigned int to_del_flament_id);
@@ -444,8 +472,12 @@ public:
/*std::pair<PresetsConfigSubstitutions, size_t> load_configbundle(
const std::string &path, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule);*/
//Orca: load config bundle from json, pass the base bundle to support cross vendor inheritance
// Orca: `dir` is where the vendor is looked for — its own directory, whether or
// not the profile JSONs are still there. A whole-vendor load comes from the
// vendor's preset cache whenever one covers the profile on disk, and is parsed
// from the JSONs in `dir` only when none does. Nothing here reads resources.
std::pair<PresetsConfigSubstitutions, size_t> load_vendor_configs_from_json(
const std::string &path, const std::string &vendor_name, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule, const PresetBundle* base_bundle = nullptr);
const std::string &dir, const std::string &vendor_name, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule, const PresetBundle* base_bundle = nullptr);
// Export a config bundle file containing all the presets and the names of the active presets.
//void export_configbundle(const std::string &path, bool export_system_settings = false, bool export_physical_printers = false);
@@ -466,6 +498,14 @@ public:
// Read out the number of extruders from an active printer preset,
// update size and content of filament_presets.
void update_multi_material_filament_presets(size_t to_delete_filament_id = size_t(-1));
// Mixed-color filament slots: virtual slots realized from 2-3 physical filaments.
bool is_mixed_filament(size_t idx) const;
std::vector<size_t> physical_filament_config_indices() const;
// How many slots are mixed. They sit at the tail of the filament list and have no nozzle of
// their own, so any resize driven by the printer's extruder count has to add this on top.
size_t num_mixed_filaments() const;
// How many slots hold a real filament, i.e. everything ahead of the mixed tail.
size_t num_physical_filaments() const;
void on_extruders_count_changed(int extruder_count);
@@ -517,11 +557,49 @@ public:
// Orca: for validation only.
bool has_errors(bool check_duplicate_filament_subtypes = false) const;
// Errors the last load recorded. What the cache's error accounting promises —
// a cache-served vendor reports what its parse would — is pinned against this.
int error_count() const { return m_errors; }
// Orca: for validation only. Flag any system preset whose inherits / compatible_printers /
// compatible_prints references a deleted (unknown) or renamed (old) preset name.
bool check_preset_references() const;
// Merge one vendor's presets with the other vendor's presets, report duplicates.
// Public so per-vendor-cache consumers (e.g. the setup wizard) can assemble a
// bundle out of several per-vendor caches loaded into separate PresetBundle instances.
std::vector<std::string> merge_presets(PresetBundle &&other);
private:
// Load one vendor from the preset cache installed in `dir`, judged against
// the vendor profile there. False, with this bundle left clean, when there
// is no usable cache and the vendor has to be parsed. This is how
// load_vendor_configs_from_json reads a cache.
bool load_vendor_cache(const boost::filesystem::path& dir, const std::string& vendor_name, const PresetBundle* base_bundle);
// Load one source-form preset entry into this bundle: resolve `inherits`,
// flatten, validate and register the preset. Returns the reason loading
// failed, empty on success. See the definition for the sharing contract
// between the JSON parse and the cache load.
// retain_configs, when non-null, names the only presets registered into
// config_maps (a full config copy each). The cache load passes the names its
// entries inherit — the only ones ever looked up again; the JSON parse
// retains all, not knowing what later subfiles inherit.
std::string load_vendor_preset(const CachedPreset& entry,
const std::string& path, const std::string& vendor_name,
const PresetBundle* base_bundle,
LoadConfigBundleAttributes flags,
ConfigSubstitutionContext& substitution_context, PresetsConfigSubstitutions& substitutions,
std::map<std::string, DynamicPrintConfig>& config_maps, std::map<std::string, std::string>& filament_id_maps,
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
const std::set<std::string>* retain_configs = nullptr);
// Clear every collection's m_printer_hold_alias, which reset() leaves alone.
void clear_printer_hold_aliases();
// Whether to (re)write a per-vendor cache after a JSON parse.
bool m_generate_vendor_caches { false };
// Orca: validation only - flag any printer with two or more compatible
// filament presets sharing one filament_id (ambiguous AMS subtype match).
bool check_duplicate_filament_subtypes() const;
@@ -529,8 +607,6 @@ private:
//std::pair<PresetsConfigSubstitutions, std::string> load_system_presets(ForwardCompatibilitySubstitutionRule compatibility_rule);
//BBS: add json related logic
std::pair<PresetsConfigSubstitutions, std::string> load_system_presets_from_json(ForwardCompatibilitySubstitutionRule compatibility_rule);
// Merge one vendor's presets with the other vendor's presets, report duplicates.
std::vector<std::string> merge_presets(PresetBundle &&other);
// Update the multicolor information for filaments.
void update_filament_multi_color();
// Update renamed_from and alias maps of system profiles.
+588
View File
@@ -0,0 +1,588 @@
#include "libslic3r/PresetCacheFormat.hpp"
#include <algorithm>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <utility>
#include <boost/crc.hpp>
#include <boost/filesystem.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/log/trivial.hpp>
#include <boost/nowide/fstream.hpp>
#include <cereal/types/map.hpp>
#include <cereal/types/set.hpp>
#include "libslic3r/Utils.hpp"
namespace Slic3r {
CacheDictionary::CacheDictionary()
{
// ENUM_UNNAMED is index 0 and always the empty name.
m_enum_values.emplace_back();
}
// The ints an enum option holds — one for a coEnum, the whole vector for coEnums.
static std::vector<int> enum_ints(const ConfigOptionDef& def, const ConfigOption* opt)
{
if (def.type == coEnum)
return { opt->getInt() };
return static_cast<const ConfigOptionInts*>(opt)->values;
}
// The name this build gives one of those ints, empty where it has none — a
// nullable option's nil, or a definition carrying no enum_keys_map. Enums are
// written by name so a build that reorders an enum's values still reads it right.
static std::string enum_name_of(const ConfigOptionDef& def, int value)
{
if (def.enum_keys_map != nullptr)
for (const auto& kvp : *def.enum_keys_map)
if (kvp.second == value)
return kvp.first;
return {};
}
void CacheDictionary::collect(const DynamicPrintConfig& config)
{
for (auto it = config.cbegin(); it != config.cend(); ++ it) {
const ConfigOptionDef* def = print_config_def.get(it->first);
if (def == nullptr)
continue; // save_config does not write it either
if (m_key_index.try_emplace(it->first, uint16_t(m_keys.size())).second) {
m_keys.push_back(it->first);
m_types.push_back(uint16_t(def->type));
}
if (def->type != coEnum && def->type != coEnums)
continue;
for (int value : enum_ints(*def, it->second.get())) {
std::string name = enum_name_of(*def, value);
if (! name.empty() && m_enum_index.try_emplace(name, uint16_t(m_enum_values.size())).second)
m_enum_values.push_back(std::move(name));
}
}
}
uint16_t CacheDictionary::key_index(const t_config_option_key& key) const
{
auto it = m_key_index.find(key);
if (it == m_key_index.end())
throw std::runtime_error("preset cache: option " + key + " was never collected into the dictionary");
return it->second;
}
uint16_t CacheDictionary::enum_index(const std::string& name) const
{
if (name.empty())
return ENUM_UNNAMED;
auto it = m_enum_index.find(name);
return it == m_enum_index.end() ? ENUM_UNNAMED : it->second;
}
void CacheDictionary::save(cereal::BinaryOutputArchive& ar) const
{
// Checked here rather than left to the caller: an index that wrapped would
// be written silently, and nothing downstream could tell.
if (m_keys.size() > MAX_ENTRIES || m_enum_values.size() > MAX_ENTRIES)
throw std::runtime_error("preset cache: the option dictionary outgrew the uint16 it is indexed with");
ar(m_keys, m_types, m_enum_values);
}
void CacheDictionary::load(cereal::BinaryInputArchive& ar)
{
ar(m_keys, m_types, m_enum_values);
if (m_keys.size() != m_types.size())
throw std::runtime_error("preset cache: dictionary key and type tables differ in length");
if (m_keys.size() > MAX_ENTRIES || m_enum_values.size() > MAX_ENTRIES)
throw std::runtime_error("preset cache: dictionary is larger than the uint16 it is indexed with");
if (m_enum_values.empty() || ! m_enum_values.front().empty())
throw std::runtime_error("preset cache: dictionary is missing its unnamed-enum slot");
// Resolved once per file: every option read after this is a vector index.
m_defs.resize(m_keys.size());
for (size_t i = 0; i < m_keys.size(); ++ i) {
const ConfigOptionDef* def = print_config_def.get(m_keys[i]);
m_defs[i] = (def != nullptr && uint16_t(def->type) == m_types[i]) ? def : nullptr;
}
}
// ---- one config -----------------------------------------------------------
static void save_enum_option(cereal::BinaryOutputArchive& ar, const ConfigOptionDef& def,
const ConfigOption* opt, const CacheDictionary& dict)
{
const std::vector<int> values = enum_ints(def, opt);
ar(uint32_t(values.size()));
for (int value : values) {
const uint16_t idx = dict.enum_index(enum_name_of(def, value));
ar(idx);
if (idx == CacheDictionary::ENUM_UNNAMED)
ar(int32_t(value));
}
}
// `config` may be null, in which case the option is read and dropped.
static void load_enum_option(cereal::BinaryInputArchive& ar, ConfigOptionType type,
const ConfigOptionDef* def, DynamicPrintConfig* config,
const CacheDictionary& dict)
{
uint32_t cnt = 0;
ar(cnt);
if (type == coEnum && cnt != 1)
throw std::runtime_error("preset cache: a scalar enum carrying more than one value");
// Every element is read whatever happens, so the stream stays in sync and
// whatever follows this option still loads.
bool usable = def != nullptr && config != nullptr;
std::vector<int> values;
values.reserve(cnt);
for (uint32_t i = 0; i < cnt; ++ i) {
uint16_t idx = 0;
ar(idx);
if (! dict.valid_enum_index(idx))
throw std::runtime_error("preset cache: enum value index past the end of the dictionary");
if (idx == CacheDictionary::ENUM_UNNAMED) {
// An int the writer could not name — a nil, or an option whose
// definition carried no enum_keys_map. It travels verbatim.
int32_t raw = 0;
ar(raw);
values.push_back(int(raw));
continue;
}
if (! usable)
continue; // the index above was this element's whole payload
if (def->enum_keys_map == nullptr) {
usable = false; // this build no longer maps this option's names
continue;
}
const auto it = def->enum_keys_map->find(dict.enum_name_at(idx));
if (it == def->enum_keys_map->end()) {
usable = false; // a value this build dropped: the option goes with it
continue;
}
values.push_back(it->second);
}
if (! usable)
return;
if (type == coEnum) {
config->set_key_value(def->opt_key, new ConfigOptionEnumGeneric(def->enum_keys_map, values.front()));
} else {
auto* opt = def->nullable ? static_cast<ConfigOptionInts*>(new ConfigOptionEnumsGenericNullable(def->enum_keys_map))
: static_cast<ConfigOptionInts*>(new ConfigOptionEnumsGeneric(def->enum_keys_map));
opt->values = std::move(values);
config->set_key_value(def->opt_key, opt);
}
}
void save_config(cereal::BinaryOutputArchive& ar, const DynamicPrintConfig& config, const CacheDictionary& dict)
{
struct Written { uint16_t idx; const ConfigOptionDef* def; const ConfigOption* opt; };
std::vector<Written> written;
written.reserve(config.size());
for (auto it = config.cbegin(); it != config.cend(); ++ it)
if (const ConfigOptionDef* def = print_config_def.get(it->first))
written.push_back({ dict.key_index(it->first), def, it->second.get() });
ar(uint32_t(written.size()));
for (const Written& w : written) {
ar(w.idx);
if (w.def->type == coEnum || w.def->type == coEnums)
save_enum_option(ar, *w.def, w.opt, dict);
else
w.def->save_option_to_archive(ar, w.opt);
}
}
// `config` null means: read everything, keep nothing.
static void read_config(cereal::BinaryInputArchive& ar, DynamicPrintConfig* config, const CacheDictionary& dict)
{
uint32_t cnt = 0;
ar(cnt);
if (config != nullptr)
config->clear();
// Reused across the loop: constructing a ConfigOptionDef per dropped option
// would allocate its strings and vectors for nothing.
ConfigOptionDef scratch;
for (uint32_t i = 0; i < cnt; ++ i) {
uint16_t idx = 0;
ar(idx);
if (! dict.valid_key_index(idx))
throw std::runtime_error("preset cache: option index past the end of the dictionary");
const ConfigOptionType type = dict.type_at(idx);
const ConfigOptionDef* def = dict.def_at(idx);
if (type == coEnum || type == coEnums) {
load_enum_option(ar, type, def, config, dict);
} else if (def != nullptr && config != nullptr) {
config->set_key_value(def->opt_key, def->load_option_from_archive(ar));
} else {
// Read by the type the writer recorded, then drop: the same outcome
// a JSON profile gets for an option this build no longer has.
scratch.type = type;
std::unique_ptr<ConfigOption> discard(scratch.load_option_from_archive(ar));
}
}
}
void load_config(cereal::BinaryInputArchive& ar, DynamicPrintConfig& config, const CacheDictionary& dict)
{
read_config(ar, &config, dict);
}
void skip_config(cereal::BinaryInputArchive& ar, const CacheDictionary& dict)
{
read_config(ar, nullptr, dict);
}
// ---- The per-vendor cache file (<vendor>.opc) -----------------------------
namespace {
#pragma pack(push, 1)
struct CacheFileHeader {
uint32_t magic;
uint32_t version;
uint64_t data_size;
uint32_t crc32;
};
#pragma pack(pop)
static_assert(sizeof(CacheFileHeader) == 20, "CacheFileHeader must be 20 bytes");
constexpr uint32_t CACHE_MAGIC = 0x4F52435A; // "ORCZ"
// Bump when the wire format changes in a way the payload cannot describe
// itself out of: reordering, removing or retyping a field of a hand-written
// serialize() (VendorProfile and its nested types, CachedPreset via
// save_entries below), or a change to the cache's own layout or the
// meaning of its stamps. Option-schema drift is NOT such a change — the
// dictionary handles it, which is why this no longer moves every release.
constexpr uint32_t CACHE_VERSION = 1;
// A stamp-string read that refuses an absurd length before allocating anything.
// The stamps are read from files named from the outside (peek_version is
// pointed at whatever <vendor>.opc a directory holds), so the length word may
// be arbitrary bytes — and a resize to a garbage 64-bit length does not fail as
// a catchable bad_alloc here, it takes the app down through the out-of-memory
// handler. A vendor name or profile version is a short token; anything longer
// is not a cache this build wrote.
std::string read_bounded_string(cereal::BinaryInputArchive& ar)
{
constexpr uint64_t MAX_STAMP_LEN = 1024;
cereal::size_type len = 0;
ar(cereal::make_size_tag(len));
if (uint64_t(len) > MAX_STAMP_LEN)
throw std::runtime_error("preset cache: string length out of bounds");
std::string s(size_t(len), '\0');
ar(cereal::binary_data(s.data(), size_t(len)));
return s;
}
// The prologue every cache reader starts with: the format version, then the
// vendor's identity. Returns the vendor version stamped on a body this build can
// read, empty on anything else — which is the same answer as "not this vendor".
std::string read_cache_stamps(cereal::BinaryInputArchive& ar, const std::string& expected_vendor_name)
{
// The version is judged before anything variable-length is read: on a body
// that is not a per-vendor cache of this version, the bytes where a string
// length would sit may be arbitrary framing.
uint32_t cache_version = 0;
ar(cache_version);
if (cache_version != CACHE_VERSION)
return {};
const std::string vendor_name = read_bounded_string(ar);
const std::string vendor_version = read_bounded_string(ar);
if (vendor_name != expected_vendor_name)
return {};
return vendor_version;
}
// A cache stays usable as long as it was built from a vendor profile at least
// as new as the one now on disk. Profiles whose version is invalid cannot be
// judged this way and are never served from cache; where no profile sits
// beside the cache at all, nothing can be newer than it — that state is passed
// as Semver::inf(), which no real profile can carry (an invalid version could
// not say it apart from "profile there but unjudgeable", and zero would
// collide with a genuine "0.0.0"). This is the serve rule; the install rule
// (cache_covers in PresetBundle.cpp) deliberately reads an unjudgeable profile
// the other way, so the two are not one function.
bool cache_covers_version(const std::string& cached, const Semver& on_disk)
{
if (on_disk == Semver::inf())
return true; // before parsing `cached`: nothing exists that the stamp must cover
if (! on_disk.valid())
return false;
const auto cached_ver = Semver::parse(cached);
return cached_ver && *cached_ver >= on_disk;
}
// CachedPreset on the wire: all fields, declaration order, in one place.
// `config` writes, reads or skips the config sitting in the middle of that
// order — the three things a reader can want to do with it — so save, load and
// the name peek below cannot drift apart. Keep in sync with the struct in
// PresetCacheFormat.hpp and bump CACHE_VERSION on change. Written here rather
// than as a serialize() member because the config needs the file's dictionary,
// which cereal cannot thread through one.
template<class Archive, class Entry, class ConfigFn>
void visit_entry(Archive& ar, Entry& e, ConfigFn&& config)
{
ar(e.name, e.sub_path);
config();
ar(e.inherits, e.description, e.instantiation, e.setting_id, e.filament_id, e.renamed_from);
}
// The count comes from a file that has already passed magic and CRC, but a
// reserve is a promise to allocate: cap it and let push_back grow the rest.
constexpr uint32_t MAX_RESERVED_ENTRIES = 4096;
void save_entries(cereal::BinaryOutputArchive& ar,
const std::vector<CachedPreset>& entries,
const CacheDictionary& dict)
{
ar(uint32_t(entries.size()));
for (const CachedPreset& e : entries)
visit_entry(ar, e, [&] { save_config(ar, e.config_src, dict); });
}
void load_entries(cereal::BinaryInputArchive& ar,
std::vector<CachedPreset>& entries,
const CacheDictionary& dict)
{
uint32_t cnt = 0;
ar(cnt);
entries.clear();
entries.reserve(std::min(cnt, MAX_RESERVED_ENTRIES));
for (uint32_t i = 0; i < cnt; ++ i) {
CachedPreset e;
visit_entry(ar, e, [&] { load_config(ar, e.config_src, dict); });
entries.push_back(std::move(e));
}
}
// Read a raw cache body: verify magic, size, CRC.
bool read_cache_blob(const std::string& path, std::string& out_blob)
{
try {
boost::nowide::ifstream ifs(path, std::ios::binary);
if (!ifs.is_open())
return false;
CacheFileHeader fhdr;
if (!ifs.read(reinterpret_cast<char*>(&fhdr), sizeof(fhdr)))
return false;
if (fhdr.magic != CACHE_MAGIC)
return false;
// data_size is 8 bytes from a file nothing has authenticated yet, and
// it is about to size an allocation. The body is the whole of the file
// behind the header — anything else is not a cache this build wrote.
ifs.seekg(0, std::ios::end);
const std::streamoff file_size = ifs.tellg();
if (file_size < std::streamoff(sizeof(fhdr)) ||
fhdr.data_size == 0 ||
fhdr.data_size != uint64_t(file_size) - sizeof(fhdr))
return false;
ifs.seekg(sizeof(fhdr), std::ios::beg);
out_blob.assign(fhdr.data_size, '\0');
if (!ifs.read(&out_blob[0], static_cast<std::streamsize>(fhdr.data_size)))
return false;
boost::crc_32_type crc;
crc.process_bytes(out_blob.data(), out_blob.size());
if (crc.checksum() != fhdr.crc32) {
BOOST_LOG_TRIVIAL(warning) << "VendorCacheFile: CRC mismatch: " << path;
return false;
}
return true;
} catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(warning) << "VendorCacheFile: read failed (" << path << "): " << e.what();
return false;
}
}
// Write a cache body behind the standard 20-byte file header. False when the
// file could not be opened or written whole.
bool write_cache_blob(const std::string& path, const std::string& blob)
{
boost::crc_32_type crc;
crc.process_bytes(blob.data(), blob.size());
// Written beside the target and moved into place, as AppConfig::save does:
// a cache is truncated and rewritten in full, so a write that dies partway
// would otherwise leave a header claiming more body than the file holds.
// The PID suffix also keeps two instances writing the same vendor from
// interleaving.
const std::string tmp_path = path + "." + std::to_string(get_current_pid()) + ".tmp";
try {
boost::filesystem::create_directories(boost::filesystem::path(path).parent_path());
{
boost::nowide::ofstream ofs(tmp_path, std::ios::binary | std::ios::trunc);
if (!ofs.is_open()) {
BOOST_LOG_TRIVIAL(warning) << "VendorCacheFile: cannot open for writing: " << tmp_path;
return false;
}
CacheFileHeader fhdr;
fhdr.magic = CACHE_MAGIC;
fhdr.version = CACHE_VERSION;
fhdr.data_size = static_cast<uint64_t>(blob.size());
fhdr.crc32 = crc.checksum();
ofs.write(reinterpret_cast<const char*>(&fhdr), sizeof(fhdr));
ofs.write(blob.data(), static_cast<std::streamsize>(blob.size()));
ofs.close(); // flush; close() raises failbit on error
if (! ofs.good()) {
BOOST_LOG_TRIVIAL(warning) << "VendorCacheFile: write failed (" << tmp_path << ")";
boost::system::error_code ec;
boost::filesystem::remove(tmp_path, ec);
return false;
}
}
if (const std::error_code ec = rename_file(tmp_path, path)) {
BOOST_LOG_TRIVIAL(warning) << "VendorCacheFile: could not move " << tmp_path << " into place: " << ec.message();
boost::system::error_code rm;
boost::filesystem::remove(tmp_path, rm);
return false;
}
return true;
} catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(warning) << "VendorCacheFile: write failed (" << path << "): " << e.what();
boost::system::error_code ec;
boost::filesystem::remove(tmp_path, ec);
return false;
}
}
} // anonymous namespace
// static
bool VendorCacheFile::save(const std::string& path, const std::string& vendor_name,
const std::string& vendor_version, const VendorCacheData& data)
{
try {
// Collected before anything is written: the dictionary sits ahead of the
// entries so a reader resolves it once and then indexes.
CacheDictionary dict;
for (const std::vector<CachedPreset>* entries : { &data.process_entries, &data.filament_entries, &data.machine_entries })
for (const CachedPreset& e : *entries)
dict.collect(e.config_src);
std::ostringstream body(std::ios::binary);
{
cereal::BinaryOutputArchive ar(body);
ar(CACHE_VERSION);
ar(vendor_name, vendor_version);
dict.save(ar);
ar(data.vendors);
save_entries(ar, data.process_entries, dict);
save_entries(ar, data.filament_entries, dict);
save_entries(ar, data.machine_entries, dict);
ar(data.parse_errors);
}
return write_cache_blob(path, body.str());
} catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(warning) << "VendorCacheFile: failed to save vendor cache " << path << ": " << e.what();
return false;
}
}
// static
bool VendorCacheFile::load(const std::string& path, const std::string& expected_vendor_name,
const Semver& expected_vendor_version, VendorCacheData& data)
{
std::string blob;
if (! read_cache_blob(path, blob))
return false;
try {
// Read in place: an istringstream would copy the blob once more just to
// stream over it.
boost::iostreams::stream<boost::iostreams::array_source> body(blob.data(), blob.size());
cereal::BinaryInputArchive ar(body);
const std::string vendor_version = read_cache_stamps(ar, expected_vendor_name);
if (vendor_version.empty() || ! cache_covers_version(vendor_version, expected_vendor_version))
return false;
CacheDictionary dict;
dict.load(ar);
ar(data.vendors);
load_entries(ar, data.process_entries, dict);
load_entries(ar, data.filament_entries, dict);
load_entries(ar, data.machine_entries, dict);
ar(data.parse_errors);
if (data.vendors.find(expected_vendor_name) == data.vendors.end())
throw std::runtime_error("vendor cache does not carry its own vendor profile");
return true;
} catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(warning) << "VendorCacheFile: rejecting vendor cache " << path << ": " << e.what();
return false;
}
}
// static
std::string VendorCacheFile::peek_version(const std::string& path, const std::string& expected_vendor_name)
{
try {
boost::nowide::ifstream ifs(path, std::ios::binary);
CacheFileHeader fhdr;
if (! ifs.read(reinterpret_cast<char*>(&fhdr), sizeof(fhdr)) || fhdr.magic != CACHE_MAGIC)
return {};
// Only the head of the body is read, and its CRC left unverified: the
// stamps sit at the front, and this answers "what version is this?"
// without paying for tens of megabytes. Callers that need to know the
// file is whole use usable_version instead.
std::string head(static_cast<size_t>(std::min<uint64_t>(fhdr.data_size, 1024)), '\0');
if (! ifs.read(&head[0], static_cast<std::streamsize>(head.size())))
return {};
std::istringstream body(head, std::ios::binary);
cereal::BinaryInputArchive ar(body);
return read_cache_stamps(ar, expected_vendor_name);
} catch (const std::exception&) {
return {};
}
}
// static
Semver VendorCacheFile::usable_version(const std::string& path, const std::string& expected_vendor_name)
{
std::string blob;
if (! read_cache_blob(path, blob))
return Semver::invalid();
try {
boost::iostreams::stream<boost::iostreams::array_source> body(blob.data(), blob.size());
cereal::BinaryInputArchive ar(body);
const auto ver = Semver::parse(read_cache_stamps(ar, expected_vendor_name));
return ver ? *ver : Semver::invalid();
} catch (const std::exception&) {
return Semver::invalid();
}
}
// static
bool VendorCacheFile::carries_preset(const std::string& path, const std::string& vendor_name,
Preset::Type type, const std::string& preset_name)
{
std::string blob;
if (! read_cache_blob(path, blob))
return false;
try {
boost::iostreams::stream<boost::iostreams::array_source> body(blob.data(), blob.size());
cereal::BinaryInputArchive ar(body);
if (read_cache_stamps(ar, vendor_name).empty())
return false;
CacheDictionary dict;
dict.load(ar);
VendorMap vendors;
ar(vendors);
// Reused: every entry overwrites it, and only its name is ever looked at.
CachedPreset entry;
// Written in this order by save. The list that could carry the preset
// is the last one worth reading.
for (Preset::Type kind : { Preset::TYPE_PRINT, Preset::TYPE_FILAMENT, Preset::TYPE_PRINTER }) {
uint32_t cnt = 0;
ar(cnt);
for (uint32_t i = 0; i < cnt; ++ i) {
visit_entry(ar, entry, [&] { skip_config(ar, dict); });
if (kind == type && entry.name == preset_name)
return true;
}
if (kind == type)
return false;
}
return false;
} catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(warning) << "VendorCacheFile: could not read preset names from " << path << ": " << e.what();
return false;
}
}
} // namespace Slic3r
+192
View File
@@ -0,0 +1,192 @@
#ifndef slic3r_PresetCacheFormat_hpp_
#define slic3r_PresetCacheFormat_hpp_
#include <cstdint>
#include <string>
#include <unordered_map>
#include <vector>
#include <cereal/archives/binary.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/vector.hpp>
#include "libslic3r/Config.hpp"
#include "libslic3r/Preset.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/Semver.hpp"
namespace Slic3r {
// How the preset cache writes a DynamicPrintConfig.
//
// Not through the global cereal hooks in PrintConfig.hpp: those key an option by
// its serialization_key_ordinal, which ConfigDef::add assigns by declaration
// order at static-init time. Inserting one option into the middle of
// PrintConfig.cpp shifts every later ordinal, and the lookup on the way back in
// then SUCCEEDS on the wrong option — where the two share a type, and hundreds
// of coFloat/coBool/coInt options do, the bytes deserialize cleanly into the
// wrong key. Silently wrong print settings, no error. Those hooks are also the
// undo/redo wire format, where the process cannot change underneath them, so
// they stay as they are and the cache keys by name instead.
//
// Names are not repeated per preset. Each cache file carries one dictionary of
// the distinct opt_keys it uses, the type each was written as, and the distinct
// enum value names; an option on the wire is then a uint16 index into it plus
// its value. The dictionary is resolved to this build's option definitions once
// per file, after which reading an option is a vector index.
class CacheDictionary
{
public:
CacheDictionary();
// Index reserved in the enum table for an int the writing build could not
// name — a nullable option's nil, or a definition carrying no
// enum_keys_map. The raw int32 follows it on the wire and is loaded
// verbatim, so those values survive too.
static constexpr uint16_t ENUM_UNNAMED = 0;
// ---- writing ----
// Record every key and enum value `config` uses. Call for every config that
// will be written, before writing the dictionary.
void collect(const DynamicPrintConfig& config);
uint16_t key_index(const t_config_option_key& key) const;
// ENUM_UNNAMED for an empty name or one that was never collected.
uint16_t enum_index(const std::string& name) const;
// ---- reading ----
// The definition an index resolves to in THIS build, or nullptr where the
// key is unknown here or is now defined with a different type. A nullptr
// entry's value is still read — using type_at(idx), the type the writer
// recorded — and then dropped, which is what a JSON profile gets for an
// option this build no longer has.
const ConfigOptionDef* def_at(uint16_t idx) const { return m_defs[idx]; }
ConfigOptionType type_at(uint16_t idx) const { return ConfigOptionType(m_types[idx]); }
const std::string& enum_name_at(uint16_t idx) const { return m_enum_values[idx]; }
// m_defs, not m_keys: only load() sizes it, so this is false for every index
// on a dictionary that was collected rather than read.
bool valid_key_index(uint16_t idx) const { return size_t(idx) < m_defs.size(); }
bool valid_enum_index(uint16_t idx) const { return size_t(idx) < m_enum_values.size(); }
// The layout these two agree on is covered by CACHE_VERSION (PresetCacheFormat.cpp);
// bump it when they change.
// Throws when either table outgrew the uint16 the wire format indexes it
// with. Both are bounded by the option count (912 at the time of writing), so
// that is a build-time failure in CI, not a runtime one.
void save(cereal::BinaryOutputArchive& ar) const;
// Throws on a dictionary that cannot be indexed as written.
void load(cereal::BinaryInputArchive& ar);
private:
// Indices are uint16, so a table may hold at most this many entries.
static constexpr size_t MAX_ENTRIES = 0xFFFF;
std::vector<std::string> m_keys;
// ConfigOptionType, as written. Sixteen bits, not eight: coVectorType is
// 0x4000, so every vector type — coFloats, coEnums, coStrings — is above
// 255, and a byte would fold each one onto its scalar counterpart.
std::vector<uint16_t> m_types;
std::vector<std::string> m_enum_values; // [ENUM_UNNAMED] is always empty
// Writing.
std::unordered_map<std::string, uint16_t> m_key_index;
std::unordered_map<std::string, uint16_t> m_enum_index;
// Reading, resolved once by load().
std::vector<const ConfigOptionDef*> m_defs;
};
// One config, keyed through `dict`. Options print_config_def does not know are
// not written: nothing could give them a type on the way back in.
void save_config(cereal::BinaryOutputArchive& ar, const DynamicPrintConfig& config, const CacheDictionary& dict);
// Throws only on a payload that cannot be indexed; an option this build cannot
// place is dropped, not fatal.
void load_config(cereal::BinaryInputArchive& ar, DynamicPrintConfig& config, const CacheDictionary& dict);
// Consume one config without building it, for a reader that only wants what
// comes after.
void skip_config(cereal::BinaryInputArchive& ar, const CacheDictionary& dict);
// One preset as its JSON subfile states it: the config diff, the name of the
// preset it inherits, and the parse metadata — everything the parse phase of
// load_vendor_configs_from_json extracts and nothing it derives. Inheritance
// is resolved when the entry is installed, against whatever filament library
// is loaded then, so a cache carries no other vendor's values and no other
// vendor's update can make it stale.
// Written and read by visit_entry in PresetCacheFormat.cpp, which lists every
// field below in this order — once, for the save, the load and the name peek alike.
struct CachedPreset
{
std::string name;
std::string sub_path; // path under the vendor's directory
DynamicPrintConfig config_src; // the preset's own diff, nothing inherited
std::string inherits;
std::string description;
std::string instantiation; // "true"/"false" as stated; anything else was already counted as a parse error
std::string setting_id;
std::string filament_id;
std::vector<std::string> renamed_from;
};
// What one per-vendor cache file carries besides its stamps: the vendor profile
// map, the presets in source form, and how many errors their parse counted.
struct VendorCacheData
{
VendorMap vendors;
std::vector<CachedPreset> process_entries;
std::vector<CachedPreset> filament_entries;
std::vector<CachedPreset> machine_entries;
uint64_t parse_errors = 0;
};
// A per-vendor preset cache file (<vendor>.opc): a 20-byte header (magic, format
// version, body size, CRC) framing one cereal body — stamps (format version,
// vendor name, vendor profile version), the option dictionary, then the
// VendorCacheData. Everything about those bytes lives here; when a vendor is
// served from its cache, and how entries install into a bundle, is
// PresetBundle's business.
class VendorCacheFile
{
public:
// Save one vendor (vendor_name at vendor_version). False when the file
// could not be written whole.
static bool save(const std::string& path, const std::string& vendor_name,
const std::string& vendor_version, const VendorCacheData& data);
// Read a whole cache into `data`. False — with `data` in an unspecified
// state — unless the file is a cache this build wrote, its CRC holds, it
// names this vendor, it was built from a vendor profile at least as new as
// `expected_vendor_version`, and it carries its own vendor profile. An
// invalid expected version (a profile whose version
// cannot be judged) is never served from cache; Semver::inf() (no profile
// beside the cache at all) accepts whatever is cached.
static bool load(const std::string& path, const std::string& expected_vendor_name,
const Semver& expected_vendor_version, VendorCacheData& data);
// Read the profile version a cache was stamped with, without deserializing
// its presets. Empty if the file is unreadable, not a cache this build
// understands, or not this vendor's. This is how an installed vendor's
// version is known when only its cache is installed.
static std::string peek_version(const std::string& path, const std::string& expected_vendor_name);
// The profile version an installed cache can actually be served at, or an
// invalid Semver when the file is not a cache this build can read. Unlike
// peek_version this verifies the body's CRC, at the cost of reading the
// whole file: where the cache is the vendor's whole installation, "a file
// is there" is not enough to call it installed, and a vendor wrongly
// believed installed is never repaired.
static Semver usable_version(const std::string& path, const std::string& expected_vendor_name);
// Whether a cache carries a preset of `type` under `preset_name`, without
// installing any of them. False when the file is not a cache this build can
// read. The three kinds are written in one stream, so reaching the machines
// means reading past the processes and filaments — their configs are consumed
// and dropped rather than built. This is how a build that ships caches instead
// of preset JSONs answers "which vendor carries this preset?".
static bool carries_preset(const std::string& path, const std::string& vendor_name,
Preset::Type type, const std::string& preset_name);
};
} // namespace Slic3r
#endif // slic3r_PresetCacheFormat_hpp_
+115 -31
View File
@@ -5,6 +5,7 @@
#include "Brim.hpp"
#include "ClipperUtils.hpp"
#include "Extruder.hpp"
#include "FilamentMixer.hpp"
#include "Flow.hpp"
#include "Geometry/ConvexHull.hpp"
#include "I18N.hpp"
@@ -565,7 +566,7 @@ std::vector<unsigned int> Print::extruders(bool conside_custom_gcode) const
// If a wipe tower filament is explicitly set, ensure it participates in tool ordering.
if (has_wipe_tower() && config().wipe_tower_filament != 0 && extruders.size() > 1) {
assert(config().wipe_tower_filament > 0 && config().wipe_tower_filament < int(config().nozzle_diameter.size()));
assert(config().wipe_tower_filament > 0 && config().wipe_tower_filament <= int(config().filament_diameter.size()));
extruders.emplace_back(config().wipe_tower_filament - 1); // config value is 1-based
}
@@ -1327,6 +1328,19 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin
if (extruders.empty())
return { L("No extrusions under current settings.") };
// Orca: a gradient mixed filament only renders its gradient with "Mixed color sublayer" on;
// without it ToolOrdering::resolve_mixed_filaments prints one whole component per layer and
// the gradient is dropped silently. extruders() already covers painting, height ranges,
// per-feature filament ids and supports, and still lists mixed slots under their own id here.
if (!m_config.enable_mixed_color_sublayer.value) {
const auto &is_mixed = m_config.filament_is_mixed.values;
const auto &gradient = m_config.filament_mixed_gradient.values;
if (std::any_of(extruders.begin(), extruders.end(), [&](unsigned int e) {
return e < is_mixed.size() && is_mixed[e] && e < gradient.size() && gradient[e]; }))
warn(L("A gradient mixed filament is used, but 'Mixed color sublayer' is disabled. The gradient will not be printed."),
"enable_mixed_color_sublayer");
}
if (nozzles < 2 && extruders.size() > 1) {
auto ret = check_multi_filament_valid(*this);
if (!ret.string.empty())
@@ -1388,6 +1402,13 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin
// #4043
if (total_copies_count > 1 && m_config.print_sequence != PrintSequence::ByObject)
return {L("Please select \"By object\" print sequence to print multiple objects in spiral vase mode."), nullptr, "spiral_mode"};
// A mixed (virtual) filament always resolves to multiple physical components, which
// spiral vase cannot print.
const auto &is_mixed = m_config.filament_is_mixed.values;
for (const PrintObject *object : m_objects)
for (unsigned int ext : object->object_extruders())
if (ext < is_mixed.size() && is_mixed[ext])
return {L("Spiral (vase) mode does not work when an object contains more than one material."), nullptr, "spiral_mode"};
assert(m_objects.size() == 1);
const auto all_regions = m_objects.front()->all_regions();
if (all_regions.size() > 1) {
@@ -1464,6 +1485,17 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin
}
if (this->has_wipe_tower() && ! m_objects.empty()) {
// Orca: wipe_tower_filament (issue #10971) is inserted into the tool order after
// resolve_mixed_filaments has expanded every mixed (virtual) slot, so a mixed slot here
// would reach the G-code as a tool change to a slot no nozzle carries. The GUI hides
// mixed slots from the option; this guards loaded projects and the CLI.
if (m_config.wipe_tower_filament > 0) {
const auto &is_mixed = m_config.filament_is_mixed.values;
const size_t wipe_idx = size_t(m_config.wipe_tower_filament - 1);
if (wipe_idx < is_mixed.size() && is_mixed[wipe_idx])
return { L("The wipe tower filament cannot be a mixed filament."), nullptr, "wipe_tower_filament" };
}
// Make sure all extruders use same diameter filament and have the same nozzle diameter
// EPSILON comparison is used for nozzles and 10 % tolerance is used for filaments
double first_nozzle_diam = m_config.nozzle_diameter.get_at(extruders.front());
@@ -2585,18 +2617,31 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
std::vector<const PrintInstance*>::const_iterator print_object_instance_sequential_active;
std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> layers_to_print = GCode::collect_layers_to_print(*this);
std::vector<unsigned int> printExtruders;
// Per-object first-layer mixed-slot resolutions for the by-object remap below
// (BBS reads them from m_sequential_print_data->object_tool_ordering_map).
std::map<ObjectID, std::map<unsigned int, unsigned int>> seq_mixed_resolution;
// Cleared on every process so a print-sequence or selector-mode change can never leave
// stale object pointers behind; repopulated below only by the sequential selector path.
m_sequential_dynamic_orderings.clear();
if (this->config().print_sequence == PrintSequence::ByObject) {
// Order object instances for sequential print.
print_object_instances_ordering = sort_object_instances_by_model_order(*this);
// A mixed slot is virtual; only its components reach a nozzle. These per-object orderings
// are unsorted (no resolve_mixed_filaments), so expand the slots here for the grouping, the
// unprintable sets and the slice-used lists. Because the expansion happens here rather than
// on the sorted orderings, the first-layer used set lists every component of a mixed slot,
// not just the one layer 0 resolves to. No-op without mixed filaments.
const auto &is_mixed = m_config.filament_is_mixed.values;
const auto &comp_strs = m_config.filament_mixed_components.values;
const bool has_mixed = has_any_mixed_filament(is_mixed);
std::vector<unsigned int> first_layer_used_filaments;
std::vector<std::vector<unsigned int>> all_filaments;
for (print_object_instance_sequential_active = print_object_instances_ordering.begin(); print_object_instance_sequential_active != print_object_instances_ordering.end(); ++print_object_instance_sequential_active) {
tool_ordering = ToolOrdering(*(*print_object_instance_sequential_active)->print_object, initial_extruder_id);
for (size_t idx = 0; idx < tool_ordering.layer_tools().size(); ++idx) {
auto& layer_filament = tool_ordering.layer_tools()[idx].extruders;
auto layer_filament = tool_ordering.layer_tools()[idx].extruders;
if (has_mixed)
layer_filament = expand_mixed_filaments(layer_filament, is_mixed, comp_strs);
all_filaments.emplace_back(layer_filament);
if (idx == 0)
first_layer_used_filaments.insert(first_layer_used_filaments.end(), layer_filament.begin(), layer_filament.end());
@@ -2608,6 +2653,8 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
auto physical_unprintables = this->get_physical_unprintable_filaments(used_filaments);
auto geometric_unprintables = this->get_geometric_unprintable_filaments();
if (has_mixed)
expand_mixed_slots_in_unprintables(geometric_unprintables, is_mixed, comp_strs);
auto filament_unprintable_volumes = this->get_filament_unprintable_flow(used_filaments);
// Selector (per-layer regroup) prints skip the static grouping: their print-wide result
// is stitched from the per-object plans after the ordering loop below.
@@ -2659,6 +2706,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
std::vector<std::vector<int>> nozzle_map_per_layer;
std::vector<std::vector<unsigned int>> stitched_layer_filaments;
print_object_instance_sequential_active = print_object_instances_ordering.begin();
std::vector<unsigned int> used_mixed_filaments;
for (; print_object_instance_sequential_active != print_object_instances_ordering.end(); ++print_object_instance_sequential_active) {
const PrintObject *print_object = (*print_object_instance_sequential_active)->print_object;
if (dynamic_reorder) {
@@ -2687,11 +2735,18 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
} else {
tool_ordering = ToolOrdering(*print_object, initial_extruder_id);
tool_ordering.sort_and_build_data(*print_object, initial_extruder_id);
if (!tool_ordering.layer_tools().empty())
seq_mixed_resolution[print_object->id()] = tool_ordering.layer_tools().front().mixed_filament_resolution;
}
// Only sorted orderings have run resolve_mixed_filaments, so only they know which
// mixed slots actually print.
append(used_mixed_filaments, tool_ordering.used_mixed_filaments());
if ((initial_extruder_id = tool_ordering.first_extruder()) != static_cast<unsigned int>(-1)) {
append(printExtruders, tool_ordering.tools_for_layer(layers_to_print.front().first).extruders);
}
}
sort_remove_duplicates(used_mixed_filaments);
this->set_slice_used_mixed_filaments(used_mixed_filaments);
if (dynamic_reorder && m_objects.size() > 1) {
// Stitch the per-object plans into one print-wide selector result. A single-object
// sequential print publishes (and writes back) from its own ordering instead: the
@@ -2712,6 +2767,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
first_layer_used_filaments = tool_ordering.layer_tools().front().extruders;
this->set_slice_used_filaments(first_layer_used_filaments, tool_ordering.all_extruders());
this->set_slice_used_mixed_filaments(tool_ordering.used_mixed_filaments());
has_wipe_tower = this->has_wipe_tower() && tool_ordering.has_wipe_tower();
initial_extruder_id = tool_ordering.first_extruder();
print_object_instances_ordering = chain_print_object_instances(*this);
@@ -2719,6 +2775,28 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
}
auto objectExtruderMap = getObjectExtruderMap(*this);
// Resolve mixed filament virtual slots to physical components so brim
// extruder matching works correctly (mixed slot IDs are not present
// in printExtruders after ToolOrdering::resolve_mixed_filaments).
{
const LayerTools *first_lt = nullptr;
if (m_config.print_sequence != PrintSequence::ByObject && !tool_ordering.layer_tools().empty())
first_lt = &tool_ordering.layer_tools().front();
for (auto &[obj_id, ext_1based] : objectExtruderMap) {
if (ext_1based == 0)
continue;
const std::map<unsigned int, unsigned int> *resolution = nullptr;
if (first_lt)
resolution = &first_lt->mixed_filament_resolution;
else if (auto obj_it = seq_mixed_resolution.find(obj_id); obj_it != seq_mixed_resolution.end())
resolution = &obj_it->second;
if (resolution) {
auto it = resolution->find(ext_1based - 1);
if (it != resolution->end())
ext_1based = it->second + 1;
}
}
}
std::vector<std::pair<ObjectID, unsigned int>> objPrintVec;
for (const PrintInstance* instance : print_object_instances_ordering) {
const ObjectID& print_object_ID = instance->print_object->id();
@@ -3776,6 +3854,14 @@ bool Print::is_dynamic_group_reorder() const
const bool enabled = opt && opt->value;
if (!enabled || m_config.filament_map_mode != FilamentMapMode::fmmAutoForFlush || m_config.nozzle_diameter.size() <= 1)
return false;
// Dynamic regrouping and mixed-color slots are incompatible: a mixed slot is resolved to
// different physical components per layer, so a group assignment made up-front would be wrong.
const auto &is_mixed = m_config.filament_is_mixed.values;
for (unsigned int filament_id : extruders()) {
if (filament_id < is_mixed.size() && is_mixed[filament_id])
return false;
}
return true;
}
@@ -3999,38 +4085,36 @@ void Print::_make_wipe_tower()
return;
// Check whether there are any layers in m_tool_ordering, which are marked with has_wipe_tower,
// they print neither object, nor support. These layers are above the raft and below the object, and they
// shall be added to the support layers to be printed.
// see https://github.com/prusa3d/PrusaSlicer/issues/607
// they print neither object, nor support. Each such layer needs a virtual support layer
// counterpart in m_objects.front() so that GCode::collect_layers_to_print picks it up and the
// wipe tower G-code is actually emitted for that z. Such layers appear in two scenarios:
// - above the raft, between raft top and the first real object layer
// (see https://github.com/prusa3d/PrusaSlicer/issues/607);
// - between two real wipe-tower layers, when one object is fully floating above another and
// the support_top_z_distance / support_bottom_z_distance gap leaves interior z values with
// neither object nor support (continuity fill in ToolOrdering::fill_wipe_tower_partitions).
// The previous implementation only handled the first contiguous run starting at the first
// virtual layer, which made the second scenario silently produce empty wipe-tower layers.
{
size_t idx_begin = size_t(-1);
size_t idx_end = m_wipe_tower_data.tool_ordering.layer_tools().size();
// Find the first wipe tower layer, which does not have a counterpart in an object or a support layer.
auto &support_layers = m_objects.front()->support_layers();
auto it_layer = support_layers.begin();
const size_t idx_end = m_wipe_tower_data.tool_ordering.layer_tools().size();
for (size_t i = 0; i < idx_end; ++ i) {
const LayerTools &lt = m_wipe_tower_data.tool_ordering.layer_tools()[i];
if (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support) {
idx_begin = i;
break;
}
}
if (idx_begin != size_t(-1)) {
// Find the position in m_objects.first()->support_layers to insert these new support layers.
double wipe_tower_new_layer_print_z_first = m_wipe_tower_data.tool_ordering.layer_tools()[idx_begin].print_z;
auto it_layer = m_objects.front()->support_layers().begin();
auto it_end = m_objects.front()->support_layers().end();
for (; it_layer != it_end && (*it_layer)->print_z - EPSILON < wipe_tower_new_layer_print_z_first; ++ it_layer);
// Find the stopper of the sequence of wipe tower layers, which do not have a counterpart in an object or a support layer.
for (size_t i = idx_begin; i < idx_end; ++ i) {
LayerTools &lt = const_cast<LayerTools&>(m_wipe_tower_data.tool_ordering.layer_tools()[i]);
if (! (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support))
break;
lt.has_support = true;
// Insert the new support layer.
double height = lt.print_z - (i == 0 ? 0. : m_wipe_tower_data.tool_ordering.layer_tools()[i-1].print_z);
//FIXME the support layer ID is set to -1, as Vojtech hopes it is not being used anyway.
it_layer = m_objects.front()->insert_support_layer(it_layer, -1, 0, height, lt.print_z, lt.print_z - 0.5 * height);
LayerTools &lt = const_cast<LayerTools&>(m_wipe_tower_data.tool_ordering.layer_tools()[i]);
if (! (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support))
continue;
while (it_layer != support_layers.end() && (*it_layer)->print_z + EPSILON < lt.print_z)
++ it_layer;
if (it_layer != support_layers.end() && std::abs((*it_layer)->print_z - lt.print_z) < EPSILON) {
lt.has_support = true;
++ it_layer;
continue;
}
lt.has_support = true;
double height = lt.print_z - (i == 0 ? 0. : m_wipe_tower_data.tool_ordering.layer_tools()[i-1].print_z);
//FIXME the support layer ID is set to -1, as Vojtech hopes it is not being used anyway.
it_layer = m_objects.front()->insert_support_layer(it_layer, -1, 0, height, lt.print_z, lt.print_z - 0.5 * height);
++ it_layer;
}
}
this->throw_if_canceled();
@@ -5827,7 +5911,7 @@ BoundingBoxf3 PrintInstance::get_bounding_box() const {
Polygon PrintInstance::get_convex_hull_2d() {
Polygon poly = print_object->model_object()->convex_hull_2d(model_instance->get_matrix());
poly.douglas_peucker(0.1);
poly.douglas_peucker(scale_(0.1));
return poly;
}
+23 -4
View File
@@ -117,9 +117,9 @@ class PrintRegion
public:
PrintRegion() = default;
PrintRegion(const PrintRegionConfig &config);
PrintRegion(const PrintRegionConfig &config, const size_t config_hash, int print_object_region_id = -1) : m_config(config), m_config_hash(config_hash), m_print_object_region_id(print_object_region_id) {}
PrintRegion(const PrintRegionConfig &config, const size_t config_hash, int print_object_region_id = -1, ObjectID gradient_volume_id = ObjectID()) : m_config(config), m_config_hash(config_hash), m_print_object_region_id(print_object_region_id), m_gradient_volume_id(gradient_volume_id) {}
PrintRegion(PrintRegionConfig &&config);
PrintRegion(PrintRegionConfig &&config, const size_t config_hash, int print_object_region_id = -1) : m_config(std::move(config)), m_config_hash(config_hash), m_print_object_region_id(print_object_region_id) {}
PrintRegion(PrintRegionConfig &&config, const size_t config_hash, int print_object_region_id = -1, ObjectID gradient_volume_id = ObjectID()) : m_config(std::move(config)), m_config_hash(config_hash), m_print_object_region_id(print_object_region_id), m_gradient_volume_id(gradient_volume_id) {}
~PrintRegion() = default;
// Methods NOT modifying the PrintRegion's state:
@@ -129,6 +129,10 @@ public:
// Identifier of this PrintRegion in the list of Print::m_print_regions.
int print_region_id() const throw() { return m_print_region_id; }
int print_object_region_id() const throw() { return m_print_object_region_id; }
// Volume identity used to differentiate same-config regions when per-part gradient is enabled.
// Default-constructed (invalid) means this region is not tied to a specific volume — preserves
// existing behavior for all paths not using per_part_gradient.
ObjectID gradient_volume_id() const throw() { return m_gradient_volume_id; }
// 1-based extruder identifier for this region and role.
unsigned int extruder(FlowRole role) const;
Flow flow(const PrintObject &object, FlowRole role, double layer_height, bool first_layer = false) const;
@@ -158,6 +162,10 @@ private:
int m_print_region_id { -1 };
int m_print_object_region_id { -1 };
int m_ref_cnt { 0 };
// Per-part gradient: when non-invalid, this region belongs exclusively to one ModelVolume,
// letting same-color volumes within a combined ModelObject be tracked separately for gradient
// emission. Default invalid -> region keying behaves exactly as before.
ObjectID m_gradient_volume_id;
};
inline bool operator==(const PrintRegion &lhs, const PrintRegion &rhs) { return lhs.config_hash() == rhs.config_hash() && lhs.config() == rhs.config(); }
@@ -306,6 +314,11 @@ public:
Transform3d trafo_bboxes;
std::vector<ObjectID> cached_volume_ids;
// Per-part gradient: the slot_per_part_enabled bit vector that produced these regions.
// Print::apply compares it against the current one to detect a change that PrintRegionConfig
// alone would not reveal, and regenerates the regions when it differs.
std::vector<bool> last_slot_per_part_enabled;
void ref_cnt_inc() { ++ m_ref_cnt; }
void ref_cnt_dec() { if (-- m_ref_cnt == 0) delete this; }
void clear() {
@@ -930,8 +943,8 @@ public:
// If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r).
std::string export_gcode(const std::string& path_template, GCodeProcessorResult* result, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
//return 0 means successful
int export_cached_data(const std::string& dir_path, bool with_space=false);
int load_cached_data(const std::string& directory);
int export_cached_data(const std::string& dir_path, bool with_space=false) override;
int load_cached_data(const std::string& directory) override;
// methods for handling state
bool is_step_done(PrintStep step) const { return Inherited::is_step_done(step); }
@@ -1075,6 +1088,10 @@ public:
m_slice_used_filaments = used_filaments;
}
std::vector<unsigned int> get_slice_used_filaments(bool first_layer) const { return first_layer ? m_slice_used_filaments_first_layer : m_slice_used_filaments;}
void set_slice_used_mixed_filaments(const std::vector<unsigned int> &used_mixed_filaments) {
m_slice_used_mixed_filaments = used_mixed_filaments;
}
const std::vector<unsigned int>& get_slice_used_mixed_filaments() const { return m_slice_used_mixed_filaments; }
/**
* @brief Determines the unprintable filaments for each extruder based on its physical attributes
@@ -1342,6 +1359,8 @@ private:
std::vector<unsigned int> m_slice_used_filaments;
std::vector<unsigned int> m_slice_used_filaments_first_layer;
// 0-based mixed (virtual) filament slots actually used on this plate.
std::vector<unsigned int> m_slice_used_mixed_filaments;
//BBS: plate's origin
Vec3d m_origin {0, 0, 0};
+127 -15
View File
@@ -1,6 +1,7 @@
#include "ClipperUtils.hpp"
#include "Model.hpp"
#include "Print.hpp"
#include "FilamentMixer.hpp"
#include <boost/log/trivial.hpp>
#include <cfloat>
@@ -559,11 +560,9 @@ 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)
{
// 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;
Transform3d m = object_trafo * volume_trafo;
m.translation().x() = 0.;
m.translation().y() = 0.;
return m.cast<float>();
}
@@ -888,7 +887,12 @@ bool verify_update_print_object_regions(
size_t hash = regions[i]->config_hash();
size_t j = i;
for (++ j; j < regions.size() && regions[j]->config_hash() == hash; ++ j)
if (regions[i]->config() == regions[j]->config()) {
// Same config but different gradient_volume_id is intentional (per-part gradient
// splitting) and must NOT be flagged as a merge. When per-part is off all regions
// carry an invalid (default) gradient_volume_id, so the AND condition is always
// true and behavior matches the legacy check.
if (regions[i]->config() == regions[j]->config()
&& regions[i]->gradient_volume_id() == regions[j]->gradient_volume_id()) {
// Regions were merged. We need to reslice.
return false;
}
@@ -980,7 +984,10 @@ static PrintObjectRegions* generate_print_object_regions(
const float xy_contour_compensation,
const std::vector<unsigned int> &painting_extruders,
std::vector<int> &variant_index,
const bool has_painted_fuzzy_skin)
const bool has_painted_fuzzy_skin,
// Per-part gradient: slot_per_part_enabled[s-1] is true when mixed slot s has
// filament_mixed_gradient_per_part on. Empty / all-false preserves legacy behavior.
const std::vector<bool> &slot_per_part_enabled = {})
{
// Reuse the old object or generate a new one.
auto out = print_object_regions_old ? std::unique_ptr<PrintObjectRegions>(print_object_regions_old) : std::make_unique<PrintObjectRegions>();
@@ -1015,19 +1022,71 @@ static PrintObjectRegions* generate_print_object_regions(
update_volume_bboxes(layer_ranges_regions, out->cached_volume_ids, model_volumes, out->trafo_bboxes, is_mm_painted ? 0.f : std::max(0.f, xy_contour_compensation));
std::vector<PrintRegion*> region_set;
auto get_create_region = [&region_set, &all_regions](PrintRegionConfig &&config) -> PrintRegion* {
// Look up or create a PrintRegion. The optional volume_tag, when valid (non-zero ObjectID),
// keys the region to one ModelVolume so two volumes with identical settings still get
// separate regions — needed so each part can run its own gradient. A default (invalid)
// tag reproduces the previous lookup exactly.
auto get_create_region = [&region_set, &all_regions](PrintRegionConfig &&config, ObjectID volume_tag = ObjectID()) -> PrintRegion* {
size_t hash = config.hash();
auto it = Slic3r::lower_bound_by_predicate(region_set.begin(), region_set.end(), [&config, hash](const PrintRegion* l) {
return l->config_hash() < hash || (l->config_hash() == hash && l->config() < config); });
if (it != region_set.end() && (*it)->config_hash() == hash && (*it)->config() == config)
auto it = Slic3r::lower_bound_by_predicate(region_set.begin(), region_set.end(), [&config, hash, volume_tag](const PrintRegion* l) {
return l->config_hash() < hash || (l->config_hash() == hash && l->config() < config)
|| (l->config_hash() == hash && l->config() == config && l->gradient_volume_id() < volume_tag); });
if (it != region_set.end() && (*it)->config_hash() == hash && (*it)->config() == config
&& (*it)->gradient_volume_id() == volume_tag)
return *it;
// Insert into a sorted array, it has O(n) complexity, but the calling algorithm has an O(n^2*log(n)) complexity anyways.
all_regions.emplace_back(std::make_unique<PrintRegion>(std::move(config), hash, int(all_regions.size())));
all_regions.emplace_back(std::make_unique<PrintRegion>(std::move(config), hash, int(all_regions.size()), volume_tag));
PrintRegion *region = all_regions.back().get();
region_set.emplace(it, region);
return region;
};
// Per-part gradient: count how many model-part volumes in this object use each
// per-part-enabled gradient slot. Only slots with at least 2 users get their volumes
// tagged — a single-user slot gains nothing from per-volume splitting and would only
// inflate the region count. Empty slot_per_part_enabled leaves this empty, so
// compute_volume_tag below always returns an invalid tag and nothing changes.
std::vector<int> per_part_volume_users;
if (!slot_per_part_enabled.empty()) {
per_part_volume_users.assign(slot_per_part_enabled.size(), 0);
for (const ModelVolume *mv : model_volumes) {
if (! mv->is_model_part())
continue;
const DynamicPrintConfig *range_cfg = layer_ranges_regions.empty() ? nullptr : layer_ranges_regions.front().config;
PrintRegionConfig vol_cfg = region_config_from_model_volume(default_region_config, range_cfg, *mv, num_extruders, variant_index);
for (unsigned int s_1based : { (unsigned int)vol_cfg.outer_wall_filament_id.value,
(unsigned int)vol_cfg.inner_wall_filament_id.value,
(unsigned int)vol_cfg.sparse_infill_filament_id.value,
(unsigned int)vol_cfg.internal_solid_filament_id.value,
(unsigned int)vol_cfg.top_surface_filament_id.value,
(unsigned int)vol_cfg.bottom_surface_filament_id.value }) {
if (s_1based >= 1
&& size_t(s_1based - 1) < slot_per_part_enabled.size()
&& slot_per_part_enabled[s_1based - 1])
++per_part_volume_users[s_1based - 1];
}
}
}
auto compute_volume_tag = [&](const PrintRegionConfig &cfg, const ModelVolume &mv) -> ObjectID {
if (per_part_volume_users.empty())
return ObjectID();
auto qualifies = [&](unsigned int s_1based) {
return s_1based >= 1
&& size_t(s_1based - 1) < slot_per_part_enabled.size()
&& slot_per_part_enabled[s_1based - 1]
&& per_part_volume_users[s_1based - 1] >= 2;
};
if (qualifies((unsigned int)cfg.outer_wall_filament_id.value)
|| qualifies((unsigned int)cfg.inner_wall_filament_id.value)
|| qualifies((unsigned int)cfg.sparse_infill_filament_id.value)
|| qualifies((unsigned int)cfg.internal_solid_filament_id.value)
|| qualifies((unsigned int)cfg.top_surface_filament_id.value)
|| qualifies((unsigned int)cfg.bottom_surface_filament_id.value)) {
return mv.id();
}
return ObjectID();
};
// Chain the regions in the order they are stored in the volumes list.
for (int volume_id = 0; volume_id < int(model_volumes.size()); ++ volume_id) {
const ModelVolume &volume = *model_volumes[volume_id];
@@ -1036,9 +1095,11 @@ static PrintObjectRegions* generate_print_object_regions(
if (const PrintObjectRegions::BoundingBox *bbox = find_volume_extents(layer_range, volume); bbox) {
if (volume.is_model_part()) {
// Add a model volume, assign an existing region or generate a new one.
PrintRegionConfig vol_cfg = region_config_from_model_volume(default_region_config, layer_range.config, volume, num_extruders, variant_index);
ObjectID volume_tag = compute_volume_tag(vol_cfg, volume);
layer_range.volume_regions.push_back({
&volume, -1,
get_create_region(region_config_from_model_volume(default_region_config, layer_range.config, volume, num_extruders, variant_index)),
get_create_region(std::move(vol_cfg), volume_tag),
bbox
});
} else if (volume.is_negative_volume()) {
@@ -1123,6 +1184,12 @@ static PrintObjectRegions* generate_print_object_regions(
}
}
// Save the slot_per_part_enabled bit vector that produced these regions, so the guard in
// Print::apply can detect changes on the next call even when PrintRegionConfig did not
// change. Always written — including an empty vector — so the snapshot always reflects
// the exact input used to generate the current regions.
out->last_slot_per_part_enabled = slot_per_part_enabled;
return out.release();
}
@@ -1143,6 +1210,17 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
std::vector <unsigned int> used_filaments = this->extruders(true);
std::unordered_set <unsigned int> used_filament_set(used_filaments.begin(), used_filaments.end());
// A mixed slot is virtual: the filaments actually consumed are its components, so add them
// to the used set or they would be treated as unused and stripped from the config.
{
auto* is_mixed_opt = new_full_config.option<ConfigOptionBools>("filament_is_mixed");
auto* comp_strs_opt = new_full_config.option<ConfigOptionStrings>("filament_mixed_components");
if (is_mixed_opt && comp_strs_opt && has_any_mixed_filament(is_mixed_opt->values)) {
auto expanded = expand_mixed_filaments(used_filaments, is_mixed_opt->values, comp_strs_opt->values);
used_filament_set.insert(expanded.begin(), expanded.end());
}
}
//new_full_config.normalize_fdm(used_filaments);
new_full_config.normalize_fdm_1();
t_config_option_keys changed_keys = new_full_config.normalize_fdm_2(objects().size(), used_filaments.size());
@@ -1804,6 +1882,29 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
update_filament_self_index_cache();
}
// Per-part gradient: compute the per-slot enable bit vector once for this Print::apply pass.
// Used by generate_print_object_regions to decide which volumes deserve their own PrintRegion.
std::vector<bool> slot_per_part_enabled;
{
const auto &is_mixed_vec = m_config.filament_is_mixed.values;
const auto &grad_vec = m_config.filament_mixed_gradient.values;
const auto &per_part_vec = m_config.filament_mixed_gradient_per_part.values;
const auto &components_vec = m_config.filament_mixed_components.values;
slot_per_part_enabled.assign(is_mixed_vec.size(), false);
for (size_t i = 0; i < is_mixed_vec.size(); ++i) {
if (! is_mixed_vec[i])
continue;
std::vector<unsigned int> comps = parse_mixed_components(i < components_vec.size() ? components_vec[i] : "");
if (comps.size() != 2)
continue;
if (i >= grad_vec.size() || ! grad_vec[i])
continue;
if (i >= per_part_vec.size() || ! per_part_vec[i])
continue;
slot_per_part_enabled[i] = true;
}
}
// All regions now have distinct settings.
// Check whether applying the new region config defaults we would get different regions,
// update regions or create regions from scratch.
@@ -1830,7 +1931,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
for (const ModelVolume *volume : volumes) {
const std::vector<bool> &volume_used_facet_states = volume->mmu_segmentation_facets.get_data().used_states;
assert(volume_used_facet_states.size() == used_facet_states.size());
// Paint data saved before the painted state range was extended deserializes a
// shorter used_states vector, so merge over the common prefix.
for (size_t state_idx = 0; state_idx < std::min(volume_used_facet_states.size(), used_facet_states.size()); ++state_idx)
used_facet_states[state_idx] |= volume_used_facet_states[state_idx];
}
@@ -1864,6 +1966,15 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
update_apply_status((*it)->invalidate_state_by_config_options(old_config, new_config, diff_keys));
},
print_variant_index)) {
// Per-part gradient: PrintRegionConfig alone cannot reveal a change in which slots
// have per-part enabled, so compare against the snapshot taken when these regions
// were generated and regenerate on any difference (slot toggled, per-part moved
// between slots, eligibility changed via components / gradient / is_mixed).
if (print_object_regions->last_slot_per_part_enabled != slot_per_part_enabled) {
invalidate();
model_object_status.print_object_regions_status = ModelObjectStatus::PrintObjectRegionsStatus::PartiallyValid;
print_regions_reshuffled = true;
}
// Regions are valid, just keep them.
} else {
// Regions were reshuffled.
@@ -1886,7 +1997,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
print_object.is_mm_painted() ? 0.f : float(print_object.config().xy_contour_compensation.value),
painting_extruders,
print_variant_index,
print_object.is_fuzzy_skin_painted());
print_object.is_fuzzy_skin_painted(),
slot_per_part_enabled);
}
for (auto it = it_print_object; it != it_print_object_end; ++it)
if ((*it)->m_shared_regions) {
+91 -1
View File
@@ -2,6 +2,7 @@
#include "PrintConfigConstants.hpp"
#include "ClipperUtils.hpp"
#include "Config.hpp"
#include "FilamentMixer.hpp"
#include "MaterialType.hpp"
#include "I18N.hpp"
#include "format.hpp"
@@ -3263,6 +3264,62 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBools { false });
// Mixed-color filament. A slot flagged here is virtual: it is not loaded into any
// physical extruder, but resolved at slicing time into the physical filaments listed
// in filament_mixed_components, blended either by splitting each layer into
// sub-layers or by alternating whole layers (see enable_mixed_color_sublayer).
def = this->add("filament_is_mixed", coBools);
def->label = L("Is mixed filament");
def->tooltip = L("Whether this filament slot is a mixed filament composed of multiple physical filaments");
def->mode = comDevelop;
def->set_default_value(new ConfigOptionBools{false});
def = this->add("filament_mixed_components", coStrings);
def->label = L("Mixed filament components");
def->tooltip = L("Comma-separated 1-based indices of component filaments, e.g. \"1,3\"");
def->mode = comDevelop;
def->set_default_value(new ConfigOptionStrings{""});
def = this->add("filament_mixed_sublayer_ratios", coStrings);
def->label = L("Mixed filament sublayer ratios");
def->tooltip = L("Comma-separated ratio values summing to 1.0, e.g. \"0.7,0.3\"");
def->mode = comDevelop;
def->set_default_value(new ConfigOptionStrings{""});
def = this->add("filament_mixed_gradient", coBools);
def->label = L("Mixed filament gradient");
def->tooltip = L("Enable Z-direction gradient mode for mixed filament sub-layers. "
"When enabled, the sub-layer ratios vary linearly across layers.");
def->mode = comDevelop;
def->set_default_value(new ConfigOptionBools{false});
def = this->add("filament_mixed_gradient_range", coStrings);
def->label = L("Mixed filament gradient range");
def->tooltip = L("Start and end ratios for the first component in gradient mode. "
"Comma-separated pair, e.g. \"0.10,0.90\" means 10% to 90%.");
def->mode = comDevelop;
def->set_default_value(new ConfigOptionStrings{""});
def = this->add("filament_mixed_gradient_curve", coStrings);
def->label = L("Mixed filament gradient curve");
def->tooltip = L("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.");
def->mode = comDevelop;
def->set_default_value(new ConfigOptionStrings{""});
def = this->add("filament_mixed_gradient_per_part", coBools);
def->label = L("Mixed filament per-part gradient");
def->tooltip = L("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.");
def->mode = comDevelop;
def->set_default_value(new ConfigOptionBools{false});
// defined in bits
// 0 means cannot support, 1 means support
// 0 bit: can support in left extruder
@@ -7402,6 +7459,14 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloats { 1. });
def = this->add("enable_mixed_color_sublayer", coBool);
def->label = L("Mixed color sublayer");
def->tooltip = L("Enable mixed color sublayer splitting. When enabled, layers containing mixed color "
"filaments will be split into sub-layers to achieve color mixing effects.");
def->category = L("Quality");
def->mode = comSimple;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("enable_prime_tower", coBool);
def->label = L("Enable");
def->tooltip = L("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.");
@@ -9605,7 +9670,15 @@ t_config_option_keys DynamicPrintConfig::normalize_fdm_2(int num_objects, int us
ConfigOptionBool *enable_wrapping_opt = this->option<ConfigOptionBool>("enable_wrapping_detection");
bool enable_wrapping = enable_wrapping_opt != nullptr && enable_wrapping_opt->value;
if (!is_smooth_timelapse && !enable_wrapping && (used_filaments == 1 || (ps_opt->value == PrintSequence::ByObject && num_objects > 1))) {
bool has_mixed_filament = false;
{
auto *mixed_opt = this->option<ConfigOptionBools>("filament_is_mixed");
if (mixed_opt)
has_mixed_filament = has_any_mixed_filament(mixed_opt->values);
}
if (!is_smooth_timelapse && !enable_wrapping
&& ( (used_filaments == 1 && !has_mixed_filament)
|| (ps_opt->value == PrintSequence::ByObject && num_objects > 1))) {
if (ept_opt->value) {
ept_opt->value = false;
changed_keys.push_back("enable_prime_tower");
@@ -11753,6 +11826,23 @@ std::map<std::string, std::string> validate(const FullPrintConfig &cfg, bool und
}
}
// Mixed-color (混色) parameter validation.
{
const auto &is_mixed = cfg.filament_is_mixed.values;
const auto &comp_strs = cfg.filament_mixed_components.values;
const auto &ratio_strs = cfg.filament_mixed_sublayer_ratios.values;
const auto &gradient_flags = cfg.filament_mixed_gradient.values;
const auto &range_strs = cfg.filament_mixed_gradient_range.values;
const auto &curve_strs = cfg.filament_mixed_gradient_curve.values;
std::map<std::string, std::string> mixed_errors = validate_mixed_filament_params(
is_mixed, comp_strs, ratio_strs, gradient_flags,
range_strs, curve_strs);
for (const auto &kv : mixed_errors)
if (error_message.find(kv.first) == error_message.end())
error_message.emplace(kv.first, kv.second);
}
// The configuration is valid.
return error_message;
}
+11 -1
View File
@@ -1538,6 +1538,14 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionStrings, filament_colour))
((ConfigOptionStrings, filament_vendor))
((ConfigOptionBools, filament_is_support))
// Mixed-color filament: a virtual slot realized from 2-3 physical filaments.
((ConfigOptionBools, filament_is_mixed))
((ConfigOptionStrings, filament_mixed_components))
((ConfigOptionStrings, filament_mixed_sublayer_ratios))
((ConfigOptionBools, filament_mixed_gradient))
((ConfigOptionStrings, filament_mixed_gradient_range))
((ConfigOptionStrings, filament_mixed_gradient_curve))
((ConfigOptionBools, filament_mixed_gradient_per_part))
((ConfigOptionInts, filament_printable))
((ConfigOptionInts, filament_extruder_compatibility))
((ConfigOptionFloats, filament_change_length))
@@ -1838,6 +1846,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
((ConfigOptionInts, nozzle_temperature_range_low))
((ConfigOptionInts, nozzle_temperature_range_high))
((ConfigOptionFloats, wipe_distance))
((ConfigOptionBool, enable_mixed_color_sublayer))
((ConfigOptionBool, enable_prime_tower))
((ConfigOptionBool, prime_tower_enable_framework))
// BBS: change wipe_tower_x and wipe_tower_y data type to floats to add partplate logic
@@ -2488,7 +2497,8 @@ namespace cereal {
archive(serialization_key_ordinal);
assert(serialization_key_ordinal > 0);
auto it = Slic3r::print_config_def.by_serialization_key_ordinal.find(serialization_key_ordinal);
assert(it != Slic3r::print_config_def.by_serialization_key_ordinal.end());
if (it == Slic3r::print_config_def.by_serialization_key_ordinal.end())
throw std::runtime_error("VendorCache: unknown serialization_key_ordinal " + std::to_string(serialization_key_ordinal) + " - cache is stale");
config.set_key_value(it->second->opt_key, it->second->load_option_from_archive(archive));
}
}
+2
View File
@@ -1,4 +1,6 @@
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <libslic3r/SLA/SupportTreeBuilder.hpp>
#include <libslic3r/SLA/SupportTreeBuildsteps.hpp>

Some files were not shown because too many files have changed in this diff Show More