Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21a31660d2 | ||
|
|
db0e14ceab | ||
|
|
81b8b01a01 | ||
|
|
2f4c9ab66d | ||
|
|
d766854af7 | ||
|
|
2355bb998d | ||
|
|
e8b63da1e2 | ||
|
|
013ac898ba | ||
|
|
5c7cb6bed5 | ||
|
|
3aefae016f | ||
|
|
e245f5d069 | ||
|
|
96f2c8e698 | ||
|
|
d855bab19d | ||
|
|
cde889a7c3 | ||
|
|
56a452875e | ||
|
|
600f0f20bd | ||
|
|
05b3c9053e | ||
|
|
dfb102f68d | ||
|
|
db29f570bd | ||
|
|
cc390f11ee | ||
|
|
6d1584844e | ||
|
|
6fdd4945c1 | ||
|
|
cbd1bf2c37 | ||
|
|
045504c880 | ||
|
|
4c71ec4770 | ||
|
|
3ab5157a49 | ||
|
|
213161b7cd | ||
|
|
142c63ab0e | ||
|
|
dbcb196f4e | ||
|
|
5552ed6cf1 | ||
|
|
9dc9b42475 | ||
|
|
1e4b48c548 | ||
|
|
6166bac17a | ||
|
|
24967b543a | ||
|
|
ea4a4a60f1 | ||
|
|
a5223279ac | ||
|
|
265ae16160 | ||
|
|
9e34dde632 | ||
|
|
bfe5f7e63c | ||
|
|
56f9edc572 | ||
|
|
390e47a8c6 | ||
|
|
2f9ef86e97 | ||
|
|
fbe4cdff23 | ||
|
|
a3231aa723 | ||
|
|
ce75a66e7c | ||
|
|
524fd5e9c0 | ||
|
|
0fa25acda8 | ||
|
|
1631d3cf01 | ||
|
|
55812a7a8d | ||
|
|
e342698d8e | ||
|
|
d61e0cb7bf | ||
|
|
07b81cfdc9 | ||
|
|
d7fed95390 | ||
|
|
c72908e377 | ||
|
|
ea376e858c | ||
|
|
877180829c | ||
|
|
2b1499a087 | ||
|
|
7934814077 | ||
|
|
4a32a9e066 | ||
|
|
ff35dacf4c | ||
|
|
6f32d59997 | ||
|
|
f02423074c | ||
|
|
38d51783ae | ||
|
|
af5397d678 | ||
|
|
9985688b5b | ||
|
|
d27766aff0 | ||
|
|
cfeca9b9ff | ||
|
|
716bba53df | ||
|
|
8965b0be21 | ||
|
|
0c3d7c6ed1 | ||
|
|
2131ef0560 | ||
|
|
6745a33d53 | ||
|
|
b2e1870a14 | ||
|
|
6e52c091f3 | ||
|
|
1b5b8fce54 | ||
|
|
b1e3cdc666 | ||
|
|
94a1cd6c93 | ||
|
|
fcdfcae427 | ||
|
|
9d733e50f9 | ||
|
|
3c37bf9ca4 | ||
|
|
42f708bbb6 | ||
|
|
86a7e93a48 | ||
|
|
72a68e9a0f | ||
|
|
ccd34ab03a | ||
|
|
76f23396ea | ||
|
|
51bc06a68a | ||
|
|
8b20a4b066 | ||
|
|
8fea099d99 | ||
|
|
550e234a37 | ||
|
|
3b4e65d8a9 | ||
|
|
4b397fc2cc | ||
|
|
90f76fa28c | ||
|
|
f05444dc94 | ||
|
|
5ed56eb876 | ||
|
|
6ef02a67db | ||
|
|
ca65f0fd8e | ||
|
|
87ca2bc42e | ||
|
|
aa233a82a5 | ||
|
|
aaa8e98bb0 | ||
|
|
dc75ce6811 | ||
|
|
165a1e9f4c | ||
|
|
ba22973919 | ||
|
|
f5f3d2221d | ||
|
|
8047141981 | ||
|
|
c215d0291b | ||
|
|
872c660cb3 | ||
|
|
35db2cd89b | ||
|
|
1e87d56482 | ||
|
|
1c90ba78a5 | ||
|
|
bb1e68aa94 | ||
|
|
02f148123d | ||
|
|
7c55b07736 | ||
|
|
156e096a9b | ||
|
|
050ebbb1f4 | ||
|
|
e840187edc | ||
|
|
5be1f8f209 | ||
|
|
02736fee16 | ||
|
|
ffee402494 | ||
|
|
4fd7fdb3fa | ||
|
|
322dc9b6a6 | ||
|
|
6c0f5eee55 | ||
|
|
6a52ea1818 | ||
|
|
b6e4f52c05 | ||
|
|
ba22a87a0b | ||
|
|
542cd18d19 | ||
|
|
57092d5abd | ||
|
|
f529692ac0 | ||
|
|
728cf63c3d | ||
|
|
86a63e7e2f | ||
|
|
9c7e6711c6 | ||
|
|
adcbdddc12 | ||
|
|
7e3724b5f3 | ||
|
|
dd910dcb85 | ||
|
|
bf40951a4f | ||
|
|
97955dbab8 | ||
|
|
4531dc2af1 | ||
|
|
2c8f56dd84 | ||
|
|
ec31750330 | ||
|
|
111364d880 | ||
|
|
58b17f08e0 | ||
|
|
9d37ee4709 | ||
|
|
73131735a2 | ||
|
|
7580d8ef8c | ||
|
|
e9ca9d41d1 | ||
|
|
d5dbd96dd6 | ||
|
|
0225cadff0 | ||
|
|
c5aedd1cea | ||
|
|
78eef79ffe | ||
|
|
56d2c527cb | ||
|
|
fd23b74b99 | ||
|
|
41c107d4f7 | ||
|
|
86d4429197 | ||
|
|
43ec8805b1 | ||
|
|
482da7288f | ||
|
|
547bcc7b03 | ||
|
|
5b7a58c8bb | ||
|
|
b10c91cf11 | ||
|
|
2d9a3be88f | ||
|
|
936900d4d8 | ||
|
|
50dfcff031 | ||
|
|
e2eebc69dd | ||
|
|
dc4562cbfc | ||
|
|
7382a15b89 | ||
|
|
0325f94de1 | ||
|
|
ce53d34b4d | ||
|
|
26383d5c22 | ||
|
|
76e3da15e3 | ||
|
|
a9be080ebc | ||
|
|
7b5f8d00a0 | ||
|
|
76546d89f1 | ||
|
|
004aea23c8 | ||
|
|
3045ff7788 | ||
|
|
fed03193e2 | ||
|
|
c3d9c27091 | ||
|
|
240227de79 | ||
|
|
be2be5c831 | ||
|
|
2ae0a52928 | ||
|
|
d325b6b85c | ||
|
|
b612cfa38b | ||
|
|
0f06620d40 | ||
|
|
fbc5dbcfd4 | ||
|
|
297572dc03 | ||
|
|
8832d54b53 | ||
|
|
7c09b0bcba | ||
|
|
56ac17f085 | ||
|
|
4196c23d44 | ||
|
|
d322b1a156 | ||
|
|
ee6613a4b8 | ||
|
|
e9d421050e | ||
|
|
d926f7c490 | ||
|
|
5e6895ddd2 | ||
|
|
6dbdb1d07e | ||
|
|
117ed0060d | ||
|
|
c5d2944ee0 | ||
|
|
5005ecc88b | ||
|
|
7be7f07551 | ||
|
|
54fe28ab08 | ||
|
|
b422636740 | ||
|
|
5d6008eed2 | ||
|
|
c806a09c7c | ||
|
|
1a8f39c5f7 | ||
|
|
9421e7fa9b | ||
|
|
af9fd10d7a | ||
|
|
74aed7a2bb | ||
|
|
8bff9aaf32 | ||
|
|
83723e2a7b | ||
|
|
e2fd46f82c | ||
|
|
b216813bf0 | ||
|
|
b3296fa199 | ||
|
|
6d9a9eeb04 | ||
|
|
8e243faa3a | ||
|
|
b5412221b6 | ||
|
|
f444176df8 | ||
|
|
a684c6daf6 | ||
|
|
7f10c73dce | ||
|
|
945520b827 | ||
|
|
b281c91b99 | ||
|
|
b57d7a67e2 | ||
|
|
18ca06ec6b | ||
|
|
32a4e0fb37 | ||
|
|
6345d57512 | ||
|
|
159e577543 | ||
|
|
f9ed5843c0 | ||
|
|
7c73739e1a | ||
|
|
aa4e28b2b5 | ||
|
|
408db4b3b0 | ||
|
|
169189498e | ||
|
|
72784cfe91 | ||
|
|
ef4815b26c | ||
|
|
b97ca3c0ac | ||
|
|
f73566dd2b | ||
|
|
7fbfb7ba87 | ||
|
|
23bd320076 | ||
|
|
b2e05d0683 | ||
|
|
274150af27 | ||
|
|
ae27a09ffe | ||
|
|
cd33f589dc | ||
|
|
9ee736fe27 | ||
|
|
ced1058b31 | ||
|
|
aae83220f1 | ||
|
|
a10d9e77cf | ||
|
|
1d023216f2 | ||
|
|
dc2796209f | ||
|
|
194ef34080 | ||
|
|
4e1caa39eb | ||
|
|
38f5c84e7f | ||
|
|
4d8ce0e8a7 | ||
|
|
38cb1ae8d1 | ||
|
|
f3f44bffcb | ||
|
|
2d3e911efa | ||
|
|
32f82b64e7 | ||
|
|
e56d7aeb80 | ||
|
|
4758dc6c68 | ||
|
|
596cbb8b2d | ||
|
|
6312caaf13 | ||
|
|
0051768206 | ||
|
|
1d078e005a | ||
|
|
82759d3899 | ||
|
|
59155f26ac | ||
|
|
56236f56a8 | ||
|
|
79dcace1ac | ||
|
|
df5a08517a | ||
|
|
5d953f915a | ||
|
|
dd2cb92685 | ||
|
|
b2f08c3ff8 | ||
|
|
75a2460649 | ||
|
|
01493d4e3a | ||
|
|
8dfc7a14b9 | ||
|
|
1534268183 | ||
|
|
501af81ba9 | ||
|
|
16c44940d2 | ||
|
|
40eab797c6 | ||
|
|
ca7fbfb007 | ||
|
|
7b404596e9 | ||
|
|
06ef58bad8 | ||
|
|
74c4a7e450 | ||
|
|
dbb991bf07 | ||
|
|
66d3f3f9c3 | ||
|
|
6b5c8af1c8 | ||
|
|
e72a3a65b2 | ||
|
|
1b71835337 | ||
|
|
f9fa1c117f | ||
|
|
6f3ca7d1b9 | ||
|
|
13ae3a1c90 | ||
|
|
fb36d5e73b | ||
|
|
abb2ab8d3f | ||
|
|
95b781745d | ||
|
|
80e64f80a6 | ||
|
|
477208a969 | ||
|
|
2e08b19d6b | ||
|
|
ea7117b7ca | ||
|
|
603a8f9c8f | ||
|
|
6a2a57bdf4 | ||
|
|
c8aacea176 | ||
|
|
4824a171f1 | ||
|
|
101f43b2d8 | ||
|
|
e01ac1f0a6 | ||
|
|
b51db32bb5 | ||
|
|
603b02f0e7 | ||
|
|
54dc5a2f1d | ||
|
|
303be94262 | ||
|
|
58bad17af9 | ||
|
|
ddce030322 | ||
|
|
2d4b431d5f | ||
|
|
acb0be6ed9 | ||
|
|
14b05a4d8e | ||
|
|
27c468754c | ||
|
|
3ab9cf53d0 | ||
|
|
88632710d5 | ||
|
|
d434e35488 | ||
|
|
7bd53b1283 | ||
|
|
252df70ec4 | ||
|
|
6489b4cad3 | ||
|
|
086bbf986b | ||
|
|
71c4eebfc9 | ||
|
|
00f558aa18 | ||
|
|
3145f28bb7 | ||
|
|
67e1ce03a6 | ||
|
|
36bd453ac8 | ||
|
|
2db770b672 | ||
|
|
9292db2f9f | ||
|
|
29d4513694 | ||
|
|
0dc14aa876 | ||
|
|
bef47b2c70 | ||
|
|
013a9452af | ||
|
|
e00906a833 | ||
|
|
56c28fc102 | ||
|
|
2a46197322 | ||
|
|
5ede9711f5 | ||
|
|
6bcb809dd0 | ||
|
|
33dfb66aa5 | ||
|
|
ef7bfeda9c | ||
|
|
47ccca7f72 | ||
|
|
5b475e5e98 | ||
|
|
56810c8c7f | ||
|
|
c3c37e474a | ||
|
|
04e13200aa | ||
|
|
1696d5ca39 | ||
|
|
466c36eaa3 | ||
|
|
5792fef805 | ||
|
|
bc016af1c9 | ||
|
|
7a378d2fc4 | ||
|
|
2e246341d1 | ||
|
|
15fd3fc97c | ||
|
|
9513300835 | ||
|
|
f7caf0db07 | ||
|
|
00f778e863 | ||
|
|
dc1e8b6dc3 | ||
|
|
753054974b | ||
|
|
eacc236ccb | ||
|
|
345369e005 | ||
|
|
18c5d31fb2 | ||
|
|
61d2d4355a | ||
|
|
ab023f3f6d | ||
|
|
b073aa4d23 | ||
|
|
8247514ae2 | ||
|
|
00f55639d3 | ||
|
|
68d754d946 | ||
|
|
dc5a48bdfd | ||
|
|
05083bb6ab | ||
|
|
a393b21642 | ||
|
|
a7c8dcc58d | ||
|
|
0013c1da34 | ||
|
|
3514249197 | ||
|
|
7f2598d0d6 | ||
|
|
5afc6ae9b2 | ||
|
|
adb0ca3dc3 | ||
|
|
08128911e3 | ||
|
|
0a7ac3f2ac | ||
|
|
d865e9e6e1 | ||
|
|
7aaeea2bd2 | ||
|
|
9e635925c8 | ||
|
|
ec22a58c40 | ||
|
|
a636243ec0 | ||
|
|
b9e1db41a0 |
@@ -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
|
||||
|
||||
@@ -32,9 +32,17 @@ body:
|
||||
attributes:
|
||||
label: OrcaSlicer Version
|
||||
description: Which version of Orca Slicer are you running? You can see the full version in `Help` -> `About Orca Slicer`.
|
||||
placeholder: e.g. 1.9.0
|
||||
placeholder: e.g. 2.5.0
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: working_version
|
||||
attributes:
|
||||
label: Regression compared to a previous version
|
||||
description: Did it work in a previous version?
|
||||
placeholder: e.g. 2.3.2
|
||||
validations:
|
||||
required: false
|
||||
- type: dropdown
|
||||
id: os_type
|
||||
attributes:
|
||||
|
||||
@@ -14,6 +14,7 @@ on:
|
||||
- 'localization/**'
|
||||
- 'resources/**'
|
||||
- ".github/workflows/build_*.yml"
|
||||
- 'scripts/build_preset_cache.*'
|
||||
- 'scripts/flatpak/**'
|
||||
- 'scripts/msix/**'
|
||||
- 'tests/**'
|
||||
@@ -33,6 +34,7 @@ on:
|
||||
- 'build_release_vs.bat'
|
||||
- 'build_release_vs2022.bat'
|
||||
- 'build_release_macos.sh'
|
||||
- 'scripts/build_preset_cache.*'
|
||||
- 'scripts/flatpak/**'
|
||||
- 'scripts/msix/**'
|
||||
- 'tests/**'
|
||||
|
||||
@@ -149,7 +149,7 @@ jobs:
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
if [ -z "${{ vars.SELF_HOSTED }}" ]; then
|
||||
brew install automake texinfo libtool
|
||||
brew install automake texinfo libtool pkgconf yasm nasm
|
||||
fi
|
||||
./build_release_macos.sh -dx ${{ !vars.SELF_HOSTED && '-1' || '' }} -a ${{ inputs.arch }} -t 10.15
|
||||
(cd "${{ github.workspace }}/deps/build/${{ inputs.arch }}" && \
|
||||
|
||||
@@ -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 }}
|
||||
@@ -377,6 +385,13 @@ jobs:
|
||||
dir "C:/Program Files (x86)/Windows Kits/10/Include"
|
||||
choco install nsis
|
||||
|
||||
- name: Install pkg-config
|
||||
# FFmpeg is discovered via pkg-config (pkg_check_modules LIBAV in
|
||||
# src/slic3r/CMakeLists.txt); the Windows runners don't ship it.
|
||||
if: runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||
run: |
|
||||
choco install pkgconfiglite -y
|
||||
|
||||
- name: Build slicer Win
|
||||
if: runner.os == 'Windows'
|
||||
working-directory: ${{ github.workspace }}
|
||||
@@ -390,6 +405,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 +561,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
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
name: Check profiles
|
||||
on:
|
||||
pull_request:
|
||||
# release/* is included because pr-merge-bot.yml lets delegates merge into
|
||||
# it, and it gates on this workflow's result. Without it a delegated merge
|
||||
# into a release branch would run no profile validation at all.
|
||||
branches:
|
||||
- main
|
||||
- release/*
|
||||
paths:
|
||||
- 'resources/profiles/**'
|
||||
- ".github/workflows/check_profiles.yml"
|
||||
@@ -20,6 +24,8 @@ permissions:
|
||||
|
||||
jobs:
|
||||
check_profiles:
|
||||
# This job name is the check-run name pr-merge-bot.yml requires before a
|
||||
# delegated merge. Renaming it silently disables that gate.
|
||||
name: Check profiles
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
|
||||
@@ -0,0 +1,510 @@
|
||||
name: PR Merge Bot
|
||||
|
||||
# Merges a pull request on request from a delegated vendor profile maintainer.
|
||||
# The merge is performed by this workflow's GITHUB_TOKEN, so a delegate needs no
|
||||
# repository access.
|
||||
#
|
||||
# Commands, posted as a comment on the PR:
|
||||
# /bot merge squash-merge the PR
|
||||
# /bot merge --dry-run report the verdict without merging
|
||||
#
|
||||
# Merges only when the commenter holds a grant covering every changed path, the
|
||||
# PR targets main or release/*, and CI is green on the head commit. Otherwise it
|
||||
# comments naming the files that fell outside the grant.
|
||||
#
|
||||
# Grants come from the FOLDER_MERGERS variable in the `merge-delegation`
|
||||
# environment: one per line, `account: path`, `#` comments and blank lines
|
||||
# allowed. Paths may contain spaces. A vendor takes two grants, the folder and
|
||||
# its sibling bundle JSON:
|
||||
#
|
||||
# # Acme profiles
|
||||
# vendor-maintainer: resources/profiles/Acme/
|
||||
# vendor-maintainer: resources/profiles/Acme.json
|
||||
#
|
||||
# Edit the grant list (environment scope, so admin only):
|
||||
# gh variable set FOLDER_MERGERS --env merge-delegation --body "$(cat folder-mergers.txt)"
|
||||
# gh variable get FOLDER_MERGERS --env merge-delegation
|
||||
#
|
||||
# Stop all merging without touching this file:
|
||||
# gh variable set MERGE_BOT_DRY_RUN --body true
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types:
|
||||
- created
|
||||
|
||||
# One merge attempt per PR at a time, so two quick comments cannot race.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.issue.number }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
merge:
|
||||
# Skips the job unless a PR comment mentions the command.
|
||||
if: >-
|
||||
github.repository == 'OrcaSlicer/OrcaSlicer'
|
||||
&& github.event.issue.pull_request != null
|
||||
&& contains(github.event.comment.body, '/bot merge')
|
||||
permissions:
|
||||
contents: write # pulls.merge
|
||||
pull-requests: write # pulls.merge
|
||||
issues: write # feedback comment + reactions
|
||||
actions: write # re-dispatch build_all.yml after the merge
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
# Supplies FOLDER_MERGERS. Must carry no protection rules, or every
|
||||
# delegated merge would wait for a human reviewer.
|
||||
environment: merge-delegation
|
||||
steps:
|
||||
- name: Merge PR on behalf of a folder delegate
|
||||
uses: actions/github-script@v9
|
||||
env:
|
||||
# Read as env vars, never interpolated into the script body.
|
||||
FOLDER_MERGERS: ${{ vars.FOLDER_MERGERS }}
|
||||
MERGE_BOT_DRY_RUN: ${{ vars.MERGE_BOT_DRY_RUN }}
|
||||
with:
|
||||
script: |
|
||||
function isPermissionDenied(error) {
|
||||
return error && error.status === 403 && /Resource not accessible by integration/i.test(error.message || '');
|
||||
}
|
||||
|
||||
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
const MARKER = '<!-- pr-merge-bot -->';
|
||||
// No grant may reach outside this root.
|
||||
const DELEGATABLE_ROOT = 'resources/profiles/';
|
||||
const ALLOWED_BASE_BRANCH = /^(?:main|release\/.+)$/;
|
||||
const MERGE_METHOD = 'squash';
|
||||
const REQUIRED_CHECK = 'Check profiles'; // job name in check_profiles.yml
|
||||
const MAX_CHANGED_FILES = 500; // policy cap, well under listFiles' 3000
|
||||
const LISTFILES_CAP = 3000;
|
||||
const MAX_REPORTED_FILES = 12;
|
||||
const MERGEABLE_ATTEMPTS = 5;
|
||||
const MERGEABLE_DELAY_MS = 2000;
|
||||
const OK_CONCLUSIONS = new Set(['success', 'neutral', 'skipped']);
|
||||
const REGULAR_FILE_MODES = new Set(['100644', '100755']);
|
||||
|
||||
// Paths refused whatever the grants say. Checked before grants, so
|
||||
// delegating a new root means removing it from this list too.
|
||||
const DENIED_PATTERNS = [
|
||||
/^\.github\//,
|
||||
/(^|\/)\.git(attributes|modules|ignore|config)$/,
|
||||
/^(?:src|deps|deps_src|tests|tools|cmake|sandboxes|scripts|docs?|localization|bbl)\//,
|
||||
/(^|\/)cmakelists\.txt$/,
|
||||
/\.cmake$/,
|
||||
/^build_[^/]*\.(?:sh|bat)$/,
|
||||
/^version\.inc$/,
|
||||
// Executables, including those inside the delegatable root.
|
||||
/\.(?:sh|bash|bat|cmd|ps1|py|js|mjs|cjs|ts|rb|pl|php)$/
|
||||
];
|
||||
|
||||
function parseGrants(raw) {
|
||||
// GitHub login: 1-39 chars, alphanumerics with single interior hyphens.
|
||||
const loginPattern = /^[A-Za-z0-9](?:[A-Za-z0-9]|-(?=[A-Za-z0-9])){0,38}$/;
|
||||
const grantsByLogin = new Map();
|
||||
const problems = [];
|
||||
|
||||
(raw || '').split(/\r?\n/).forEach((rawLine, index) => {
|
||||
const line = rawLine.trim();
|
||||
if (!line || line.startsWith('#')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Splits on the first colon only, so paths may contain ':' and spaces.
|
||||
const separator = line.indexOf(':');
|
||||
if (separator === -1) {
|
||||
problems.push(`line ${index + 1}: expected \`account: path\``);
|
||||
return;
|
||||
}
|
||||
|
||||
const login = line.slice(0, separator).trim().replace(/^@/, '');
|
||||
const path = line.slice(separator + 1).trim().replace(/\/+$/, '');
|
||||
|
||||
if (!loginPattern.test(login)) {
|
||||
problems.push(`line ${index + 1}: \`${login}\` is not a valid GitHub account name`);
|
||||
return;
|
||||
}
|
||||
if (/[\\*?\u0000-\u001f\u007f]/.test(path) || path.split('/').includes('..') || path.includes('//')) {
|
||||
problems.push(`line ${index + 1}: invalid path (no globs, \`..\`, \`//\`, backslashes or control characters)`);
|
||||
return;
|
||||
}
|
||||
// Rejects anything outside the root, and the bare root itself.
|
||||
if (!path.startsWith(DELEGATABLE_ROOT) || path.length <= DELEGATABLE_ROOT.length) {
|
||||
problems.push(`line ${index + 1}: \`${path}\` is not inside \`${DELEGATABLE_ROOT}\``);
|
||||
return;
|
||||
}
|
||||
|
||||
const key = login.toLowerCase();
|
||||
grantsByLogin.set(key, (grantsByLogin.get(key) || []).concat(path));
|
||||
});
|
||||
|
||||
return { grantsByLogin, problems };
|
||||
}
|
||||
|
||||
function isDenied(path) {
|
||||
if (/[\\\u0000-\u001f\u007f]/.test(path) || path.startsWith('/') || path.split('/').includes('..')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const normalized = path.normalize('NFKC').toLowerCase();
|
||||
return DENIED_PATTERNS.some((pattern) => pattern.test(normalized));
|
||||
}
|
||||
|
||||
// Byte-exact match on directory boundaries, so a grant of
|
||||
// `.../Acme` covers neither `.../Acme Labs/x.json` nor `.../Acme.json`.
|
||||
function isGranted(path, grants) {
|
||||
return grants.some((grant) => path === grant || path.startsWith(`${grant}/`));
|
||||
}
|
||||
|
||||
// Both endpoints of a rename; both must satisfy the grant.
|
||||
function pathsFor(file) {
|
||||
return [file.filename, file.previous_filename].filter(Boolean);
|
||||
}
|
||||
|
||||
function formatList(items) {
|
||||
const unique = [...new Set(items)];
|
||||
const shown = unique.slice(0, MAX_REPORTED_FILES).map((item) => `- \`${item}\``);
|
||||
if (unique.length > MAX_REPORTED_FILES) {
|
||||
shown.push(`- …and ${unique.length - MAX_REPORTED_FILES} more`);
|
||||
}
|
||||
return shown.join('\n');
|
||||
}
|
||||
|
||||
const { owner, repo } = context.repo;
|
||||
const issue = context.payload.issue;
|
||||
const comment = context.payload.comment;
|
||||
|
||||
if (!issue.pull_request) {
|
||||
core.info('Ignoring comment that is not on a pull request.');
|
||||
return;
|
||||
}
|
||||
// Ignores a comment whose sender is not its author.
|
||||
if (context.payload.action !== 'created' || context.payload.sender.login !== comment.user.login) {
|
||||
core.warning('Ignoring comment whose sender does not match its author.');
|
||||
return;
|
||||
}
|
||||
if (comment.user.type !== 'User') {
|
||||
core.info('Ignoring bot-authored command.');
|
||||
return;
|
||||
}
|
||||
|
||||
const commandLine = (comment.body || '')
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.find((line) => /^\/bot\s+merge\b/i.test(line));
|
||||
|
||||
if (!commandLine) {
|
||||
core.info('No /bot merge command found.');
|
||||
return;
|
||||
}
|
||||
|
||||
const commenter = comment.user.login;
|
||||
const { grantsByLogin, problems } = parseGrants(process.env.FOLDER_MERGERS);
|
||||
const grants = grantsByLogin.get(commenter.toLowerCase()) || [];
|
||||
|
||||
for (const problem of problems) {
|
||||
core.warning(`FOLDER_MERGERS ${problem}`);
|
||||
}
|
||||
|
||||
// Says nothing to accounts with no grant, so it cannot be used to spam.
|
||||
if (!grants.length) {
|
||||
core.info(`Ignoring /bot merge from @${commenter}: not listed in FOLDER_MERGERS.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Warns instead of failing when the token cannot post feedback.
|
||||
async function bestEffort(call, warning) {
|
||||
try {
|
||||
await call();
|
||||
} catch (error) {
|
||||
if (isPermissionDenied(error)) {
|
||||
core.warning(warning);
|
||||
return;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
const react = (content) => bestEffort(
|
||||
() => github.rest.reactions.createForIssueComment({ owner, repo, comment_id: comment.id, content }),
|
||||
`Cannot add the "${content}" reaction because the token cannot write.`);
|
||||
|
||||
const say = (body) => bestEffort(
|
||||
() => github.rest.issues.createComment({ owner, repo, issue_number: issue.number, body: `${MARKER}\n${body}` }),
|
||||
'Cannot post a comment because the token cannot write comments.');
|
||||
|
||||
// Declines the command: warns in the log, reacts, explains on the PR.
|
||||
async function refuse(reason) {
|
||||
const configNote = problems.length
|
||||
? `\n\n\`FOLDER_MERGERS\` also has problems a maintainer needs to fix:\n${problems.map((problem) => `- ${problem}`).join('\n')}`
|
||||
: '';
|
||||
const grantsNote = `\n\n<details><summary>Your current grants</summary>\n\n${formatList(grants)}\n\n</details>`;
|
||||
|
||||
core.warning(`Refused /bot merge from @${commenter}: ${reason}`);
|
||||
await react('-1');
|
||||
await say(`@${commenter} I can't merge this PR: ${reason}${configNote}${grantsNote}`);
|
||||
}
|
||||
|
||||
await react('eyes');
|
||||
|
||||
const args = (commandLine.match(/^\/bot\s+merge\s*(.*)$/i)[1] || '').trim().split(/\s+/).filter(Boolean);
|
||||
const unknownArgs = args.filter((arg) => arg.toLowerCase() !== '--dry-run');
|
||||
const dryRun = String(process.env.MERGE_BOT_DRY_RUN || '').toLowerCase() === 'true'
|
||||
|| unknownArgs.length !== args.length;
|
||||
|
||||
if (unknownArgs.length) {
|
||||
return refuse(
|
||||
`I don't understand ${unknownArgs.map((arg) => `\`${arg}\``).join(', ')}. ` +
|
||||
'Usage: `/bot merge` or `/bot merge --dry-run`.'
|
||||
);
|
||||
}
|
||||
|
||||
// Refuses everything while the grant list is malformed.
|
||||
if (problems.length) {
|
||||
return refuse(
|
||||
'the `FOLDER_MERGERS` grant list has malformed lines, so I refuse every merge until it is fixed.'
|
||||
);
|
||||
}
|
||||
|
||||
let { data: pr } = await github.rest.pulls.get({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: issue.number
|
||||
});
|
||||
|
||||
if (pr.merged) {
|
||||
return refuse('it is already merged.');
|
||||
}
|
||||
if (pr.state !== 'open') {
|
||||
return refuse(`its state is \`${pr.state}\`, not \`open\`.`);
|
||||
}
|
||||
if (pr.draft) {
|
||||
return refuse('it is still a draft. Mark it ready for review first.');
|
||||
}
|
||||
if (!ALLOWED_BASE_BRANCH.test(pr.base.ref)) {
|
||||
return refuse(`it targets \`${pr.base.ref}\`. Delegated merges are only allowed into \`main\` and \`release/*\`.`);
|
||||
}
|
||||
|
||||
// ---- folder scope ----
|
||||
const files = await github.paginate(github.rest.pulls.listFiles, {
|
||||
owner,
|
||||
repo,
|
||||
pull_number: pr.number,
|
||||
per_page: 100
|
||||
});
|
||||
|
||||
if (!files.length) {
|
||||
return refuse('it changes no files, so there is nothing to verify or merge.');
|
||||
}
|
||||
// Refuses when the file list is truncated or disagrees with the PR.
|
||||
if (files.length >= LISTFILES_CAP || files.length !== pr.changed_files) {
|
||||
return refuse(
|
||||
`it reports ${pr.changed_files} changed files but the API listed ${files.length}, ` +
|
||||
'so the file list is truncated and I cannot verify the folder scope. A maintainer must merge this one.'
|
||||
);
|
||||
}
|
||||
if (pr.changed_files > MAX_CHANGED_FILES) {
|
||||
return refuse(`it changes ${pr.changed_files} files; delegated merges are capped at ${MAX_CHANGED_FILES}.`);
|
||||
}
|
||||
|
||||
const deniedFiles = [];
|
||||
const outsideFiles = [];
|
||||
|
||||
for (const file of files) {
|
||||
for (const path of pathsFor(file)) {
|
||||
if (isDenied(path)) {
|
||||
deniedFiles.push(path);
|
||||
} else if (!isGranted(path, grants)) {
|
||||
outsideFiles.push(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deniedFiles.length) {
|
||||
core.error(`@${commenter} attempted a delegated merge touching protected paths: ${deniedFiles.join(', ')}`);
|
||||
return refuse(
|
||||
'it touches paths that are never delegatable, whatever the grants say ' +
|
||||
`(CI, build, scripts or executable files):\n\n${formatList(deniedFiles)}\n\nA maintainer should look at this before it goes any further.`
|
||||
);
|
||||
}
|
||||
if (outsideFiles.length) {
|
||||
return refuse(
|
||||
`${outsideFiles.length} changed path(s) fall outside your grants:\n\n${formatList(outsideFiles)}\n\n` +
|
||||
'A vendor needs both grants: `resources/profiles/<Vendor>/` **and** `resources/profiles/<Vendor>.json`.'
|
||||
);
|
||||
}
|
||||
|
||||
// ---- file modes: rejects symlinks and submodules ----
|
||||
// Fetches the delegatable subtree only; listFiles does not report modes.
|
||||
const headSha = pr.head.sha;
|
||||
const { data: tree } = await github.rest.git.getTree({
|
||||
owner,
|
||||
repo,
|
||||
tree_sha: `${headSha}:${DELEGATABLE_ROOT.replace(/\/$/, '')}`,
|
||||
recursive: 'true'
|
||||
});
|
||||
|
||||
if (tree.truncated) {
|
||||
return refuse('the git tree is too large to verify file modes. A maintainer must merge this one.');
|
||||
}
|
||||
|
||||
// Entry paths are subtree-relative.
|
||||
const modesByPath = new Map(tree.tree.map((entry) => [`${DELEGATABLE_ROOT}${entry.path}`, entry.mode]));
|
||||
const irregularFiles = files
|
||||
.filter((file) => file.status !== 'removed')
|
||||
.map((file) => [file.filename, modesByPath.get(file.filename)])
|
||||
.filter(([, mode]) => !REGULAR_FILE_MODES.has(mode))
|
||||
.map(([path, mode]) => `${path} (mode ${mode || 'missing'})`);
|
||||
|
||||
if (irregularFiles.length) {
|
||||
core.error(`@${commenter} attempted a delegated merge with non-regular files: ${irregularFiles.join(', ')}`);
|
||||
return refuse(
|
||||
`it adds symlinks, submodules or files I cannot verify:\n\n${formatList(irregularFiles)}\n\nA maintainer should look at this before it goes any further.`
|
||||
);
|
||||
}
|
||||
|
||||
// ---- mergeability: waits for GitHub to compute it ----
|
||||
for (let attempt = 0; pr.mergeable === null && attempt < MERGEABLE_ATTEMPTS; attempt += 1) {
|
||||
core.info(`Mergeability not computed yet; retrying in ${MERGEABLE_DELAY_MS}ms.`);
|
||||
await sleep(MERGEABLE_DELAY_MS);
|
||||
({ data: pr } = await github.rest.pulls.get({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: pr.number
|
||||
}));
|
||||
}
|
||||
|
||||
if (pr.mergeable === null) {
|
||||
return refuse('GitHub is still working out whether it can be merged. Try `/bot merge` again in a minute.');
|
||||
}
|
||||
if (!pr.mergeable) {
|
||||
return refuse(`it is not mergeable (\`${pr.mergeable_state}\`) - most likely a conflict with \`${pr.base.ref}\`.`);
|
||||
}
|
||||
|
||||
// ---- CI on the head commit ----
|
||||
const checkRuns = await github.paginate(github.rest.checks.listForRef, {
|
||||
owner,
|
||||
repo,
|
||||
ref: headSha,
|
||||
filter: 'latest',
|
||||
per_page: 100
|
||||
});
|
||||
const pendingChecks = checkRuns.filter((run) => run.status !== 'completed');
|
||||
const failedChecks = checkRuns.filter((run) => run.status === 'completed' && !OK_CONCLUSIONS.has(run.conclusion));
|
||||
|
||||
if (pendingChecks.length) {
|
||||
return refuse(
|
||||
`${pendingChecks.length} check(s) are still running on \`${headSha.slice(0, 7)}\`:\n\n` +
|
||||
`${formatList(pendingChecks.map((run) => run.name))}\n\nRe-run \`/bot merge\` once they finish.`
|
||||
);
|
||||
}
|
||||
if (failedChecks.length) {
|
||||
return refuse(
|
||||
`${failedChecks.length} check(s) are not green on \`${headSha.slice(0, 7)}\`:\n\n` +
|
||||
formatList(failedChecks.map((run) => `${run.name} (${run.conclusion})`))
|
||||
);
|
||||
}
|
||||
|
||||
const { data: combined } = await github.rest.repos.getCombinedStatusForRef({
|
||||
owner,
|
||||
repo,
|
||||
ref: headSha
|
||||
});
|
||||
// total_count 0 only means there are no legacy statuses.
|
||||
if (combined.total_count > 0 && combined.state !== 'success') {
|
||||
return refuse(
|
||||
`the combined commit status on \`${headSha.slice(0, 7)}\` is \`${combined.state}\`:\n\n` +
|
||||
formatList(combined.statuses.filter((status) => status.state !== 'success')
|
||||
.map((status) => `${status.context} (${status.state})`))
|
||||
);
|
||||
}
|
||||
|
||||
// Requires the check to have actually run, not merely to have not failed.
|
||||
const requiredCheck = checkRuns.find((run) =>
|
||||
run.name === REQUIRED_CHECK &&
|
||||
run.app && run.app.slug === 'github-actions' &&
|
||||
run.status === 'completed' && OK_CONCLUSIONS.has(run.conclusion));
|
||||
|
||||
if (!requiredCheck) {
|
||||
return refuse(
|
||||
`the \`${REQUIRED_CHECK}\` check has not succeeded on \`${headSha.slice(0, 7)}\`. ` +
|
||||
'If it never ran, a maintainer needs to approve the workflow run first.'
|
||||
);
|
||||
}
|
||||
|
||||
const scopeSummary = `${files.length} file(s), all within:\n${formatList(grants)}`;
|
||||
|
||||
if (dryRun) {
|
||||
core.info('Dry run: every gate passed, not merging.');
|
||||
await react('+1');
|
||||
await say(
|
||||
`@${commenter} **dry run** - this PR passes every gate and I *would* squash-merge it ` +
|
||||
`at \`${headSha.slice(0, 7)}\`.\n\nVerified scope: ${scopeSummary}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// ---- re-validate, then merge ----
|
||||
// An unchanged head SHA means the verified file list still holds.
|
||||
const { data: fresh } = await github.rest.pulls.get({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: pr.number
|
||||
});
|
||||
|
||||
if (fresh.head.sha !== headSha || fresh.base.ref !== pr.base.ref || fresh.state !== 'open' || fresh.merged || fresh.draft) {
|
||||
return refuse('it changed while I was checking it. Nothing was merged - re-run `/bot merge`.');
|
||||
}
|
||||
|
||||
let merged;
|
||||
try {
|
||||
// Pinned to the verified head: a moved head fails with 409.
|
||||
({ data: merged } = await github.rest.pulls.merge({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: pr.number,
|
||||
sha: headSha,
|
||||
merge_method: MERGE_METHOD,
|
||||
commit_title: `${pr.title} (#${pr.number})`,
|
||||
commit_message:
|
||||
`Merged by /bot merge on behalf of @${commenter} (id ${comment.user.id}).\n` +
|
||||
`Grants: ${grants.join(', ')}\nHead: ${headSha}\n`
|
||||
}));
|
||||
} catch (error) {
|
||||
const hint = {
|
||||
403: 'the workflow token cannot write to the repository.',
|
||||
405: 'GitHub refused the merge - branch protection, a required review or check, a newly added CODEOWNERS file, or squash merging being disabled.',
|
||||
409: `the head commit moved after I verified it (was \`${headSha.slice(0, 7)}\`).`,
|
||||
422: 'GitHub rejected the merge as invalid.'
|
||||
}[error.status];
|
||||
|
||||
if (!hint) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
await refuse(`${hint}\n\n> ${error.message}\n\nNothing was merged.`);
|
||||
core.setFailed(`Delegated merge failed: ${error.status} ${error.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
core.info(`Merged #${pr.number} as ${merged.sha}.`);
|
||||
await react('rocket');
|
||||
await say(
|
||||
`@${commenter} squash-merged into \`${pr.base.ref}\` as ${merged.sha}.\n\nVerified scope: ${scopeSummary}`
|
||||
);
|
||||
|
||||
// ---- re-kick the build ----
|
||||
// A GITHUB_TOKEN merge fires no push event, so build_all.yml would
|
||||
// otherwise never see these files.
|
||||
try {
|
||||
await github.rest.actions.createWorkflowDispatch({
|
||||
owner,
|
||||
repo,
|
||||
workflow_id: 'build_all.yml',
|
||||
ref: pr.base.ref
|
||||
});
|
||||
core.info(`Dispatched build_all.yml on ${pr.base.ref}.`);
|
||||
} catch (error) {
|
||||
core.warning(`Merged successfully, but dispatching build_all.yml failed: ${error.message}`);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -30,6 +30,7 @@ ctest --test-dir ./tests/fff_print
|
||||
- C++17, selective C++20. PascalCase classes, snake_case functions/variables
|
||||
- `#pragma once` for headers. Smart pointers and RAII preferred
|
||||
- Parallelization via TBB — be mindful of shared state
|
||||
- Always use `SetSizerAndFit(sizer)` instead of `SetSizer(sizer)` on top level window. Unless `SetSizer` must be called before the full layout is built, call `sizer->SetSizeHints(window)` afterwards in this case.
|
||||
|
||||
## Key Entry Points
|
||||
|
||||
@@ -55,11 +56,36 @@ ctest --test-dir ./tests/fff_print
|
||||
- Add helper functions or utilities only when existing code cannot reasonably be reused. Avoid duplication.
|
||||
- Keep code concise and clear. Manually simplify AI generated bloated codes before review.
|
||||
- Include targeted tests or documented verification for behavior changes, especially in slicing logic, profiles, formats, and GUI defaults.
|
||||
- For profile changes (`resources/profiles/<Vendor>/**`), check that `version` in the sibling `resources/profiles/<Vendor>.json` was bumped.
|
||||
- For translation changes (`localization/i18n/**/*.po`), check that recurring terms match the [Localization glossary](https://github.com/OrcaSlicer/OrcaSlicer_WIKI/blob/main/guides/localization_glossary.md) for that language.
|
||||
|
||||
## Localization & translations
|
||||
|
||||
- Translation catalogs live in `localization/i18n/<lang>/OrcaSlicer_<lang>.po`.
|
||||
- When creating or reviewing translations, use the [Localization glossary](https://github.com/OrcaSlicer/OrcaSlicer_WIKI/blob/main/guides/localization_glossary.md) as the source of truth for recurring terms, so the same English term is always rendered the same way within a language and terms that must stay in English (brand/product names, acronyms, file formats, G-code, macros/variables) are not translated.
|
||||
- If a term's established translation changes, update both the affected `.po` files and the glossary so they stay in sync.
|
||||
- Only edit `msgstr` (never `msgid`); keep placeholders (`%s`, `%1%`, `\n`), context (`msgctxt`), and file encoding/line endings intact.
|
||||
Catalogs live in `localization/i18n/<lang>/OrcaSlicer_<lang>.po`; the template is `OrcaSlicer.pot`.
|
||||
See the [Localization guide](https://github.com/OrcaSlicer/OrcaSlicer_WIKI/blob/main/guides/localization_guide.md) for the human-facing version of these principles.
|
||||
|
||||
### Terminology
|
||||
|
||||
- Use the [Localization glossary](https://github.com/OrcaSlicer/OrcaSlicer_WIKI/blob/main/guides/localization_glossary.md) as the source of truth for recurring terms, so the same English term is always rendered the same way within a language, and terms that must stay in English (brand/product names, acronyms, materials, file formats, G-code tokens, macros/variables/identifiers) are not translated.
|
||||
- If a term's established translation changes, update both the affected `.po` files and the glossary (`localization_glossary.tsv`, then regenerate) so they stay in sync.
|
||||
- Translate the *meaning*, not the words. Check what the string actually controls before translating it — English reuses one word for different things. `Flow ratio` (multiplier), `Flow Rate` (throughput) and `Flow Dynamics` (pressure compensation) are three different terms; `extruder` may mean the toolhead, the feeder motor, or the nozzle depending on the string.
|
||||
- Reuse one template per recurring message shape (`Failed to connect to …`, `Are you sure you want to …?`), even where the English wording varies.
|
||||
|
||||
### Editing rules
|
||||
|
||||
- Only edit `msgstr` — **never** change `msgid`, and never "fix" wrong English in the translation alone. Report the source string instead.
|
||||
- Preserve exactly: placeholders (`%s`, `%d`, `%1%`, `%zu`, `%%`), every `\n` (count *and* position, including leading/trailing), leading/trailing spaces, HTML tags, `℃`, and the file's encoding and line endings.
|
||||
- **Never reorder positional arguments** in a `c-format` string. If the msgid is `%d` then `%s`, that order must hold — swapping them breaks at runtime.
|
||||
- `msgctxt` separates homonyms — always read it. `Back`/`Camera View` is the rear view of the 3D navigator, while `Back`/`Navigation` is the go-back button; `Top` exists in the *Alignment*, *Layers* and *Camera View* senses.
|
||||
- When a string needs disambiguating, add context in the source (`_L_CONTEXT`/`_u8L_CONTEXT`), don't work around it in the translation.
|
||||
- A literal `%` inside a string xgettext flagged `possible-c-format` will fail `msgfmt`. Fix it with a `// xgettext:no-c-format, no-boost-format` comment above the string in the source — do not mangle the translation or use `%%` in text that is never passed through printf.
|
||||
- Plural entries: read `nplurals` from the catalog's `Plural-Forms` header (it is **not** always 2 — ja/ko/zh/th/vi use 1, ru/cs/pl/lt use 3, uk uses 4). Each form must be genuinely inflected for its quantity; repeating one sentence across all forms is a bug in Slavic/Baltic languages, though it is correct for Turkish and Hungarian.
|
||||
- An entry whose `msgstr` equals its `msgid` is untranslated even though it is not empty; a plural entry with any empty form is likewise incomplete.
|
||||
- Mark machine-produced translations with an `# AI Translated` translator comment. Don't add it to a human translation you didn't actually rewrite.
|
||||
- Don't reflow or re-wrap unrelated entries — keep the diff limited to the strings you changed.
|
||||
|
||||
### Verifying
|
||||
|
||||
- `scripts/run_gettext.bat --full` (Windows) regenerates the template, merges every catalog and compiles the `.mo` files. It must exit 0.
|
||||
- Or check a single catalog with `msgfmt --check-format -o <out>.mo localization/i18n/<lang>/OrcaSlicer_<lang>.po`.
|
||||
- Fuzzy entries are not shown to users. If you correct one, clear its `fuzzy` flag, otherwise the fix never ships.
|
||||
|
||||
@@ -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
|
||||
@@ -80,8 +87,12 @@ endif()
|
||||
|
||||
if (DEFINED BBL_RELEASE_TO_PUBLIC)
|
||||
add_compile_definitions("BBL_RELEASE_TO_PUBLIC=${BBL_RELEASE_TO_PUBLIC}")
|
||||
if (BBL_RELEASE_TO_PUBLIC)
|
||||
add_compile_definitions(WXINSPECTOR_DISABLE)
|
||||
endif ()
|
||||
else ()
|
||||
add_compile_definitions("BBL_RELEASE_TO_PUBLIC=$<CONFIG:Release>")
|
||||
add_compile_definitions("$<$<CONFIG:Release>:WXINSPECTOR_DISABLE>")
|
||||
endif ()
|
||||
|
||||
find_package(Git)
|
||||
@@ -122,6 +133,8 @@ option(SLIC3R_GUI "Compile OrcaSlicer with GUI components (OpenGL,
|
||||
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)
|
||||
@@ -285,6 +298,8 @@ if (APPLE)
|
||||
SET(CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.orcaslicer.OrcaSlicer")
|
||||
|
||||
message(STATUS "Orca: IS_CROSS_COMPILE: ${IS_CROSS_COMPILE}")
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
set(CMAKE_INSTALL_RPATH "$ORIGIN")
|
||||
endif ()
|
||||
|
||||
# Proposal for C++ unit tests and sandboxes
|
||||
@@ -331,15 +346,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)
|
||||
@@ -456,7 +476,8 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
# WIN10SDK_PATH is used to point CMake to the WIN10 SDK installation directory.
|
||||
# We pick it from environment if it is not defined in another way
|
||||
# ORCA: Removed Netfabb STL fixing service support in favor of CGAL.
|
||||
# if(WIN32)
|
||||
if(WIN32)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
# if(NOT DEFINED WIN10SDK_PATH)
|
||||
# if(DEFINED ENV{WIN10SDK_PATH})
|
||||
# set(WIN10SDK_PATH "$ENV{WIN10SDK_PATH}")
|
||||
@@ -492,7 +513,7 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
# else()
|
||||
# message("Building without Win10 Netfabb STL fixing service support")
|
||||
# endif()
|
||||
# endif()
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
message("OS X SDK Path: ${CMAKE_OSX_SYSROOT}")
|
||||
@@ -519,8 +540,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" )
|
||||
@@ -1040,6 +1068,10 @@ function(orcaslicer_copy_dlls target config postfix output_dlls)
|
||||
${CMAKE_PREFIX_PATH}/bin/occt/TKXDESTEP.dll
|
||||
${CMAKE_PREFIX_PATH}/bin/occt/TKXSBase.dll
|
||||
${CMAKE_PREFIX_PATH}/bin/freetype.dll
|
||||
${CMAKE_PREFIX_PATH}/bin/avcodec-61.dll
|
||||
${CMAKE_PREFIX_PATH}/bin/swresample-5.dll
|
||||
${CMAKE_PREFIX_PATH}/bin/swscale-8.dll
|
||||
${CMAKE_PREFIX_PATH}/bin/avutil-59.dll
|
||||
DESTINATION ${_out_dir})
|
||||
|
||||
set(${output_dlls}
|
||||
@@ -1075,15 +1107,110 @@ function(orcaslicer_copy_dlls target config postfix output_dlls)
|
||||
${_out_dir}/TKXSBase.dll
|
||||
|
||||
${_out_dir}/freetype.dll
|
||||
|
||||
${_out_dir}/avcodec-61.dll
|
||||
${_out_dir}/swresample-5.dll
|
||||
${_out_dir}/swscale-8.dll
|
||||
${_out_dir}/avutil-59.dll
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
endfunction()
|
||||
|
||||
function(orcaslicer_copy_sos target config postfix output_sos)
|
||||
|
||||
get_property(_is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
get_target_property(_alt_out_dir ${target} RUNTIME_OUTPUT_DIRECTORY)
|
||||
|
||||
if (_alt_out_dir)
|
||||
set(_out_dir "${_alt_out_dir}")
|
||||
elseif (_is_multi)
|
||||
set(_out_dir "${CMAKE_CURRENT_BINARY_DIR}/${config}")
|
||||
else ()
|
||||
set(_out_dir "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif ()
|
||||
|
||||
file(COPY ${CMAKE_PREFIX_PATH}/lib/libavcodec.so
|
||||
${CMAKE_PREFIX_PATH}/lib/libavcodec.so.61
|
||||
${CMAKE_PREFIX_PATH}/lib/libavcodec.so.61.3.100
|
||||
${CMAKE_PREFIX_PATH}/lib/libavutil.so
|
||||
${CMAKE_PREFIX_PATH}/lib/libavutil.so.59
|
||||
${CMAKE_PREFIX_PATH}/lib/libavutil.so.59.8.100
|
||||
${CMAKE_PREFIX_PATH}/lib/libswscale.so
|
||||
${CMAKE_PREFIX_PATH}/lib/libswscale.so.8
|
||||
${CMAKE_PREFIX_PATH}/lib/libswscale.so.8.1.100
|
||||
${CMAKE_PREFIX_PATH}/lib/libswresample.so
|
||||
${CMAKE_PREFIX_PATH}/lib/libswresample.so.5
|
||||
${CMAKE_PREFIX_PATH}/lib/libswresample.so.5.1.100
|
||||
DESTINATION ${_out_dir})
|
||||
|
||||
set(${output_sos}
|
||||
${_out_dir}/libavcodec.so
|
||||
${_out_dir}/libavcodec.so.61
|
||||
${_out_dir}/libavcodec.so.61.3.100
|
||||
${_out_dir}/libavutil.so
|
||||
${_out_dir}/libavutil.so.59
|
||||
${_out_dir}/libavutil.so.59.8.100
|
||||
${_out_dir}/libswscale.so
|
||||
${_out_dir}/libswscale.so.8
|
||||
${_out_dir}/libswscale.so.8.1.100
|
||||
${_out_dir}/libswresample.so
|
||||
${_out_dir}/libswresample.so.5
|
||||
${_out_dir}/libswresample.so.5.1.100
|
||||
PARENT_SCOPE
|
||||
)
|
||||
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)
|
||||
|
||||
@@ -1095,6 +1222,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)
|
||||
@@ -1139,6 +1270,20 @@ else ()
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
set(LIBRARY_FILES
|
||||
${LIBDIR_BIN}/libavcodec.so.61
|
||||
${LIBDIR_BIN}/libavcodec.so.61.3.100
|
||||
${LIBDIR_BIN}/libavutil.so.59
|
||||
${LIBDIR_BIN}/libavutil.so.59.8.100
|
||||
${LIBDIR_BIN}/libswresample.so.5
|
||||
${LIBDIR_BIN}/libswresample.so.5.1.100
|
||||
${LIBDIR_BIN}/libswscale.so.8
|
||||
${LIBDIR_BIN}/libswscale.so.8.1.100
|
||||
)
|
||||
install(FILES ${LIBRARY_FILES} DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
|
||||
endif ()
|
||||
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/LICENSE.txt DESTINATION ".")
|
||||
configure_file(${LIBDIR}/dev-utils/platform/unix/fhs.hpp.in ${LIBDIR_BIN}/dev-utils/platform/unix/fhs.hpp)
|
||||
|
||||
|
||||
@@ -119,6 +119,10 @@ Download the **Windows Installer exe** for your preferred version from the [rele
|
||||
- This file may already be available on your computer if you've installed visual studio. Check the following location: `%VCINSTALLDIR%Redist\MSVC\v142`
|
||||
</details>
|
||||
|
||||
### Microsoft Store
|
||||
|
||||
Install from the [Microsoft Store](https://apps.microsoft.com/detail/9mv6gl23xm59) when you prefer a Store-signed package (helps on Windows 11 Smart App Control).
|
||||
|
||||
### Windows Package Manager
|
||||
|
||||
```shell
|
||||
|
||||
@@ -0,0 +1,581 @@
|
||||
# Texture Displacement - Technical Notes
|
||||
|
||||
Branch: `feature/texture_displacement`. Reference for the feature as it stands: what it does, how the
|
||||
algorithms work, and where the code lives.
|
||||
|
||||
## What it does
|
||||
|
||||
A paint-style gizmo (`GLGizmoTextureDisplacement`) that lets you:
|
||||
- Paint one or more "layers" onto a model's surface, each a height-map texture with its own
|
||||
depth/tiling/rotation/offset/invert/tile-mode/projection-mode/blend-mode.
|
||||
- Pick a texture from a shipped library (`resources/textures/displacement/`) or import your own
|
||||
(saved into `<data_dir>/textures/displacement/`, kept separate so app updates can't clobber it).
|
||||
- Combine overlapping layers with image-editor-style blend modes (Add/Subtract/Multiply/Divide).
|
||||
- Preview the true displaced result live, before baking (background job, not on the UI thread).
|
||||
- Preview via a fast GPU shader instead (no real geometry movement) for a lighter-weight alternative.
|
||||
- Bake into real mesh geometry on demand, restricted to the painted area only.
|
||||
- Remesh and subdivide so a low-poly model has enough vertices to show fine detail.
|
||||
- Unwrap a painted patch with a real CGAL LSCM parameterization and view it in a dedicated,
|
||||
dockable 2D "UV Editor" pane.
|
||||
|
||||
## Standard vs Pro mode
|
||||
|
||||
A two-position slider in the panel header, right of the Dock/Undock button.
|
||||
|
||||
**Pro** shows every mesh-preparation control; Remesh, Subdivide and Bake are run separately by the user,
|
||||
in whatever order they like.
|
||||
|
||||
**Standard** hides all of it and folds one fixed recipe into the Bake button, because a height map only
|
||||
ever *moves vertices that already exist* - painting onto an imported 12-triangle box and pressing Bake
|
||||
would otherwise do nothing visible. Standard's Bake is:
|
||||
|
||||
1. `plan_remesh()` + `replace_mesh_keep_all_paint()` - isotropic remesh to 1 mm, sharp edges above 40
|
||||
degrees protected. Gives the subdivider an even starting density whatever the input looked like.
|
||||
2. `plan_adaptive_subdivision()` + `apply_adaptive_subdivision()` - feature-adaptive refinement, max
|
||||
edge 20 mm, detail 0.02 mm, min edge 0.02 mm.
|
||||
3. `bake()` - the ordinary background displacement job.
|
||||
|
||||
Both preparation stages are *planned* before the undo snapshot and *applied* after it, so a stage with
|
||||
nothing to do is skipped without leaving an empty undo step. The standalone Pro buttons share the same
|
||||
plan/apply split.
|
||||
|
||||
**All three stages sit under one undo step.** `Plater::take_snapshot()` records the state *before* the
|
||||
change, so a single snapshot taken at the top of `bake_standard()` means one Undo returns the mesh to
|
||||
exactly what was imported. `TextureDisplacementBakeInput::take_snapshot` lets the caller say who owns
|
||||
the undo step - true for the Pro-mode button, false for the pipeline, whose background job commits long
|
||||
after that snapshot's scope has closed.
|
||||
|
||||
The presets live in one place (`STD_*` constants) and `apply_standard_mode_presets()` pins the hidden
|
||||
controls to them every frame while Standard is active, so the live preview cannot disagree with what
|
||||
Bake will do. Switching to Standard also closes the subdivision preview, whose controls have just gone.
|
||||
|
||||
One control survives into Standard: **"Added triangles (k)"**, the subdivision budget. It is deliberately
|
||||
*not* pinned - pinning would fight the user's own slider every frame - because unlike the rest of the
|
||||
recipe its right value depends on the part rather than on the method (a big model, or a fine texture,
|
||||
simply needs more triangles). Default 1500. The widget is one lambda shared by both layouts.
|
||||
|
||||
Standard remeshes *after* painting, so the remesh has to preserve paint: `ModelVolume::restore_painting()`
|
||||
only remaps the four standard channels, so `replace_mesh_keep_all_paint()` additionally runs
|
||||
`TriangleSelector::remap_painting()` over the eight texture-displacement masks. The Pro Remesh button
|
||||
goes through the same helper. If the remap comes back empty the pipeline stops with a message rather
|
||||
than baking a flat mesh.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Data model (per `ModelVolume`)
|
||||
|
||||
Each of up to `TEXTURE_DISPLACEMENT_MAX_LAYERS` (8) layers gets its **own independent
|
||||
`FacetsAnnotation`** paint mask - the same `TriangleSelector`/`FacetsAnnotation` machinery every other
|
||||
paint gizmo (FdmSupports, Seam, MMU, FuzzySkin) already uses, just one full instance per layer slot
|
||||
instead of one per volume. This is what makes layered/blended painting work for free: the same triangle
|
||||
can be `ENFORCER` in layer 2's mask and layer 5's mask simultaneously, and at bake/preview time each
|
||||
layer displaces the surface left by the previous one (image-editor-layer semantics).
|
||||
|
||||
Whole-stack settings (border handling, post-process smoothing) live beside the layers in
|
||||
`texture_displacement_options` (`TextureDisplacementOptions`), since they belong to no single layer.
|
||||
|
||||
### Bake algorithm (`libslic3r/TextureDisplacement.cpp`)
|
||||
|
||||
`build_texture_displacement(base_mesh, layers, facets_data, options)` is **accumulate-then-displace,
|
||||
and topology-preserving**: the returned mesh has exactly the input's vertices and triangles, in the
|
||||
same order - only the positions of displaced vertices differ.
|
||||
|
||||
1. `its_compactify_vertices()` on a copy of the input. In practice a no-op (it only drops
|
||||
*unreferenced* vertices, and preserves the order and indices of the rest). It is there to
|
||||
guarantee the index alignment step 3 depends on.
|
||||
2. Area-weighted vertex normals of the **undisplaced** mesh, computed once. Every layer both projects
|
||||
and displaces along these, so a vertex covered by several layers moves along one single well-defined
|
||||
direction. Where the paint does *not* cover every triangle around a vertex, the normal is recomputed
|
||||
from the painted triangles alone (the union over all layers, so it stays one direction per vertex):
|
||||
on the rim of a fully painted top face the whole-mesh normal is the 45-degree bisector it shares with
|
||||
the side wall, and displacing along that flares the rim outwards instead of raising it. Interior
|
||||
vertices are unaffected - all their triangles are painted, so the two normals coincide. Paint
|
||||
coverage per original triangle comes straight off `TriangleSplittingData::triangles_to_split`.
|
||||
3. For each layer in slot order: deserialize its stored paint mask into a `TriangleSelector` against
|
||||
the **base mesh** (never against a previous layer's output), then
|
||||
`selector.get_facets_strict(ENFORCER)` → the painted patch. Two facts are exploited:
|
||||
- `get_facets_strict()` returns the mesh's **entire** referenced vertex array regardless of which
|
||||
state was asked for - only `.indices` is filtered by state. So `get_facets_strict(ENFORCER)`
|
||||
and `get_facets_strict(NONE)` share identical vertex indexing, which is what lets boundary
|
||||
detection be a plain index check instead of a position-hash lookup.
|
||||
- The selector's vertex array *starts with* the mesh's own vertices (extra ones created where a
|
||||
brush stroke split a triangle are appended after them), and `get_facets_strict()` emits the
|
||||
referenced ones in order. Combined with step 1, **selector vertex index `i` is our vertex `i`**.
|
||||
Split vertices live past the end of our array and are simply skipped - they sit on the paint
|
||||
boundary anyway (splitting only happens at partial coverage).
|
||||
4. A vertex used by at least one **unpainted** triangle is a border vertex. Whether it moves is
|
||||
`TextureDisplacementOptions::displace_border`, and it does by default. Nothing can tear: the bake is
|
||||
topology-preserving, so a border vertex is *one* vertex shared by both regions and moving it simply
|
||||
tilts the unpainted triangles that use it. Pinning it instead clamps the outermost ring of relief to
|
||||
zero, which on a fully painted face collapses the pattern into a ring of steep ramps at the edge; it
|
||||
is kept as an option for when the relief must not spill past the paint at all. Either way the border
|
||||
drives the `edge_smoothing` falloff.
|
||||
5. Per interior vertex: sample the height texture (`sample_layer_height()`, see Projection methods)
|
||||
and fold `height * depth_mm * (invert ? -1 : 1)` into that vertex's running total via the layer's
|
||||
`TextureBlendMode` (see Blend modes). A `visited` set makes each layer fold in exactly **once**
|
||||
per vertex, no matter how many of the patch's triangles share it - otherwise a Multiply/Subtract
|
||||
layer would apply two or three times over depending on local triangle fan-out.
|
||||
6. Move each touched vertex along its (step 2) normal by its accumulated total.
|
||||
7. Optionally (`TextureDisplacementOptions::smooth_*`) relax the result - see Post-process smoothing.
|
||||
|
||||
### Post-process smoothing
|
||||
|
||||
`smooth_mesh_vertices(mesh, movable, strength, iterations)` - Laplacian relaxation, run after all layers
|
||||
have been folded in, restricted to the vertices flagged in `movable`. Each pass moves a movable vertex a
|
||||
`strength` fraction of the way to the average of its one-ring, read from a **snapshot** of the previous
|
||||
pass so the result does not depend on vertex order (a Gauss-Seidel sweep would smooth several times as
|
||||
hard at the end of the array as at the start). Neighbours come from a CSR-style adjacency built once per
|
||||
call. Topology-preserving, like the bake.
|
||||
|
||||
Its job is to round off the hard steps a bitmap height map leaves behind - a different knob from
|
||||
`TextureDisplacementLayer::smoothing`, which blurs the *height map* before it is ever sampled.
|
||||
|
||||
Two ways in, sharing one set of settings on the volume:
|
||||
- The **"Smooth result"** checkbox + "Smoothing (%)" / "Passes" ride along with Preview and Bake.
|
||||
`movable` is exactly the set of vertices the displacement moved, so the untouched part of the model
|
||||
keeps its exact geometry and the ring just outside the displaced set anchors the relaxation (the
|
||||
relief cannot creep outward).
|
||||
- **"Smooth baked mesh now"** (`GLGizmoTextureDisplacement::smooth_model()`) applies the same settings to
|
||||
the volume's *committed* geometry, for relief that is already baked in. `movable` there is the painted
|
||||
triangles' vertices. Because smoothing never touches the triangle list, this is the one geometry
|
||||
operation in the gizmo that keeps **every** paint channel verbatim - it saves and restores the eight
|
||||
texture-displacement masks around `set_mesh()` rather than remapping or dropping them.
|
||||
|
||||
**"Ignore outer ring"** (`smooth_skip_border`, on by default) drops the patch's own outermost ring of
|
||||
vertices from `movable`. That ring's neighbours *outside* the paint never move, so relaxing it drags the
|
||||
rim of the relief down toward the flat surface and the pattern comes out half-melted where it meets the
|
||||
edge. Held out, the border keeps the full depth the texture asked for and only the interior relaxes.
|
||||
Turning it off softens the outer edge deliberately (a blunter version of the per-layer edge-smoothing
|
||||
falloff). This is the *smoothing* rim, independent of whether that rim is displaced at all
|
||||
(`displace_border`, step 4 above); both default to keeping the border sharp.
|
||||
|
||||
### Blend modes
|
||||
|
||||
`TextureBlendMode` {Add, Subtract, Multiply, Divide}, per layer, applied per vertex against the
|
||||
total accumulated by the layers **below** it (lower slots). The quantity blended is a signed
|
||||
displacement in **mm**, not a pixel value.
|
||||
|
||||
Add/Subtract are self-explanatory. Multiply/Divide are *scaling* operations and so need a unit
|
||||
convention: they treat the layer's own value as a **factor relative to 1 mm**. That makes `depth_mm`
|
||||
a gain, and - the property that makes a Multiply layer usable as a mask - a layer with depth 1 mm
|
||||
sampling a white (1.0) texel multiplies by exactly 1, i.e. leaves the layers below unchanged.
|
||||
Divide floors its divisor's magnitude at 0.05: a black texel samples to *exactly* zero, so the divisor
|
||||
really does hit zero in ordinary use, and an unbounded `1/0` would fling vertices thousands of mm away
|
||||
and poison the mesh's bounding box (and every plate/print-volume check downstream). The floor doubles as
|
||||
a cap on how far Divide can amplify the relief beneath it: at most 20×.
|
||||
|
||||
The **lowest painted layer ignores its blend mode**: it has nothing beneath it, and Multiply/Divide
|
||||
against an implicit zero base would annihilate (or blow up) it. Enforced in
|
||||
`build_texture_displacement()` (the first layer to reach a given vertex always folds in additively) and
|
||||
surfaced in the UI, which labels that layer "Base layer" instead of offering a control that does nothing.
|
||||
|
||||
### Projection methods
|
||||
|
||||
Five choices per layer (`TextureProjectionMethod`), all funneling through `apply_uv_transform()`
|
||||
(scale by `1/tiling_scale`, rotate by `rotation_deg`, add `offset`). They are dispatched by
|
||||
`sample_layer_height()`, which returns a **height**, not a UV - because Triplanar takes three
|
||||
texture samples per vertex and so has no single UV that represents it.
|
||||
|
||||
- **Triplanar** (default) - samples the texture on all three world planes (`(y,z)`, `(x,z)`, `(x,y)`)
|
||||
and blends the three by the vertex's own normal raised to `TRIPLANAR_BLEND_SHARPNESS` (4). Hard-picking
|
||||
the single axis most aligned with the normal instead is discontinuous wherever that dominant axis
|
||||
flips: on a +X face the planar coordinate is `(y, z)`, on a −Y face it is `(x, z)`, so at the shared
|
||||
edge `u` jumps. A weighted blend is continuous across the transition by construction, since the weight
|
||||
of the axis being left behind falls smoothly to zero. This removes the hard *seam*; some cross-fade
|
||||
blurring in the band right at a 90° edge is inherent to triplanar mapping. A genuinely seam-free wrap
|
||||
around a box needs a real unwrap - that is what the LSCM mode is for.
|
||||
- **Cylindrical** - wraps around an axis through the patch centroid, axis auto-picked as the world
|
||||
axis *least* aligned with the average normal (perpendicular to the outward radial normal, as a
|
||||
cylinder's own axis would be). `u = angle * local_radius` (arc length in mm), `v = distance along
|
||||
axis`. An approximation, not an exact fit for arbitrary geometry, and the axis/centre are not
|
||||
user-overridable.
|
||||
- **Spherical** - longitude/latitude around the centroid, scaled by local radius. Same caveat.
|
||||
- **LSCM** - real UV unwrap via `MeshBoolean::cgal::parameterize_lscm()` (CGAL's
|
||||
`Surface_mesh_parameterization` package, LSCM algorithm). Computed **once per patch** (not
|
||||
per-vertex like the others - it's a single global least-squares solve), then each vertex looks up
|
||||
its precomputed UV. Requires the patch to be a single topological disk (one connected component,
|
||||
one boundary loop) - `compute_lscm_uvs()` returns empty and the layer falls back to Triplanar if not
|
||||
(e.g. multiple disconnected painted islands, or a fully closed patch). CGAL's parameterizer needs a
|
||||
mesh with no isolated/unreferenced vertices, but `get_facets_strict()` returns the *whole* mesh's
|
||||
vertex array - so `compact_patch_with_map()` builds a clean sub-mesh plus an index map back to the
|
||||
original vertex numbering, purely local to this file.
|
||||
- **ViewProjected** ("From view") - a flat projection along a fixed direction captured from the 3D
|
||||
camera, like a slide projector. `capture_view_projection()` takes the camera's right/up axes,
|
||||
transforms them into the volume's *local* frame (so the projection rides along if the part is later
|
||||
moved), and stores them as `TextureDisplacementLayer::view_project_right/up` (unit vectors, so the
|
||||
projected coordinate stays in mm and `tiling_scale` keeps meaning mm). `sample_layer_height()`
|
||||
projects `Vec2f(dot(pos, right), dot(pos, up))`. Single-valued per point, so - like LSCM but unlike
|
||||
blended Triplanar - the fast preview and UV-check overlay precompute it per vertex
|
||||
(`compute_layer_vertex_uvs()`) and drive the shader's `use_vertex_uv` path. Faces angled away from
|
||||
the projector smear; that is inherent to view projection.
|
||||
|
||||
Two companions to this mode:
|
||||
- **Projection frame overlay** (`TextureProjectorFrame`, see below) - a semi-transparent window
|
||||
dragged over the 3D view whose border becomes the projection's edge. Applying it stores an exact
|
||||
**projective** map in `view_project_matrix`, which supersedes the affine `right`/`up` axes above
|
||||
for that layer (`view_project_projective`).
|
||||
- **"Project only on visible"** (`select_visible_faces()`) - repaints the layer with exactly the
|
||||
facets the camera can see, so the projected area matches the viewpoint the projector was captured
|
||||
from. Two tests: a facing test (normal vs. view direction, per triangle - under perspective the
|
||||
view direction varies across the model, so it is taken from the eye to each centroid), then
|
||||
`MeshRaycaster::get_unobscured_idxs()` on the survivors to drop facets hidden behind other
|
||||
geometry, so a concave part's far inner wall is correctly excluded. One ray query per front-facing
|
||||
facet, hence click-driven (on the checkbox and on each "Capture current view"), never per frame.
|
||||
It **replaces** the layer's paint rather than adding to it - "project onto what I can see" would
|
||||
otherwise accumulate every angle the user had ever looked from.
|
||||
|
||||
### Manual seams and island cutting
|
||||
|
||||
`TextureDisplacementLayer::lscm_seam_edges` - undirected mesh-vertex-index edge pairs the unwrap is
|
||||
forced to cut along, on top of the dihedral-angle seams. `segment_into_charts()` takes a set of these
|
||||
(translated from mesh → compacted-patch numbering inside `compute_patch_unwrap()`) and refuses to
|
||||
union two triangles across a marked edge whatever their angle. Both the unwrap cache key and the
|
||||
gizmo's `UVEditorState` include the seam list, so marking a seam (which leaves the paint mask
|
||||
untouched) still forces a re-solve. Like the paint masks, seams are mesh-index-space and so dropped on
|
||||
any topology change.
|
||||
|
||||
Two ways to write to it:
|
||||
- **Mark seam (manual)** - a "Mark seams" click mode (`m_seam_edit_mode`) that suppresses painting. A
|
||||
click raycasts the volume (`m_c->raycaster()->raycasters()[idx]->unproject_on_mesh()`, `idx` = the
|
||||
volume's slot among model-part volumes), finds the facet's edge nearest the hit point, and toggles it.
|
||||
Marked edges render as a red overlay (`render_seam_overlay()`), pulled toward the camera so they read
|
||||
on top. This is the Blender mark-seam workflow.
|
||||
- **Cut island (auto)** - `cut_island()` takes the selected chart's triangles (back-mapped from the
|
||||
unwrap via `source_vertex`), finds their 3D bounding box, and marks every edge that straddles the
|
||||
mid-plane perpendicular to the longest axis. The re-unwrap then splits the chart across its narrow
|
||||
waist. Exposed as the UV pane's **Cut** button.
|
||||
|
||||
### UV-check overlays (checker / distortion)
|
||||
|
||||
`resources/shaders/{110,140}/texture_displacement_uvcheck.{vs,fs}`, one shader with a `mode` uniform,
|
||||
drawn over the painted patch (`rebuild_uvcheck_mesh()`/`render_uvcheck_mesh()`, P3N3T2: `normal.x` =
|
||||
distortion, `tex_coord` = uv), pulled forward with a polygon offset. **Checker** samples a procedural
|
||||
checkerboard at the layer's uv (per-vertex for LSCM/ViewProjected, in-shader triplanar otherwise) -
|
||||
squares that stay square mean low distortion. **Distortion** colours each triangle blue→green→red by
|
||||
`log2(uv_area / surface_area)` centred on the patch's *median* stretch (so a globally-scaled unwrap
|
||||
reads as uniformly ideal and only relative stretch shows), averaged to vertices. A separate **Show mesh
|
||||
wireframe** toggle draws the whole volume's triangle edges, rebuilt only when the vertex count changes
|
||||
(not per stroke).
|
||||
|
||||
### Tiling
|
||||
|
||||
`DecodedHeightTexture::sample(uv, tile_enabled, tile_method)`. Two tile methods when enabled
|
||||
(Repeat, MirroredRepeat). **When `tile_enabled` is false, sampling outside `[0,1)` returns `0`
|
||||
directly** rather than clamping the *coordinate* into range, which would smear the border row/column of
|
||||
pixels outward to infinity in every direction (streaky lines radiating out from the painted patch).
|
||||
|
||||
### Subdivision — two modes
|
||||
|
||||
**Uniform (`subdivide_mesh_uniform()`)** — whole-mesh, 1-to-4 split. Recursive edge-midpoint split with
|
||||
a shared per-pass midpoint cache (keyed by sorted vertex-index pair) so triangles sharing an edge get
|
||||
the *same* new vertex - capped at `max_iterations` (default 6). Whole-mesh so it never leaves a
|
||||
T-junction, at the cost of densifying everywhere. Wired as a "Subdivide steps" slider (**0–5**, 0 =
|
||||
no subdivision), Apply snaps back to 0. Drops texture-displacement paint (no remap) via the standard
|
||||
`save_painting()`/`set_mesh()`/`restore_painting()` dance; the other four channels are remapped.
|
||||
|
||||
**Adaptive (`subdivide_mesh_adaptive()`)** — refine **only the painted area**, by **Rivara longest-edge
|
||||
bisection**, which is *conformal by construction*. Only **terminal** edges are ever bisected - an edge
|
||||
that is the longest edge of *every* triangle sharing it - which splits both those triangles along one
|
||||
shared midpoint at once, so a hanging node is never created. The edge to split for a triangle that wants
|
||||
refining is found by **longest-edge propagation (LEPP)**: walk to the longest edge of ever-longer-edged
|
||||
neighbours until a terminal one is reached, and bisect that. Edge length strictly increases along the
|
||||
path (ties broken by mesh-vertex key, which both sides of an edge compute identically), so the walk
|
||||
cannot cycle, and Rivara's result is that repeating it refines the original triangle in a bounded number
|
||||
of bisections. The transition triangles it pulls in just outside the painted patch are the graded band
|
||||
that makes the size change conformal.
|
||||
|
||||
The win: a small decal on a big model no longer quadruples the *whole* model's triangle count.
|
||||
|
||||
**Run to completion, worst-first, against a triangle budget.** The refinement loop is not a fixed number
|
||||
of sweeps: it holds every triangle that is over its criteria in a max-heap keyed by *how many times over*
|
||||
it is, pops the worst, walks its LEPP, bisects, and re-scores. Edge adjacency (`nb[e]`, the triangle
|
||||
across each edge) is built **once** and maintained incrementally through each bisection, so the cost
|
||||
scales with the refined region rather than with the whole model. `max_triangles` is the only bound;
|
||||
stopping on it leaves a perfectly valid, still-conformal mesh that spent its budget on the largest
|
||||
errors. A fixed sweep count instead spends itself grading the *coarse surroundings* - whose edges are
|
||||
the longest, so they win every terminal-edge contest - and never reaches the painted patch.
|
||||
|
||||
**It carries the paint forward**, which is what makes it usable (uniform subdivide drops paint). Because
|
||||
the refinement is *driven by* the paint, the remap is trivial: `subdivide_mesh_adaptive()` fills an
|
||||
`out_source[new_tri] = input_tri` map (children inherit their parent), and the gizmo rebuilds each
|
||||
layer's mask on the new mesh - a new triangle is painted iff its source was fully painted in that
|
||||
layer. `collect_paint_region()` derives both:
|
||||
- the union refine-region: **exactly** the original triangles the brush touched, read straight off
|
||||
`TriangleSplittingData::triangles_to_split` (`serialize()` records an entry per original triangle that
|
||||
is either split - i.e. partially painted, the patch boundary - or carries a non-default state). No
|
||||
dilation: marking every triangle that shares a *vertex* with the patch drags in a whole fan of huge
|
||||
unpainted neighbours and refines *those* down to the resolution floor, since the height field the
|
||||
detail test samples is not restricted to the painted area. The conformal closure already grades the
|
||||
size change outward on its own.
|
||||
- the per-layer fully-painted-triangle sets (a `get_facets_strict(ENFORCER)` sub-triangle with all three
|
||||
*original* vertex indices == a whole, fully-painted original triangle; a partial stroke's sub-triangles
|
||||
always carry a split vertex).
|
||||
|
||||
The other four channels ride the normal `restore_painting()` remap.
|
||||
|
||||
Both modes share the gizmo's Preview/Apply/Done flow; the **"Only painted area (adaptive)"** checkbox
|
||||
picks the mode, and the adaptive preview follows the paint live (`rebuild_preview()` refreshes the
|
||||
wireframe while the subdivide preview is open in adaptive mode). The panel shows the previewed triangle
|
||||
count.
|
||||
|
||||
**Feature-adaptive (follow texture detail).** A sub-mode of adaptive (the **"Follow texture detail"**
|
||||
checkbox) that puts triangles where the *displaced surface actually bends*, not evenly. A flat region or
|
||||
a linear **ramp** needs no extra vertices (linear interpolation is exact for a ramp); what needs them is
|
||||
**curvature** - the *second* derivative, not the gradient. So the extra predicate is a **chord-error**
|
||||
test: sample the combined displacement at the triangle's three edge midpoints *and its centroid*
|
||||
(sampling the interior is what catches a bump sitting inside a triangle, the blind spot of an edge-only
|
||||
test) and take the largest departure from the flat triangle's barycentric interpolation. Refine while
|
||||
that exceeds `chord_tolerance_mm` ("Detail (mm)"). Zero chord error on a ramp ⇒ untouched; high on a
|
||||
bump/ridge/noise ⇒ refined until captured. Same conformal machinery, so still crack-free. The
|
||||
per-triangle error is cached and recomputed only for the children of a split.
|
||||
|
||||
Four knobs bracket it, and all four matter:
|
||||
- **"Max edge (mm)"** (`target_edge_length_mm`) is a **baseline that applies in feature mode too**.
|
||||
Without it the chord test aliases: a big triangle over a fine pattern can sample four points that all
|
||||
land at similar heights, report no error, and stall before refinement ever starts. The baseline
|
||||
guarantees a sampling density fine enough for the curvature test to see the texture at all.
|
||||
- **"Detail (mm)"** is the chord tolerance above.
|
||||
- **"Min edge (mm)"** is a hard floor under both, and is what guarantees termination across a sharp
|
||||
texture *step*, where the error never falls however fine the mesh gets.
|
||||
- **"Added triangles (k)"** is the budget, passed as `max_triangles` (the model's own triangle count plus
|
||||
the slider, so the control still means something on an already-dense model).
|
||||
|
||||
The height field is `make_combined_displacement_sampler()` - it mirrors `build_texture_displacement()`'s
|
||||
per-layer setup (decode, patch centroid, cylinder axis, blend order, "lowest layer folds additively")
|
||||
but evaluated per point. Two deliberate simplifications, both erring toward *more* detail (safe -
|
||||
over-refinement is never a crack): every sampleable layer is sampled at every point (no per-point paint
|
||||
test), and edge-smoothing falloff is ignored. The first is *why* the refine region must not be dilated -
|
||||
outside the paint the sampler still reports full relief. **LSCM layers are skipped** (no per-point UV); a
|
||||
purely LSCM stack yields a null sampler and the code falls back to the length baseline alone. Per-vertex
|
||||
heights are sampled lazily, so a small patch on a huge model never pays for the rest of it.
|
||||
|
||||
### Fast preview (GPU-only, no CPU meshing)
|
||||
|
||||
`resources/shaders/{110,140}/texture_displacement_bump.{vs,fs}`, registered as
|
||||
`"texture_displacement_bump"`. Shades the *displaced* surface without moving geometry - active-layer
|
||||
only, selected from the View row, and the default when the gizmo opens (`m_use_bump_preview = true`).
|
||||
Vertex format is `GLModel::Geometry::EVertexLayout::P3N3T2`: `normal.x` carries the per-vertex paint
|
||||
weight (0/1), `normal.y` flags the UV island currently being dragged, and `tex_coord` carries a
|
||||
precomputed texture UV, so it can use `GLModel` normally instead of a hand-rolled VBO/VAO manager.
|
||||
|
||||
The mesh is **flat** (vertices not shared between triangles): every corner of a painted triangle gets
|
||||
weight 1, every corner of an unpainted one weight 0. A coarse mesh needs that - one painted face of a raw
|
||||
cube has no strictly-interior vertex, so per-vertex weighting would either bleed onto the neighbours or
|
||||
vanish outright. Duplicating vertices costs no shading quality here because the shader takes its surface
|
||||
normal from screen-space derivatives of position, not from a per-vertex normal.
|
||||
|
||||
**Both preview meshes work in the patch's vertex space, not the mesh's.** Those agree only until a
|
||||
*brush* stroke splits a triangle: `get_facets_strict()` then appends the split vertices, so the patch
|
||||
array is longer. `rebuild_bump_preview_mesh()` and `rebuild_uvcheck_mesh()` therefore index
|
||||
`patch.vertices` throughout. The weight buffer is rebuilt at the same cadence as the true-displacement
|
||||
preview (stroke-end/slider-release) but from the **live** `TriangleSelector` state, not the flushed model
|
||||
facets, so it does not lag by a full model round-trip.
|
||||
|
||||
The perturbed normal is the analytic one for a height field `H = ±depth_mm · h(uv)` displaced along
|
||||
`N` over any orthonormal surface tangent pair `T`/`B`:
|
||||
|
||||
N' = normalize(N − (dH/da)·T − (dH/db)·B), a = dot(p,T), b = dot(p,B)
|
||||
|
||||
The two slopes have to be genuine **mm-per-mm** derivatives for the preview's apparent depth to match
|
||||
the bake's.
|
||||
|
||||
**Two projection paths (`use_vertex_uv` uniform):**
|
||||
- **Triplanar (`use_vertex_uv = 0`)** - `uv` and the `T`/`B` axes are both derived in-shader from
|
||||
the dominant normal component, mirroring `project_planar()`/`apply_uv_transform()`, and the slope is
|
||||
formed analytically. `T`/`B` are the projection's axis-aligned pair, exact only when the face is
|
||||
axis-aligned; the shader drops the along-normal component to keep the gradient in the surface. Here
|
||||
one `uv` unit is exactly `tiling_scale` mm, so the `1/tiling_scale` gradient factor is right.
|
||||
- **Precomputed UV (`use_vertex_uv = 1`, used for LSCM and ViewProjected)** - `uv` comes per-vertex from
|
||||
the CPU (`compute_layer_vertex_uvs()`, so island placement + tiling/rotation/offset are already folded
|
||||
in), and the perturbed normal is built with **Mikkelsen's method** ("Bump Mapping Unparametrized
|
||||
Surfaces on the GPU"): the surface gradient taken directly from the screen-space derivatives of the
|
||||
*sampled height* and position. **This makes no uv→mm scale assumption**, which is essential, because an
|
||||
LSCM map is **conformal, not isometric**: it is globally area-scaled but the *local* mm-per-uv varies
|
||||
across the chart, so a single global `1/tiling_scale` factor gets the apparent depth wrong. `dFdx(h)`
|
||||
captures the true on-screen rate of change however the chart is stretched. This path is also what makes
|
||||
the fast preview follow the UV editor: move an island and its uv - hence its shading - moves with it
|
||||
(the mesh rebuilds on drag-end, `on_island_edited(finished)` → `rebuild_preview()` →
|
||||
`rebuild_bump_preview_mesh()`). The branch is uniform and the paint weight gates by multiply, so the
|
||||
texture derivatives stay well defined. A triangle straddling a seam has a discontinuous uv → the
|
||||
`det≈0` guard skips it (a localised preview-only artifact, never in the bake).
|
||||
|
||||
**Parallax (triplanar path).** Perturbing the shading normal alone welds the pattern to the base surface:
|
||||
it does not slide as the camera orbits, and does not get deeper as `depth_mm` grows. The triplanar path
|
||||
therefore shades at the point the *displaced* surface would show at this pixel, found by **ray marching**
|
||||
(parallax occlusion mapping). A point at ray parameter `s`, i.e. `P + V·s` (`P` the base point, `V` the
|
||||
unit direction to the eye), sits at height `s·dot(V,n)` above the undisplaced surface. The displaced
|
||||
surface lives in a shell between the extreme values of `amp·(h − midlevel)` - taken from both ends of
|
||||
`h ∈ [0,1]`, so it holds for an inverted layer and a raised midlevel too, where the surface sits *below*
|
||||
the undisplaced one. The march starts at the top of that shell, where the ray is outside the surface by
|
||||
construction, and steps inward until the ray height drops below the sampled height. That crossing *is*
|
||||
the visible point.
|
||||
|
||||
Solving `Q = P + V·(H(Q)/dot(V,n))` by fixed-point iteration instead is geometrically exact but the
|
||||
divisor goes to zero edge-on; the sample then lands a large fraction of a tile away and the iteration
|
||||
oscillates, which reads as a second, flat copy of the pattern ghosted over the real one. Clamping the
|
||||
step to one tile does not help - a tile-sized shift lands on the neighbouring tile, the same pattern
|
||||
again. Offset limiting (stepping along the tangential part of `V`) is stable but understates parallax
|
||||
enough that the relief still flattens as soon as the camera tilts. Marching has neither problem.
|
||||
|
||||
The hit is interpolated between the last two samples, which keeps `PARALLAX_STEPS` (24) affordable, and
|
||||
the whole march is skipped when sweeping the shell would move the sample point less than half a texel -
|
||||
the head-on case, so the common view pays almost nothing. The 140 variant samples with
|
||||
`textureLod(…, 0.0)` inside the loop, since implicit derivatives are undefined in non-uniform control
|
||||
flow. Two uniforms exist for this: `midlevel` (parallax needs the real height, not just its derivative)
|
||||
and `eye_model_pos` (the camera in the volume's local frame).
|
||||
|
||||
Parallax cannot change the model's silhouette or cast shadows; the View row's Normal mode is one click
|
||||
away for that. The LSCM path stays plain Mikkelsen bump - it has no closed-form uv, so there is no cheap
|
||||
way to re-project a marched position. One further approximation: the GPU sampler's wrap mode stands in
|
||||
for `tile_enabled`/`tile_method`, so with tiling *off* the GPU repeats where the CPU returns 0 outside
|
||||
`[0,1)`.
|
||||
|
||||
### On-canvas "Adjust Texture" gizmo
|
||||
|
||||
A per-active-layer toggle ("Adjust placement") that disables painting and shows a flat pan panel (free
|
||||
2D drag on both axes) plus two arrows along the patch's own U/V axes (constrained single-axis drag).
|
||||
Anchored to the painted patch's centroid/average-normal (`compute_layer_paint_anchor()`). Hit-testing is
|
||||
screen-space distance/point-to-segment, not real 3D ray intersection against the handle geometry - simple
|
||||
and good enough at this handle size.
|
||||
|
||||
### Projection frame overlay (ViewProjected)
|
||||
|
||||
`src/slic3r/GUI/TextureProjectorFrame.hpp/.cpp` - a semi-transparent, resizable `wxFrame` the user
|
||||
drags **over the 3D view**, like a slide projector's gate. Whatever the model shows through it is what
|
||||
the texture is projected onto, and the window's border becomes the hard edge of the displacement.
|
||||
Press **Apply projection frame** and the gizmo reads the window's rectangle and commits it.
|
||||
|
||||
The window is deliberately **dumb**: it owns no placement state and reports nothing continuously. Its
|
||||
position and size *are* the placement, read on demand at Apply - which is also when the expensive
|
||||
visible-facet raycast runs. So dragging it is free and nothing recomputes until asked.
|
||||
|
||||
Plain 2D (`wxPaintDC`), not a `wxGLCanvas`: a second GL canvas would have to share the app's one real
|
||||
`wxGLContext`. It only ever draws a bitmap and a border.
|
||||
|
||||
**The projective mapping (`apply_projection_frame()`)**. The frame defines a **screen-space** rectangle,
|
||||
but the bake samples from a **local-space** position, so the two have to be reconciled.
|
||||
`view_project_right/up` can only express an *affine* projection - exact under an orthographic camera, but
|
||||
wrong under perspective, where the near end of a part projects larger than the far end and no pair of
|
||||
axes reproduces that. So the layer instead stores a full projective map (`view_project_matrix`, row-major
|
||||
3×4, `uv = (row0·p̃/row2·p̃, row1·p̃/row2·p̃)`), built like this:
|
||||
|
||||
- `K = projection · view · (instance · volume)`, i.e. local → clip, the same product the renderer uses.
|
||||
Note `Camera::get_projection_matrix()` is typed `Transform3d` (nominally affine) but its perspective
|
||||
form explicitly writes a `(0, 0, −1, 0)` bottom row into the underlying 4×4, so `clip.w = −z_eye` is
|
||||
genuinely carried. The build therefore multiplies **`.matrix()` products** (plain `Matrix4d`), never
|
||||
`Transform3d` products, which would not compose that row correctly.
|
||||
- Window coordinates follow `igl::project`'s convention (as `CameraUtils::project` does), with y
|
||||
measured downward. Writing `uv = (win − rect_origin) / rect_size` makes u and v affine in
|
||||
`ndc = clip.xyz / clip.w`; multiplying through by `clip.w` leaves a plain linear combination of `K`'s
|
||||
rows, which is exactly the 3×4 matrix - the perspective divide survives intact.
|
||||
- `w > 0` is checked rather than divided blindly. A point behind the projector has `w < 0` and divides
|
||||
to a plausible-looking but **mirrored** uv - the classic way a projected decal reappears on the back
|
||||
of a model. `project_uv_projective()` returns false there and the caller treats it as no height.
|
||||
|
||||
The map already includes placement, so `apply_uv_transform()` is **not** applied on top of it - the
|
||||
window's own position and size are the placement, and the tiling/rotation/offset sliders would shove
|
||||
the result off the frame the user just aligned. A "Clear" button drops back to the affine path where
|
||||
those controls mean something again.
|
||||
|
||||
Apply also sets `tile_enabled = false`, so `DecodedHeightTexture::sample()` returns 0 outside `[0,1)`
|
||||
and the border is a hard edge rather than the first seam of an endless repeat, and repaints the layer
|
||||
via `select_visible_faces(&matrix)` - the frame's uv square clips the selection, which both matches the
|
||||
paint to the border and keeps the ray queries proportional to the framed area instead of the model.
|
||||
|
||||
Owned by the gizmo and **destroyed** (not just hidden) in `on_shutdown()`. Closing it only hides it, so
|
||||
reopening keeps it where it was left.
|
||||
|
||||
### UV Editor pane
|
||||
|
||||
`UVEditorCanvas` (`src/slic3r/GUI/UVEditorCanvas.hpp/.cpp`) - a standalone `wxGLCanvas` rendering the
|
||||
flattened LSCM islands (per-island wireframe + outline + fill) over the height texture (background
|
||||
quad tiled across the whole unwrap), with mouse pan/zoom. It is wrapped in a **`UVEditorPanel`**
|
||||
(same file) that adds a button row (Frame / Snap / Avg scale / Cut / Join / Unjoin) and a status line
|
||||
along the bottom naming the current gesture and the shortcuts in play. The *panel* is what is
|
||||
registered as a `wxAuiPaneInfo` pane on `Plater`'s `m_aui_mgr`; `Plater::show_uv_editor(bool)`
|
||||
shows/hides it (deferred via `CallAfter`, since the gizmo calls it mid-3D-frame), and
|
||||
`get_uv_editor_canvas()` returns the inner canvas the gizmo talks to.
|
||||
|
||||
Deliberately **shares the app's one real `wxGLContext`** (`wxGetApp().init_glcontext(*this)`, the
|
||||
same call `View3D`/`Preview`/`AssembleView` make) rather than creating an independent context like
|
||||
`SkipPartCanvas` does elsewhere in this codebase - this is what lets it reuse the already-registered
|
||||
`"flat"`/`"flat_texture"` shaders and `GLModel` as-is, instead of needing its own shader
|
||||
compilation/VBO management.
|
||||
|
||||
**Geometry is uploaded once, in the unwrap's own (raw, mm) coordinates**, one `GLModel` set per island;
|
||||
each island is then drawn through its own 2x3 affine (`island_transform_matrix()` composed with the
|
||||
layer's tiling/rotation/offset) passed as the `flat` shader's `view_model_matrix`. A drag updates one
|
||||
matrix per island and touches no vertex buffer - `on_island_edited(!finished)` calls only
|
||||
`set_island_transforms()`, and the full `set_islands()` rebuild happens solely when the unwrap itself
|
||||
changes (`unwrap_changed` in `update_uv_editor()`).
|
||||
|
||||
**Gestures** (canvas-owned, reported to the gizmo as incremental deltas via `IslandEditFn`): left-drag
|
||||
= move, right-drag or **R** = rotate (hold **Shift** to snap to 15° steps - quantised on the
|
||||
*cumulative* rotation, not each delta, so it doesn't judder, and accumulated incrementally so it
|
||||
survives crossing ±180°), **S** = scale (R/S modal, click/Enter to confirm, Esc to cancel), wheel =
|
||||
zoom about the cursor, middle-drag = pan, **Home**/**F** = frame all. Scale writes
|
||||
`TextureIsland::scale`; "Avg scale" (`average_island_scales()`) sets every island to the mean, so
|
||||
one island scaled by hand can be matched back to its neighbours' texel density. **Snap** (canvas-owned
|
||||
`m_snap_enabled`, toggled from the toolbar) sticks a dragged island's nearest boundary vertex onto a
|
||||
neighbouring island's at drag-*end* only - a magnet that re-applies mid-drag is very hard to pull out
|
||||
of. Toolbar commands the canvas can't service itself (Avg scale, Cut, Join, Unjoin) are forwarded to the
|
||||
gizmo via `CommandFn`; view-only ones (Frame, Snap) it handles directly.
|
||||
|
||||
## File map
|
||||
|
||||
**libslic3r (core, no GUI dependency):**
|
||||
- `src/libslic3r/TextureDisplacement.hpp/.cpp` - data model, bake algorithm, projection methods,
|
||||
tiling, subdivision (uniform + adaptive longest-edge bisection), post-process smoothing
|
||||
(`smooth_mesh_vertices()`), and `TextureDisplacementOptions` (the whole-stack settings). See doc
|
||||
comments throughout, they're kept accurate and up to date.
|
||||
- `src/libslic3r/MeshBoolean.hpp/.cpp` - `parameterize_lscm()` and `remesh_isotropic()` in the `cgal`
|
||||
sub-namespace, reusing the existing `CGALMesh`/`_EpicMesh`/conversion-helper infrastructure already
|
||||
there for mesh boolean ops. CGAL includes: `Polygon_mesh_processing/border.h`,
|
||||
`Polygon_mesh_processing/connected_components.h`, `Surface_mesh_parameterization/{Error_code,
|
||||
LSCM_parameterizer_3, parameterize}.h`. No new dependency - CGAL 5.6.3 is already vendored and the
|
||||
`Surface_mesh_parameterization` package headers were already present.
|
||||
- `src/libslic3r/Model.hpp/.cpp` - the 8 named `FacetsAnnotation` fields + accessor,
|
||||
`texture_displacement_layers`, `texture_displacement_options`, and all the mirrored touch points
|
||||
(see Data model above).
|
||||
|
||||
**GUI:**
|
||||
- `src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.hpp/.cpp` - the gizmo and its whole panel.
|
||||
- `src/slic3r/GUI/TextureLibrary.hpp/.cpp` - scans the shipped + user texture folders, imports an
|
||||
arbitrary image into the user folder (converting it to the 8-bit grayscale PNG libslic3r decodes),
|
||||
and loads a library file's bytes for a layer. The image→grayscale-PNG conversion lives here, on the
|
||||
GUI side, because libslic3r has no image toolkit; both the import path and the "pick a shipped
|
||||
texture" path go through the same one function.
|
||||
- `resources/textures/displacement/*.png` - the 10 shipped height maps (Bricks, Grid, Hexagons,
|
||||
Knurl, Noise, Quilt, Studs, Waves, Weave, Wood Grain). All 512×512 8-bit grayscale and **seamless**
|
||||
(each is periodic over the full image in both axes, so tiling shows no seam). Generated
|
||||
procedurally; the whole `resources/` tree is installed recursively by CMake, so a new folder under
|
||||
it ships with no build-system change.
|
||||
- `src/slic3r/GUI/Jobs/TextureDisplacementBakeJob.hpp/.cpp` - background bake commit.
|
||||
- `src/slic3r/GUI/Jobs/TextureDisplacementPreviewJob.hpp/.cpp` - background preview compute
|
||||
(mirrors the bake job's shape but commits nothing to the Model).
|
||||
- `src/slic3r/GUI/TextureProjectorFrame.hpp/.cpp` - the semi-transparent projection-frame overlay for
|
||||
ViewProjected layers (plain 2D `wxPaintDC`, no GL context - see its section above).
|
||||
- `src/slic3r/GUI/UVEditorCanvas.hpp/.cpp` - the 2D UV unwrap viewer widget.
|
||||
- `src/slic3r/GUI/Plater.hpp/.cpp` - `uv_editor_canvas` member, AUI pane registration,
|
||||
`get_uv_editor_canvas()`/`show_uv_editor()`.
|
||||
- `src/slic3r/GUI/GLShadersManager.cpp` - registers `"texture_displacement_bump"`.
|
||||
- `resources/shaders/{110,140}/texture_displacement_bump.{vs,fs}` - the fast-preview shader.
|
||||
- `src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp` - `PainterGizmoType::TEXTURE_DISPLACEMENT`.
|
||||
- `src/slic3r/GUI/Gizmos/GLGizmosManager.hpp/.cpp` - `EType::TextureDisplacement` registration.
|
||||
|
||||
## Tests
|
||||
|
||||
`tests/libslic3r/test_texture_displacement.cpp`. Covers `decode_height_texture` round-trip, empty-layer
|
||||
no-op, full-cube uniform displacement, a second layer over the same area contributing, all four blend
|
||||
modes (table-driven), the lowest layer ignoring its blend mode, border displace/pin, post-process
|
||||
smoothing and its mask guarantees, and adaptive subdivision: conformality (`every_edge_used_twice` on a
|
||||
partially-refined cube - an exact crack detector for a closed mesh), the target edge length actually
|
||||
being reached, the triangle budget capping the result without opening a crack, curvature-driven
|
||||
refinement (a Gaussian bump refines at its centre, a linear ramp adds nothing), and the max-edge
|
||||
baseline.
|
||||
|
||||
`BUILD_TESTS` is `OFF` in the checked-in build cache; flip it on to run them:
|
||||
|
||||
cmake -S . -B build -DBUILD_TESTS=ON
|
||||
cmake --build build --config Release --target libslic3r_tests -- -m
|
||||
./build/tests/libslic3r/Release/libslic3r_tests.exe "[TextureDisplacement]" --order rand
|
||||
@@ -0,0 +1,326 @@
|
||||
# Texture Displacement — Feature & Controls Guide
|
||||
|
||||
Texture Displacement is a paint-style gizmo that stamps height-map textures onto a model's surface
|
||||
and turns them into real relief — engraved or embossed detail — either as a live preview or baked
|
||||
into actual mesh geometry. You paint where the texture applies, stack multiple textures as blended
|
||||
layers, choose how each is projected onto the surface, and (for the unwrap projection) lay the result
|
||||
out by hand in a dedicated 2D **UV Editor** pane.
|
||||
|
||||
This document describes every feature and control. For the internal architecture and algorithms, see
|
||||
`TEXTURE_DISPLACEMENT.md`.
|
||||
|
||||
---
|
||||
|
||||
## Table of contents
|
||||
|
||||
1. [Quick start](#quick-start)
|
||||
2. [Entering the tool](#entering-the-tool)
|
||||
3. [Selection modes](#selection-modes)
|
||||
4. [View modes](#view-modes)
|
||||
5. [Auto update](#auto-update)
|
||||
6. [Texture layers](#texture-layers)
|
||||
7. [Per-layer settings](#per-layer-settings)
|
||||
8. [Projection methods](#projection-methods)
|
||||
9. [The UV Editor](#the-uv-editor)
|
||||
10. [Seams](#seams)
|
||||
11. [Adjust placement (on-model)](#adjust-placement-on-model)
|
||||
12. [Preparing the mesh: Subdivide & Remesh](#preparing-the-mesh-subdivide--remesh)
|
||||
13. [Baking & resetting](#baking--resetting)
|
||||
14. [Controls reference](#controls-reference)
|
||||
15. [Tips & limitations](#tips--limitations)
|
||||
|
||||
---
|
||||
|
||||
## Quick start
|
||||
|
||||
1. Select an object and open the **Texture displacement** gizmo from the left toolbar.
|
||||
2. A texture layer is added automatically. Pick a texture from the layer's picker, or import your own.
|
||||
3. **Paint** the area you want the texture to affect (or press **Select whole model**).
|
||||
4. The relief appears live on the model. Tune **Depth**, **Tile size**, **Rotation**, etc.
|
||||
5. If the model is low-poly, use **Subdivide** or **Remesh** so there are enough vertices for detail.
|
||||
6. Press **Bake** to convert the preview into real geometry, or leave it as a live preview.
|
||||
|
||||
> The tool only ever affects the **painted** area. Everything you don't paint keeps its original
|
||||
> surface, and bake blends the relief seamlessly into it.
|
||||
|
||||
---
|
||||
|
||||
## Entering the tool
|
||||
|
||||
The gizmo lives on the left gizmo toolbar (icon: `toolbar_texture_displacement.svg`). Its settings
|
||||
panel opens beside the toolbar. You can **Dock panel / Undock panel** (top of the panel) to pin it or
|
||||
float it freely over the 3D view, and **Close** at the bottom exits the gizmo.
|
||||
|
||||
When you first open the tool on a never-textured object it starts with **one texture layer already
|
||||
added**, so you can paint straight away.
|
||||
|
||||
---
|
||||
|
||||
## Selection modes
|
||||
|
||||
Choose *how* you paint. All three write into the **active layer's** mask.
|
||||
|
||||
| Mode | What it does |
|
||||
|------|--------------|
|
||||
| **Brush** | Free-hand painting with a round brush. Shows a **Brush size** slider and a **Circle / Sphere** choice (circle = surface disc, sphere = 3D ball that also paints around curves). |
|
||||
| **Face** | Click a single triangle to paint it. |
|
||||
| **Connected area** | Click to flood-fill a region; the **Angle threshold** slider limits how far the fill spreads across changes in surface angle. |
|
||||
|
||||
- **Select whole model** — marks the entire model as painted for the active layer, instead of
|
||||
brushing it by hand.
|
||||
|
||||
---
|
||||
|
||||
## View modes
|
||||
|
||||
A row of icon buttons labelled **View** controls how the painted area is shown. The first four are a
|
||||
radio group; **Wireframe** is an independent toggle. Hover any icon for its tooltip.
|
||||
|
||||
| View | Meaning |
|
||||
|------|---------|
|
||||
| **Normal** | The true displaced geometry — exactly what **Bake** produces. Rebuilt in the background. |
|
||||
| **Fast** | A GPU bump-shaded approximation of the *active layer only*. No real geometry movement — quick to update, not exact. Best while tuning or dragging islands. |
|
||||
| **Checker** | A test grid painted over the unwrap so you can see stretching (squares stay square where the map isn't distorted). |
|
||||
| **Distortion** | A blue→green→red heatmap of how much each area is compressed or stretched in UV space. Needs the **Unwrap (LSCM)** projection. |
|
||||
| **Wireframe** | Overlays the mesh edges (white). Independent of the view above; in **Normal** view it sits on the displaced surface. |
|
||||
|
||||
---
|
||||
|
||||
## Auto update
|
||||
|
||||
**Auto update** (on by default) rebuilds the true displaced geometry as soon as *anything* changes —
|
||||
painting, swapping textures, moving sliders. Turn it off on very heavy models to only rebuild when you
|
||||
release a slider (painting still updates on stroke end).
|
||||
|
||||
---
|
||||
|
||||
## Texture layers
|
||||
|
||||
You can stack up to **8** texture layers. Each has its own independent paint mask, its own texture,
|
||||
and its own parameters, and they combine in slot order like layers in an image editor.
|
||||
|
||||
- **Add a layer** — the **+ icon** to the right of the *Texture layers* heading (reuses the tool icon
|
||||
for now).
|
||||
- **Remove** — the button on each layer's header row.
|
||||
- **Active layer** — click a layer's header (or anywhere in its block) to make it active. The active
|
||||
layer is the one you paint into and the one whose block is tinted. Only one layer is active at a time.
|
||||
- **Erase all** — clears the active layer's paint.
|
||||
|
||||
Each layer shows a texture **picker** (large preview + name). Open it to choose from the shipped
|
||||
library or import your own image (any png/jpg/bmp; it's converted to an 8-bit grayscale height map and
|
||||
copied into your user texture folder so app updates can't overwrite it).
|
||||
|
||||
---
|
||||
|
||||
## Per-layer settings
|
||||
|
||||
| Control | Range / options | What it does |
|
||||
|---------|-----------------|--------------|
|
||||
| **Depth (mm)** | 0.01–10 (log) | Maximum displacement along the surface normal. |
|
||||
| **Tile size (mm)** | 0.2–200 (log) | Physical size of one texture tile on the surface. |
|
||||
| **Rotation** | 0–360° | Rotates the texture on the surface. |
|
||||
| **Midlevel** | 0–10 | The grey level that means "don't move". At 0 the texture only pushes outward; raise it and darker texels cut *inward* (one map both embosses and engraves). 0.5 makes mid-grey neutral. |
|
||||
| **Smoothing** | 0–1 | Blurs the height texture before it displaces — rounds hard edges and removes speckle without needing a softer source image. |
|
||||
| **Edge smoothing** | checkbox + **Edge amount** 0–1 | Fades the relief to flat toward the *edge of the painted area*, so it blends into the surrounding surface. A small amount softens only a thin band at the very edge; the maximum flattens the whole painted face. |
|
||||
| **Invert** | checkbox | Flips the height map (peaks become valleys). |
|
||||
| **Blend** | Add / Subtract / Multiply / Divide | How this layer combines with the layers **below** it where they overlap. Add/Subtract pile relief on or carve it away; Multiply/Divide scale the relief underneath (a mask). The lowest painted layer is the **Base** and always behaves additively. |
|
||||
| **Tile** | checkbox + **Repeat / Mirrored repeat** | When off, the texture is placed once (a decal) instead of repeating. Mirrored repeat flips every other tile to hide seams. |
|
||||
| **Projection** | see below | How the texture is mapped onto the painted surface. |
|
||||
|
||||
> **Midlevel warning:** cutting inward can fold the surface through itself in sharp concave corners or
|
||||
> thin walls. Keep Depth small relative to the feature you're cutting into; the panel warns when a deep
|
||||
> inward setting is risky.
|
||||
|
||||
---
|
||||
|
||||
## Projection methods
|
||||
|
||||
How the 2D texture is wrapped onto the 3D painted area.
|
||||
|
||||
| Method | Best for | Notes |
|
||||
|--------|----------|-------|
|
||||
| **Triplanar (blended)** | Patches wrapping around edges | Projects from all three axes at once and blends, so there's no seam across a sharp edge. |
|
||||
| **Cylindrical** | Round, tube-like selections | Wraps the texture around the patch's own centre/axis. |
|
||||
| **Spherical** | Ball-like selections | Longitude/latitude wrap around the patch centre. |
|
||||
| **Unwrap (LSCM)** | Flat, controlled layout | A real conformal unwrap. Cuts the area into pieces at sharp edges (see **Seam angle**), flattens each, and lets you lay them out by hand in the **UV Editor**. Unlocks Checker/Distortion, seams, and island editing. |
|
||||
| **From view** | Decals / slide-projector look | Projects straight onto the surface from the current camera direction. Use **Capture current view** to re-lay it from wherever you're looking. |
|
||||
|
||||
### LSCM-only controls
|
||||
|
||||
These appear when a layer uses **Unwrap (LSCM)**:
|
||||
|
||||
- **Seam angle** (5–90°) — edges sharper than this are cut so each piece lies flat. Lower cuts more
|
||||
(less stretching, more seams); raise to keep more in one piece. A box's 90° corners are cut by
|
||||
default. *Ignored once you've marked any seam by hand* (your seams then define the pieces).
|
||||
- **Connect islands** (on by default) — lays the unwrap out as a **connected net**: pieces that share
|
||||
an edge are unfolded next to each other (a cube becomes a joined net instead of six loose squares).
|
||||
They stay separate islands, so you can still move any of them by hand. Turn off for the classic
|
||||
packed-grid layout.
|
||||
- **Open UV editor** — shows the flattened unwrap in a side pane (see below). Opens *only* when you
|
||||
turn this on — it never pops up on its own.
|
||||
- **Mark seams** / **Path** / **Clear seams** — see [Seams](#seams).
|
||||
- An **Unwrap: N islands, F faces, V verts** read-out tells you what the unwrap actually produced.
|
||||
|
||||
---
|
||||
|
||||
## The UV Editor
|
||||
|
||||
A dockable 2D pane (enable **Open UV editor** on an LSCM layer) showing the flattened unwrap over the
|
||||
height texture. Islands are the flattened pieces; you can rearrange them freely — nothing re-packs them
|
||||
behind your back. Moving an island updates the model **live** (in Fast view it tracks the cursor
|
||||
smoothly, via a shader uniform — no rebuild until you release).
|
||||
|
||||
### Navigation
|
||||
|
||||
| Action | Control |
|
||||
|--------|---------|
|
||||
| Pan | Middle-drag |
|
||||
| Zoom | Mouse wheel (zooms about the cursor) |
|
||||
| Frame everything | **Home** or **F**, or the **Frame** toolbar button |
|
||||
|
||||
### Editing an island
|
||||
|
||||
| Action | Control |
|
||||
|--------|---------|
|
||||
| Select | Left-click an island |
|
||||
| Move | Left-drag |
|
||||
| Rotate | Right-drag, or press **R** then move the mouse (click/Enter to confirm, Esc to cancel) |
|
||||
| Rotate snapped | Hold **Shift** while rotating — snaps to **global** 15° marks (0/15/30…). A protractor dial with tick marks and the current angle is shown. |
|
||||
| Scale | Press **S** then move the mouse (click/Enter to confirm, Esc to cancel) |
|
||||
| Undo / Redo | **Ctrl+Z** / **Ctrl+Shift+Z** or **Ctrl+Y** |
|
||||
|
||||
The **selected** island gets a bold light-green outline and a brighter wireframe; unselected islands
|
||||
are a translucent light-green wash. The texture underneath repeats exactly as it will when baked.
|
||||
A **status line** along the bottom always names the current gesture and the shortcuts in play.
|
||||
|
||||
### Toolbar
|
||||
|
||||
| Button | Action |
|
||||
|--------|--------|
|
||||
| **Frame** | Frame all islands (same as Home). |
|
||||
| **Snap** | Toggle magnetic snapping — a dragged island sticks its boundary to a neighbour's when they come close. |
|
||||
| **Avg scale** | Give every island the same texel density (Blender's "Average Islands Scale"). |
|
||||
| **Cut** | Split the selected island across its long axis (useful for very long islands). |
|
||||
| **Join** | Unfold the selected island onto its nearest neighbour along their shared edge — keeps both as separate islands with their own borders. |
|
||||
| **Unjoin** | Send the selected island back to its own packed position. |
|
||||
|
||||
> **Checker / Distortion in the UV editor:** selecting those View modes also colours the UV pane — a
|
||||
> checker background, or a per-island distortion heatmap — so you can judge stretch in 2D as well as
|
||||
> on the model.
|
||||
|
||||
---
|
||||
|
||||
## Seams
|
||||
|
||||
Seams are edges the unwrap is forced to cut along, on top of whatever the Seam angle cuts — the
|
||||
Blender "mark seam" workflow. They let you control exactly where the unwrap splits.
|
||||
|
||||
Enable **Mark seams** on an active LSCM layer, then:
|
||||
|
||||
- **Click an edge** on the model to mark it (it turns **red**); click a red edge again to unmark it.
|
||||
The edge under the cursor is highlighted **yellow** so you can see what a click will toggle.
|
||||
- **Path mode** (the **Path** checkbox) — for dense meshes where clicking each edge is tedious: click a
|
||||
start point, then an end point, and the whole **shortest path** between them is seamed at once. It
|
||||
chains (each click extends from the last point); the start vertex is shown in **green**.
|
||||
- **Ctrl+drag** rotates/pans the camera while in seam mode.
|
||||
- **Clear seams** removes them all.
|
||||
|
||||
Once any seam is marked, the automatic Seam-angle cutting is disabled so *your* seams define the
|
||||
islands — pieces you leave un-seamed merge together.
|
||||
|
||||
---
|
||||
|
||||
## Adjust placement (on-model)
|
||||
|
||||
**Adjust placement** (on an active layer) lets you position the texture by dragging a handle on the
|
||||
model instead of nudging the Rotation/offset numbers. The handle is a flat panel in the patch's
|
||||
tangent plane (drag anywhere on it to move freely) plus U/V arrows for single-axis nudges. It's
|
||||
anchored to the painted patch, so paint something first.
|
||||
|
||||
---
|
||||
|
||||
## Preparing the mesh: Subdivide & Remesh
|
||||
|
||||
Displacement can only move vertices that exist, so a coarse model needs more of them first.
|
||||
|
||||
### Subdivide
|
||||
|
||||
Splits every triangle into four, **1–5 times** (each step roughly quadruples the triangle count).
|
||||
|
||||
- **Subdivide steps** (1–5) — how many times to split.
|
||||
- **Preview subdivision** — shows the result as a **cyan wireframe** without changing the model.
|
||||
- **Apply** — commits the subdivision to the geometry.
|
||||
- **Done** — ends the preview and leaves the model as it is.
|
||||
|
||||
### Remesh
|
||||
|
||||
Rebuilds the whole model with triangles close to a target edge length — evens out a mesh with wildly
|
||||
varying triangle sizes (CGAL isotropic remeshing).
|
||||
|
||||
- **Target edge (mm)** — desired triangle edge length (seeded to the model's current average).
|
||||
- **Remesh** — splits the big triangles and merges the small ones to that size.
|
||||
|
||||
> Both Subdivide-Apply and Remesh **replace the geometry** and clear any *not-yet-baked* paint on it
|
||||
> (already-baked relief is kept). If you had the mesh **Wireframe** on before, it stays on afterward.
|
||||
|
||||
---
|
||||
|
||||
## Baking & resetting
|
||||
|
||||
- **Bake** — converts the current preview into real, permanent mesh geometry, restricted to the
|
||||
painted area. Runs in the background; the button shows *Baking…* while it works.
|
||||
- **Erase all** — clears the active layer's paint.
|
||||
|
||||
Baking is the exact same algorithm as the **Normal** preview, so what you see is what you get.
|
||||
|
||||
---
|
||||
|
||||
## Controls reference
|
||||
|
||||
### Mouse — 3D view (while painting)
|
||||
|
||||
| Input | Action |
|
||||
|-------|--------|
|
||||
| Left-drag | Paint the active layer |
|
||||
| Ctrl + drag | Rotate / pan the camera (works in seam mode too) |
|
||||
| Wheel | Zoom |
|
||||
|
||||
### Mouse & keys — UV Editor
|
||||
|
||||
| Input | Action |
|
||||
|-------|--------|
|
||||
| Left-click | Select island |
|
||||
| Left-drag | Move island |
|
||||
| Right-drag | Rotate island |
|
||||
| **R** / **S** | Modal rotate / scale (mouse drives it, click or Enter confirms, Esc cancels) |
|
||||
| **Shift** (while rotating) | Snap to global 15° marks |
|
||||
| Middle-drag | Pan |
|
||||
| Wheel | Zoom about cursor |
|
||||
| **Home** / **F** | Frame all islands |
|
||||
| **Ctrl+Z** / **Ctrl+Shift+Z** / **Ctrl+Y** | Undo / redo |
|
||||
|
||||
### Seam mode
|
||||
|
||||
| Input | Action |
|
||||
|-------|--------|
|
||||
| Click edge | Mark / unmark a seam (yellow = hover, red = marked) |
|
||||
| Click (Path mode) | Set start, then seam the shortest path to the next click |
|
||||
| Ctrl + drag | Rotate / pan camera |
|
||||
|
||||
---
|
||||
|
||||
## Tips & limitations
|
||||
|
||||
- **Paint first, then bake.** The preview is free to explore; only Bake changes the real mesh.
|
||||
- **Not enough detail?** Subdivide or Remesh before painting fine textures.
|
||||
- **Inward cuts** (high Midlevel + big Depth) can self-intersect on thin walls or sharp concave
|
||||
corners — keep Depth modest there.
|
||||
- **Fast vs Normal:** Fast preview shades a bump and shows only the active layer; use it for quick
|
||||
tuning and smooth UV dragging, but trust **Normal**/**Bake** for the exact result.
|
||||
- **Topology changes drop unbaked paint.** Subdivide-Apply, Remesh, and Simplify replace the mesh, and
|
||||
texture-displacement paint isn't remapped across that change (already-baked relief is unaffected).
|
||||
- **Island placements** are tied to the current unwrap. Re-painting or changing the Seam angle can
|
||||
re-segment the charts and renumber them, so a re-unwrap re-lays the connected net and discards
|
||||
hand placements made before it.
|
||||
- **Connect islands** is on by default; turn it off (per layer) for the classic packed-grid layout, or
|
||||
if an unfold looks wrong on an unusual mesh.
|
||||
@@ -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
|
||||
|
||||
@@ -20,6 +20,18 @@ for %%a in (%*) do (
|
||||
if "%%a"=="-x" set USE_NINJA=1
|
||||
)
|
||||
|
||||
@REM Check for clang-cl option (-l). Combined with -x it also builds the deps with
|
||||
@REM clang-cl; on the Visual Studio generator it applies to the slicer only, because
|
||||
@REM the dependency sub-builds have no toolset to inherit and stay on MSVC.
|
||||
set CLANG_ARG=
|
||||
set TOOLSET_ARG=
|
||||
for %%a in (%*) do (
|
||||
if "%%a"=="-l" (
|
||||
set CLANG_ARG=-DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl
|
||||
set TOOLSET_ARG=-T ClangCL
|
||||
)
|
||||
)
|
||||
|
||||
@REM Check for unit-tests option ("tests")
|
||||
set BUILD_TESTS=OFF
|
||||
for %%a in (%*) do (
|
||||
@@ -127,12 +139,13 @@ if "%1"=="slicer" (
|
||||
GOTO :slicer
|
||||
)
|
||||
echo "building deps.."
|
||||
if defined CLANG_ARG if "%USE_NINJA%"=="0" echo Note: -l needs -x for the dependencies; building them with MSVC.
|
||||
|
||||
echo on
|
||||
REM Set minimum CMake policy to avoid <3.5 errors
|
||||
set CMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
if "%USE_NINJA%"=="1" (
|
||||
cmake ../ -G %CMAKE_GENERATOR% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake ../ -G %CMAKE_GENERATOR% %CLANG_ARG% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target deps
|
||||
) else (
|
||||
cmake ../ -G %CMAKE_GENERATOR% -A %arch% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
@@ -151,10 +164,10 @@ cd %build_dir%
|
||||
echo on
|
||||
set CMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
if "%USE_NINJA%"=="1" (
|
||||
cmake .. -G %CMAKE_GENERATOR% -DORCA_TOOLS=ON %SIG_FLAG% -DBUILD_TESTS=%BUILD_TESTS% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target ALL_BUILD
|
||||
cmake .. -G %CMAKE_GENERATOR% %CLANG_ARG% -DORCA_TOOLS=ON %SIG_FLAG% -DBUILD_TESTS=%BUILD_TESTS% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target all
|
||||
) else (
|
||||
cmake .. -G %CMAKE_GENERATOR% -A %arch% -DORCA_TOOLS=ON %SIG_FLAG% -DBUILD_TESTS=%BUILD_TESTS% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake .. -G %CMAKE_GENERATOR% -A %arch% %TOOLSET_ARG% -DORCA_TOOLS=ON %SIG_FLAG% -DBUILD_TESTS=%BUILD_TESTS% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target ALL_BUILD -- -m
|
||||
)
|
||||
@echo off
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
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
|
||||
# Assimp's ccache support sets the global RULE_LAUNCH_COMPILE, which breaks
|
||||
# the Ninja RC rule. The superbuild forwards CMAKE_<LANG>_COMPILER_LAUNCHER.
|
||||
-DASSIMP_BUILD_USE_CCACHE=OFF
|
||||
-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 ()
|
||||
@@ -24,6 +24,13 @@ if (MSVC AND DEP_DEBUG)
|
||||
set(_options "FORWARD_CONFIG")
|
||||
endif ()
|
||||
|
||||
# Boost.Container's bundled dlmalloc passes int* where the Win32 Interlocked API
|
||||
# takes volatile long*; cl compiles that with a warning, clang errors out.
|
||||
set(_boost_c_flags_line "")
|
||||
if (MSVC AND CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
set(_boost_c_flags_line "-DCMAKE_C_FLAGS:STRING=-Wno-incompatible-pointer-types")
|
||||
endif ()
|
||||
|
||||
orcaslicer_add_cmake_project(Boost
|
||||
${_options}
|
||||
URL "https://github.com/boostorg/boost/releases/download/boost-1.84.0/boost-1.84.0.tar.gz"
|
||||
@@ -38,6 +45,7 @@ orcaslicer_add_cmake_project(Boost
|
||||
"${_context_abi_line}"
|
||||
"${_context_arch_line}"
|
||||
"${_context_impl_line}"
|
||||
"${_boost_c_flags_line}"
|
||||
)
|
||||
|
||||
set(DEP_Boost_DEPENDS ZLIB)
|
||||
set(DEP_Boost_DEPENDS ZLIB)
|
||||
|
||||
@@ -157,8 +157,16 @@ endif ()
|
||||
function(orcaslicer_add_cmake_project projectname)
|
||||
cmake_parse_arguments(P_ARGS "FORWARD_CONFIG" "INSTALL_DIR;BUILD_COMMAND;INSTALL_COMMAND" "CMAKE_ARGS" ${ARGN})
|
||||
|
||||
# MSVC is true for clang-cl as well, so the sub-build toolchain has to key on the
|
||||
# generator. A non-Visual-Studio superbuild passes its own generator down, and with
|
||||
# it the CMAKE_C_COMPILER / CMAKE_CXX_COMPILER forwarded below.
|
||||
set(_dep_msvc_gen FALSE)
|
||||
if (MSVC AND CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
set(_dep_msvc_gen TRUE)
|
||||
endif ()
|
||||
|
||||
set(_configs_line -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE})
|
||||
if (_is_multi OR MSVC)
|
||||
if (_is_multi OR _dep_msvc_gen)
|
||||
if (P_ARGS_FORWARD_CONFIG)
|
||||
set(_configs_line -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE})
|
||||
elseif (ORCA_INCLUDE_DEBUG_INFO AND NOT DEP_DEBUG)
|
||||
@@ -174,7 +182,7 @@ function(orcaslicer_add_cmake_project projectname)
|
||||
set(_target_config "Release")
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (_dep_msvc_gen)
|
||||
set(_gen CMAKE_GENERATOR "${DEP_MSVC_GEN}" CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}")
|
||||
else()
|
||||
set(_gen "")
|
||||
@@ -182,7 +190,7 @@ function(orcaslicer_add_cmake_project projectname)
|
||||
|
||||
if ($ENV{CMAKE_BUILD_PARALLEL_LEVEL})
|
||||
set(_build_j "") # assume environment will control --build parallel setting
|
||||
elseif(MSVC)
|
||||
elseif(_dep_msvc_gen)
|
||||
set(_build_j "/m")
|
||||
else()
|
||||
set(_build_j "-j${NPROC}")
|
||||
@@ -367,6 +375,9 @@ include(libnoise/libnoise.cmake)
|
||||
|
||||
include(Draco/Draco.cmake)
|
||||
|
||||
include(FFMPEG/FFMPEG.cmake)
|
||||
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
|
||||
@@ -448,6 +459,8 @@ set(_dep_list
|
||||
dep_libnoise
|
||||
dep_python3
|
||||
dep_wxInspector
|
||||
dep_FFMPEG
|
||||
dep_Assimp
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
|
||||
@@ -56,6 +56,18 @@ else()
|
||||
set(_curl_static ON)
|
||||
endif()
|
||||
|
||||
# curl 7.75's configure probes and code rely on C laxness cl allows but clang
|
||||
# errors on (implicit function declarations, int* vs u_long* in ioctlsocket),
|
||||
# which flips probe results and misconfigures nonblock.c into the AmigaOS
|
||||
# IoctlSocket branch. Relax both diagnostics so the probes behave like cl, and
|
||||
# pin the camel-case probes off since they only "pass" by implicit declaration.
|
||||
set(_curl_c_flags_line "")
|
||||
set(_curl_probe_overrides "")
|
||||
if (MSVC AND CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
set(_curl_c_flags_line "-DCMAKE_C_FLAGS:STRING=-Wno-implicit-function-declaration -Wno-incompatible-pointer-types")
|
||||
set(_curl_probe_overrides -DHAVE_IOCTLSOCKET_CAMEL=0 -DHAVE_IOCTLSOCKET_CAMEL_FIONBIO=0)
|
||||
endif ()
|
||||
|
||||
orcaslicer_add_cmake_project(CURL
|
||||
# GIT_REPOSITORY https://github.com/curl/curl.git
|
||||
# GIT_TAG curl-7_75_0
|
||||
@@ -69,6 +81,8 @@ orcaslicer_add_cmake_project(CURL
|
||||
-DBUILD_CURL_EXE:BOOL=OFF
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
-DCURL_STATICLIB=${_curl_static}
|
||||
"${_curl_c_flags_line}"
|
||||
${_curl_probe_overrides}
|
||||
${_curl_platform_flags}
|
||||
)
|
||||
|
||||
|
||||
@@ -7,5 +7,20 @@ orcaslicer_add_cmake_project(Eigen
|
||||
URL https://gitlab.com/libeigen/eigen/-/archive/5.0.1/eigen-5.0.1.zip
|
||||
URL_HASH SHA256=0dbb1f9e3aaad66f352c03227d8c983f6f0b49e0b07e71a7300f4abcc01aee12
|
||||
CMAKE_ARGS "${_eigen_extra_flags}"
|
||||
# Only the headers are consumed here. Everything below builds nothing we
|
||||
# use, and all three enable_language(Fortran): test/CMakeLists.txt:9,
|
||||
# lapack/CMakeLists.txt:6 and blas/testing/CMakeLists.txt:2. They default
|
||||
# to ON because the dependency configures as its own top-level project.
|
||||
#
|
||||
# Whether that probe is harmless depends on what CMake finds. The Visual
|
||||
# Studio generator supports no Fortran, so it finds nothing; clang-cl sits
|
||||
# next to the LLVM toolset's flang, which works. MSVC with Ninja finds
|
||||
# Strawberry Perl's MinGW gfortran instead, which the deps build already
|
||||
# requires for OpenSSL, and hands it the MSVC-style /machine:x64 that
|
||||
# MinGW's ld reads as a missing input file. The configure dies there and
|
||||
# takes the rest of the superbuild with it.
|
||||
-DEIGEN_BUILD_TESTING=OFF
|
||||
-DEIGEN_BUILD_BLAS=OFF
|
||||
-DEIGEN_BUILD_LAPACK=OFF
|
||||
DEPENDS dep_Boost dep_GMP dep_MPFR
|
||||
)
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
set(_conf_cmd ./configure)
|
||||
|
||||
if (MSVC)
|
||||
set(_source_dir "${CMAKE_BINARY_DIR}/dep_FFMPEG-prefix/src/dep_FFMPEG")
|
||||
|
||||
set(PREBUILD_URL_arm64 "https://github.com/Noisyfox/FFmpeg-Builds-Orca/releases/download/autobuild-2026-07-17-14-28/ffmpeg-n7.0.3-31-g9b6ffd74b5-winarm64-orca-shared-7.0.zip")
|
||||
set(PREBUILD_HASH_arm64 "12f4140279f2f8469885e1b5b2e8be9d788882914c21523cacd56989f3548054")
|
||||
set(PREBUILD_URL_x64 "https://github.com/Noisyfox/FFmpeg-Builds-Orca/releases/download/autobuild-2026-07-17-14-28/ffmpeg-n7.0.3-31-g9b6ffd74b5-win64-orca-shared-7.0.zip")
|
||||
set(PREBUILD_HASH_x64 "e65916020ddb9ef84b2666dfbcbfc9b1d67f69d15b4a66db53754637bf2d498c")
|
||||
|
||||
ExternalProject_Add(dep_FFMPEG
|
||||
URL ${PREBUILD_URL_${DEPS_ARCH}}
|
||||
URL_HASH SHA256=${PREBUILD_HASH_${DEPS_ARCH}}
|
||||
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/FFMPEG
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory "${_source_dir}/bin" "${DESTDIR}/bin"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory "${_source_dir}/lib" "${DESTDIR}/lib"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory "${_source_dir}/include" "${DESTDIR}/include"
|
||||
)
|
||||
|
||||
else ()
|
||||
if (APPLE)
|
||||
set(_minos_cmd
|
||||
"--extra-cflags=-mmacosx-version-min=${DEP_OSX_TARGET}"
|
||||
"--extra-ldflags=-mmacosx-version-min=${DEP_OSX_TARGET}"
|
||||
)
|
||||
# Static FFmpeg: nothing to bundle into the .app, no rpath handling.
|
||||
# Disable the VideoToolbox/AudioToolbox HW-accel paths: the player decodes
|
||||
# in software (swscale), and the auto-detected HW objects would drag in
|
||||
# system frameworks that the static libs would then depend on.
|
||||
set(_link_cmd --enable-static --disable-shared --disable-videotoolbox --disable-audiotoolbox)
|
||||
if (IS_CROSS_COMPILE)
|
||||
set(_cross_cmd --enable-cross-compile)
|
||||
set(_pic_cmd --enable-pic)
|
||||
if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64")
|
||||
set(_arch_cmd --arch=arm64)
|
||||
set(_cc_cmd "--cc=clang -arch arm64")
|
||||
else()
|
||||
set(_arch_cmd --arch=x86_64)
|
||||
set(_cc_cmd "--cc=clang -arch x86_64")
|
||||
endif()
|
||||
endif()
|
||||
else ()
|
||||
set(_link_cmd --enable-shared)
|
||||
endif ()
|
||||
|
||||
set(_build_j -j)
|
||||
if(DEFINED ENV{CMAKE_BUILD_PARALLEL_LEVEL})
|
||||
set(_build_j "-j$ENV{CMAKE_BUILD_PARALLEL_LEVEL}")
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(dep_FFMPEG
|
||||
URL https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n7.0.3.tar.gz
|
||||
URL_HASH SHA256=DEEDCABE339165214A3637DF4C86A507AEF0D793CF8774FF68735F4737E8DDBC
|
||||
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/FFMPEG
|
||||
CONFIGURE_COMMAND ${_conf_cmd}
|
||||
${_cross_cmd}
|
||||
${_pic_cmd}
|
||||
${_arch_cmd}
|
||||
${_cc_cmd}
|
||||
"--prefix=${DESTDIR}"
|
||||
${_link_cmd}
|
||||
${_minos_cmd}
|
||||
--disable-doc
|
||||
--enable-small
|
||||
--disable-outdevs
|
||||
--disable-filters
|
||||
--enable-filter=*null*,afade,*fifo,*format,*resample,aeval,allrgb,allyuv,atempo,pan,*bars,color,*key,crop,draw*,eq*,framerate,*_qsv,*_vaapi,*v4l2*,hw*,scale,volume,test*
|
||||
--disable-protocols
|
||||
--enable-protocol=file,fd,pipe,rtp,udp
|
||||
--disable-muxers
|
||||
--enable-muxer=rtp
|
||||
--disable-encoders
|
||||
--disable-decoders
|
||||
--enable-decoder=*aac*,h264*,mp3*,mjpeg,rv*
|
||||
--disable-demuxers
|
||||
--enable-demuxer=h264,mp3,mov
|
||||
--disable-zlib
|
||||
--disable-avdevice
|
||||
BUILD_IN_SOURCE ON
|
||||
BUILD_COMMAND make ${_build_j}
|
||||
INSTALL_COMMAND make install
|
||||
)
|
||||
|
||||
endif()
|
||||
@@ -1,3 +1,20 @@
|
||||
diff --git a/adm/cmake/occt_defs_flags.cmake b/adm/cmake/occt_defs_flags.cmake
|
||||
index 00000000..00000001 100644
|
||||
--- a/adm/cmake/occt_defs_flags.cmake
|
||||
+++ b/adm/cmake/occt_defs_flags.cmake
|
||||
@@ -134,7 +134,11 @@
|
||||
set (CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}")
|
||||
endif()
|
||||
# Optimize size of binaries
|
||||
- set (CMAKE_SHARED_LINKER_FLAGS "-Wl,-s ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
+ # clang-cl reports the Clang compiler ID, and OCCT builds shared on Windows,
|
||||
+ # where the MSVC-style linker gets this flag as an argument it does not know.
|
||||
+ if (NOT WIN32)
|
||||
+ set (CMAKE_SHARED_LINKER_FLAGS "-Wl,-s ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
+ endif()
|
||||
elseif(MINGW)
|
||||
add_definitions(-D_WIN32_WINNT=0x0601)
|
||||
# _WIN32_WINNT=0x0601 (use Windows 7 SDK)
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index d98acc0f..28eb8eb4 100644
|
||||
--- a/CMakeLists.txt
|
||||
@@ -168,6 +185,32 @@ index d98acc0f..28eb8eb4 100644
|
||||
endforeach()
|
||||
|
||||
if (BUILD_SAMPLES_QT)
|
||||
diff --git a/adm/cmake/occt_macros.cmake b/adm/cmake/occt_macros.cmake
|
||||
index 224c96b1..8c94a1c5 100644
|
||||
--- a/adm/cmake/occt_macros.cmake
|
||||
+++ b/adm/cmake/occt_macros.cmake
|
||||
@@ -608,7 +608,7 @@ macro (OCCT_INSERT_CODE_FOR_TARGET)
|
||||
install(CODE "if (\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$\")
|
||||
set (OCCT_INSTALL_BIN_LETTER \"\")
|
||||
elseif (\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^([Rr][Ee][Ll][Ww][Ii][Tt][Hh][Dd][Ee][Bb][Ii][Nn][Ff][Oo])$\")
|
||||
- set (OCCT_INSTALL_BIN_LETTER \"i\")
|
||||
+ set (OCCT_INSTALL_BIN_LETTER \"\")
|
||||
elseif (\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^([Dd][Ee][Bb][Uu][Gg])$\")
|
||||
set (OCCT_INSTALL_BIN_LETTER \"d\")
|
||||
endif()")
|
||||
diff --git a/adm/cmake/occt_toolkit.cmake b/adm/cmake/occt_toolkit.cmake
|
||||
index 550e0e2f..7ac1a3b8 100644
|
||||
--- a/adm/cmake/occt_toolkit.cmake
|
||||
+++ b/adm/cmake/occt_toolkit.cmake
|
||||
@@ -241,7 +241,7 @@
|
||||
else()
|
||||
set (aReleasePdbConf)
|
||||
endif()
|
||||
- install (FILES ${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/bin\${OCCT_INSTALL_BIN_LETTER}/${PROJECT_NAME}.pdb
|
||||
+ install (FILES $<TARGET_PDB_FILE:${PROJECT_NAME}>
|
||||
CONFIGURATIONS Debug ${aReleasePdbConf} RelWithDebInfo
|
||||
DESTINATION "${INSTALL_DIR_BIN}\${OCCT_INSTALL_BIN_LETTER}")
|
||||
endif()
|
||||
diff --git a/src/Font/Font_FTFont.cxx b/src/Font/Font_FTFont.cxx
|
||||
index 5ae9899f..0a17372b 100644
|
||||
--- a/src/Font/Font_FTFont.cxx
|
||||
|
||||
@@ -17,10 +17,20 @@ else()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(_conf_cmd perl Configure )
|
||||
set(_openssl_msvc_env CC=cl CXX=cl RC=rc CL=/FS)
|
||||
# OpenSSL's perl Configure honors the CC environment variable, but the
|
||||
# VC-WIN64A makefile only works with cl (an unquoted clang-cl path with
|
||||
# spaces, e.g. exported by CLion, silently produces no .obj files and the
|
||||
# lib step fails with LNK1181). Pin the upstream toolchain.
|
||||
# Keep rc.exe resolved from the MSVC developer environment as well. The
|
||||
# absolute Windows SDK path contains spaces and OpenSSL 1.1.1 writes it to
|
||||
# the generated nmake file without quoting, which skips .res generation.
|
||||
# /FS serializes access to OpenSSL's shared generated PDB when cl is
|
||||
# driven through nmake from a Ninja configure step.
|
||||
set(_conf_cmd ${CMAKE_COMMAND} -E env ${_openssl_msvc_env} perl Configure )
|
||||
set(_cross_comp_prefix_line "")
|
||||
set(_make_cmd nmake)
|
||||
set(_install_cmd nmake install_sw )
|
||||
set(_make_cmd ${CMAKE_COMMAND} -E env ${_openssl_msvc_env} nmake)
|
||||
set(_install_cmd ${CMAKE_COMMAND} -E env ${_openssl_msvc_env} nmake install_sw )
|
||||
else()
|
||||
if(APPLE)
|
||||
set(_conf_cmd export MACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} && ./Configure -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET})
|
||||
@@ -52,6 +62,14 @@ ExternalProject_Add(dep_OpenSSL
|
||||
CONFIGURE_COMMAND ${_conf_cmd} ${_cross_arch}
|
||||
"--openssldir=${DESTDIR}"
|
||||
"--prefix=${DESTDIR}"
|
||||
# OpenSSL's linux-x86_64 target sets multilib=64, so it installs to
|
||||
# <prefix>/lib64 while every other dep uses <prefix>/lib. CPython's
|
||||
# --with-openssl only ever emits -L<dir>/lib, so it misses the bundled
|
||||
# static libs and silently links the system OpenSSL instead -- which,
|
||||
# against 1.1.1w headers, leaves _ssl.so with an undefined
|
||||
# SSL_get_peer_certificate (removed in OpenSSL 3.x). Pin libdir so the
|
||||
# prefix stays single-layout.
|
||||
"--libdir=lib"
|
||||
${_cross_comp_prefix_line}
|
||||
no-shared
|
||||
no-asm
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set(TBB_LINK_DEF_FILE_FLAG ${CMAKE_LINK_DEF_FILE_FLAG})
|
||||
set(TBB_DEF_FILE_PREFIX win${TBB_ARCH})
|
||||
|
||||
# Workaround for CMake issue https://gitlab.kitware.com/cmake/cmake/issues/18317.
|
||||
# TODO: consider use of CMP0092 CMake policy.
|
||||
string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
|
||||
set(TBB_WARNING_LEVEL $<$<BOOL:${TBB_STRICT}>:/W4> $<$<BOOL:${TBB_STRICT}>:/WX>)
|
||||
|
||||
# Warning suppression C4324: structure was padded due to alignment specifier
|
||||
set(TBB_WARNING_SUPPRESS /wd4324)
|
||||
set(TBB_TEST_COMPILE_FLAGS /bigobj)
|
||||
|
||||
if (MSVC_VERSION LESS_EQUAL 1900)
|
||||
# Warning suppression C4503 for VS2015 and earlier:
|
||||
# decorated name length exceeded, name was truncated.
|
||||
# More info can be found at
|
||||
# https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4503
|
||||
set(TBB_TEST_COMPILE_FLAGS ${TBB_TEST_COMPILE_FLAGS} /wd4503)
|
||||
endif()
|
||||
|
||||
set(TBB_LIB_COMPILE_FLAGS -D_CRT_SECURE_NO_WARNINGS /GS)
|
||||
set(TBB_COMMON_COMPILE_FLAGS /volatile:iso /FS /EHsc)
|
||||
|
||||
# Ignore /WX set through add_compile_options() or added to CMAKE_CXX_FLAGS if TBB_STRICT is disabled.
|
||||
if (NOT TBB_STRICT AND COMMAND tbb_remove_compile_flag)
|
||||
tbb_remove_compile_flag(/WX)
|
||||
endif()
|
||||
|
||||
if (WINDOWS_STORE OR TBB_WINDOWS_DRIVER)
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} /D_WIN32_WINNT=0x0A00)
|
||||
set(TBB_COMMON_LINK_FLAGS -NODEFAULTLIB:kernel32.lib -INCREMENTAL:NO)
|
||||
set(TBB_COMMON_LINK_LIBS OneCore.lib)
|
||||
endif()
|
||||
|
||||
if (WINDOWS_STORE)
|
||||
if (NOT CMAKE_SYSTEM_VERSION EQUAL 10.0)
|
||||
message(FATAL_ERROR "CMAKE_SYSTEM_VERSION must be equal to 10.0")
|
||||
endif()
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} /ZW /ZW:nostdlib)
|
||||
# CMake define this extra lib, remove it for this build type
|
||||
string(REGEX REPLACE "WindowsApp.lib" "" CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES}")
|
||||
|
||||
if (TBB_NO_APPCONTAINER)
|
||||
set(TBB_LIB_LINK_FLAGS ${TBB_LIB_LINK_FLAGS} -APPCONTAINER:NO)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (TBB_WINDOWS_DRIVER)
|
||||
# Since this is universal driver disable this variable
|
||||
set(CMAKE_SYSTEM_PROCESSOR "")
|
||||
# CMake define list additional libs, remove it for this build type
|
||||
set(CMAKE_CXX_STANDARD_LIBRARIES "")
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} /D _UNICODE /DUNICODE /DWINAPI_FAMILY=WINAPI_FAMILY_APP /D__WRL_NO_DEFAULT_LIB__)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED TBB_ENABLE_IPO)
|
||||
if (DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION)
|
||||
set(TBB_ENABLE_IPO ${CMAKE_INTERPROCEDURAL_OPTIMIZATION})
|
||||
else()
|
||||
set(TBB_ENABLE_IPO ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (TBB_ENABLE_IPO)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "(Clang|IntelLLVM)")
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86|AMD64)")
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -mrtm -mwaitpkg)
|
||||
endif()
|
||||
set(TBB_OPENMP_NO_LINK_FLAG TRUE)
|
||||
set(TBB_IPO_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:-flto>)
|
||||
else()
|
||||
set(TBB_IPO_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:/GL>)
|
||||
set(TBB_IPO_LINK_FLAGS $<$<NOT:$<CONFIG:Debug>>:-LTCG> $<$<NOT:$<CONFIG:Debug>>:-INCREMENTAL:NO>)
|
||||
endif()
|
||||
else()
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "(Clang|IntelLLVM)" AND CMAKE_SYSTEM_PROCESSOR MATCHES "(x86|AMD64)")
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -mrtm -mwaitpkg)
|
||||
endif()
|
||||
set(TBB_IPO_COMPILE_FLAGS "")
|
||||
set(TBB_IPO_LINK_FLAGS "")
|
||||
endif()
|
||||
|
||||
set(TBB_OPENMP_FLAG /openmp)
|
||||
@@ -1,4 +1,6 @@
|
||||
if (FLATPAK AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
if (MSVC)
|
||||
set(_patch_command ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_DIR}/MSVC.cmake ./cmake/compilers/MSVC.cmake)
|
||||
elseif (FLATPAK AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(_patch_command ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_DIR}/GNU.cmake ./cmake/compilers/GNU.cmake)
|
||||
else()
|
||||
set(_patch_command "")
|
||||
@@ -13,6 +15,8 @@ orcaslicer_add_cmake_project(
|
||||
-DTBB_BUILD_SHARED=OFF
|
||||
-DTBB_BUILD_TESTS=OFF
|
||||
-DTBB_TEST=OFF
|
||||
-DTBB_ENABLE_IPO=OFF
|
||||
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
-DCMAKE_DEBUG_POSTFIX=_debug
|
||||
)
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
# wxInspector finds wxWidgets through CMake's FindwxWidgets module, which only
|
||||
# searches lib/vc*_lib because _WX_TOOL is hardcoded to "vc". A superbuild driven
|
||||
# by clang-cl installs wxWidgets into lib/clang_x64_lib, so hand the module the
|
||||
# directory wxWidgets actually used, derived the same way wxWidgetsConfig.cmake
|
||||
# derives it.
|
||||
set(_wxinspector_wx_hints "")
|
||||
if (MSVC)
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(_wx_compiler_prefix "clang")
|
||||
else ()
|
||||
set(_wx_compiler_prefix "vc")
|
||||
endif ()
|
||||
set(_wx_arch_suffix "")
|
||||
if (CMAKE_GENERATOR_PLATFORM AND NOT CMAKE_GENERATOR_PLATFORM STREQUAL "Win32")
|
||||
string(TOLOWER "_${CMAKE_GENERATOR_PLATFORM}" _wx_arch_suffix)
|
||||
elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(_wx_arch_suffix "_x64")
|
||||
endif ()
|
||||
set(_wxinspector_wx_hints
|
||||
"-DwxWidgets_ROOT_DIR=${DESTDIR}"
|
||||
"-DwxWidgets_LIB_DIR=${DESTDIR}/lib/${_wx_compiler_prefix}${_wx_arch_suffix}_lib")
|
||||
endif ()
|
||||
|
||||
orcaslicer_add_cmake_project(
|
||||
wxInspector
|
||||
URL https://github.com/Noisyfox/wxInspector/archive/refs/tags/v1.0.0.zip
|
||||
@@ -6,6 +29,7 @@ orcaslicer_add_cmake_project(
|
||||
CMAKE_ARGS
|
||||
-DCMAKE_CXX_FLAGS="-DwxDEBUG_LEVEL=0"
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
${_wxinspector_wx_hints}
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
|
||||
@@ -37,7 +37,11 @@ target_include_directories(Clipper2
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
target_compile_options(Clipper2 PRIVATE /W4 /WX)
|
||||
if (MSVC AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
target_compile_options(Clipper2 PRIVATE /W4 /WX)
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||
target_compile_options(Clipper2 PRIVATE /W4)
|
||||
endif()
|
||||
else()
|
||||
target_compile_options(Clipper2 PRIVATE -Wall -Wextra -Wpedantic -Werror)
|
||||
target_link_libraries(Clipper2 PUBLIC -lm)
|
||||
|
||||
@@ -2856,6 +2856,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesDefault()
|
||||
{
|
||||
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
||||
0x2000, 0x206F, // General Punctuation
|
||||
0x2103, 0x2103, // ℃ Celsius symbol
|
||||
0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
|
||||
0x31F0, 0x31FF, // Katakana Phonetic Extensions
|
||||
0xFF00, 0xFFEF, // Half-width characters
|
||||
|
||||
@@ -465,6 +465,57 @@ static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *stat
|
||||
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
|
||||
y = r.ymin;
|
||||
}
|
||||
else
|
||||
{
|
||||
// In multi-line mode, clamp y to stay within the text vertical bounds.
|
||||
// This lets the click still land at a valid location if the mouse is slightly
|
||||
// above or below the text.
|
||||
StbTexteditRow r;
|
||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||
int i = 0;
|
||||
float base_y = 0, y_min, y_max;
|
||||
|
||||
// Get the first row to establish y_min and start the iteration
|
||||
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
|
||||
if (r.num_chars <= 0)
|
||||
{
|
||||
state->cursor = 0;
|
||||
state->select_start = state->cursor;
|
||||
state->select_end = state->cursor;
|
||||
state->has_preferred_x = 0;
|
||||
return;
|
||||
}
|
||||
y_min = r.ymin;
|
||||
y_max = base_y + r.ymax;
|
||||
i = r.num_chars;
|
||||
base_y += r.baseline_y_delta;
|
||||
|
||||
// Walk the remaining rows to find the bottom of the last row
|
||||
while (i < n)
|
||||
{
|
||||
STB_TEXTEDIT_LAYOUTROW(&r, str, i);
|
||||
if (r.num_chars <= 0)
|
||||
break;
|
||||
y_max = base_y + r.ymax;
|
||||
i += r.num_chars;
|
||||
base_y += r.baseline_y_delta;
|
||||
}
|
||||
|
||||
// If the text ends with a newline, account for the empty trailing line
|
||||
// so the cursor can be placed on it
|
||||
if (n > 0 && STB_TEXTEDIT_GETCHAR(str, n - 1) == STB_TEXTEDIT_NEWLINE)
|
||||
{
|
||||
STB_TEXTEDIT_LAYOUTROW(&r, str, n);
|
||||
y_max = base_y + r.ymax;
|
||||
}
|
||||
|
||||
// Subtract half the last line height to avoid rounding issues when the mouse
|
||||
// is just barely below the last line (keep cursor on the last line, not after the text)
|
||||
y_max -= (r.ymax - r.ymin) * 0.5f;
|
||||
|
||||
if (y < y_min) y = y_min;
|
||||
if (y > y_max) y = y_max;
|
||||
}
|
||||
|
||||
state->cursor = stb_text_locate_coord(str, x, y);
|
||||
state->select_start = state->cursor;
|
||||
@@ -485,6 +536,50 @@ static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state
|
||||
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
|
||||
y = r.ymin;
|
||||
}
|
||||
else
|
||||
{
|
||||
// In multi-line mode, clamp y to stay within the text vertical bounds.
|
||||
// This lets the drag keep working if the mouse goes off the top or bottom of the text.
|
||||
StbTexteditRow r;
|
||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||
int i = 0;
|
||||
float base_y = 0, y_min, y_max;
|
||||
|
||||
// Get the first row to establish y_min and start the iteration
|
||||
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
|
||||
if (r.num_chars <= 0)
|
||||
return;
|
||||
y_min = r.ymin;
|
||||
y_max = base_y + r.ymax;
|
||||
i = r.num_chars;
|
||||
base_y += r.baseline_y_delta;
|
||||
|
||||
// Walk the remaining rows to find the bottom of the last row
|
||||
while (i < n)
|
||||
{
|
||||
STB_TEXTEDIT_LAYOUTROW(&r, str, i);
|
||||
if (r.num_chars <= 0)
|
||||
break;
|
||||
y_max = base_y + r.ymax;
|
||||
i += r.num_chars;
|
||||
base_y += r.baseline_y_delta;
|
||||
}
|
||||
|
||||
// If the text ends with a newline, account for the empty trailing line
|
||||
// so the cursor can be placed on it
|
||||
if (n > 0 && STB_TEXTEDIT_GETCHAR(str, n - 1) == STB_TEXTEDIT_NEWLINE)
|
||||
{
|
||||
STB_TEXTEDIT_LAYOUTROW(&r, str, n);
|
||||
y_max = base_y + r.ymax;
|
||||
}
|
||||
|
||||
// Subtract half the last line height to avoid rounding issues when the mouse
|
||||
// is just barely below the last line (keep cursor on the last line, not after the text)
|
||||
y_max -= (r.ymax - r.ymin) * 0.5f;
|
||||
|
||||
if (y < y_min) y = y_min;
|
||||
if (y > y_max) y = y_max;
|
||||
}
|
||||
|
||||
if (state->select_start == state->select_end)
|
||||
state->select_start = state->cursor;
|
||||
|
||||
@@ -11,6 +11,8 @@ add_library(miniz_static STATIC
|
||||
|
||||
if(${CMAKE_C_COMPILER_ID} STREQUAL "GNU")
|
||||
target_compile_definitions(miniz_static PRIVATE _GNU_SOURCE)
|
||||
elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||
target_compile_options(miniz_static PRIVATE /clang:-Wno-error=incompatible-pointer-types)
|
||||
endif()
|
||||
|
||||
target_link_libraries(miniz INTERFACE miniz_static)
|
||||
|
||||
@@ -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 <data_dir>/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` |
|
||||
@@ -0,0 +1,376 @@
|
||||
# macOS FFmpeg Media Player Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Make macOS use the same FFmpeg-based media player (`wxMediaCtrl3` + `AVVideoDecoder`) as Windows/Linux, linking the static FFmpeg libraries from the deps build, and remove the old `wxMediaCtrl2.mm` BambuPlayer-based player.
|
||||
|
||||
**Architecture:** The new player is platform-neutral C++ already used on Linux/Windows. Enabling it on macOS is pure build wiring: compile `wxMediaCtrl3.cpp` + `AVVideoDecoder.cpp` on macOS, drop the `__WXMAC__` alias that redirects `wxMediaCtrl3` to the old `wxMediaCtrl2`, and link static FFmpeg (`libavcodec.a`/`libswscale.a`/`libavutil.a`) from the deps install. The Bambu stream API is dlsym'd at runtime from the network plugin (`libBambuSource.dylib`), which already exports it — no plugin changes needed. Rendering reuses the existing `wxImage` → `DrawBitmap` paint path (same as Linux).
|
||||
|
||||
**Tech Stack:** C++17, wxWidgets, CMake, FFmpeg 7.0.3 (libavcodec/libswscale/libavutil), macOS (Xcode generator), `deps/` ExternalProject build system.
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Branch: `dev/ffmpeg-player-macos`. Commit after every task.
|
||||
- **Linux and Windows builds must not change** — the FFmpeg deps flag change is guarded by `APPLE`; Linux keeps `--enable-shared`, Windows keeps its prebuilt DLL zips.
|
||||
- Static FFmpeg only on macOS: deps produce `libavcodec.a`/`libswscale.a`/`libavutil.a`; the app links those explicitly — the app binary must have **no** `libav*` dylib references (`otool -L` check).
|
||||
- Follow existing code style: PascalCase classes, snake_case functions, C++17.
|
||||
- No changes to `StatusPanel.cpp`, `MediaPlayCtrl.*`, or the BambuTunnel interface — the app already creates `wxMediaCtrl3` and uses only its public interface.
|
||||
- The player cannot be unit-tested (hardware/plugin-dependent GUI code); verification is build-level, link-level, and manual runtime on a Mac.
|
||||
- `localization/i18n/list.txt` references only `wxMediaCtrl2.cpp` (Win/Linux, stays) — no translation-list changes needed.
|
||||
- Build dirs on the dev machine: main app = `build_arm64/` (Xcode generator, multi-config), deps = `deps/build/arm64/` (Unix Makefiles). App target name: `OrcaSlicer`. Substitute your own configured build dirs where noted.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Enable wxMediaCtrl3 on macOS and link static FFmpeg
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/slic3r/GUI/wxMediaCtrl3.h` (lines 18–22: the `#ifdef __WXMAC__` alias branch)
|
||||
- Modify: `src/slic3r/GUI/wxMediaCtrl3.cpp:13` (uncomment the event define)
|
||||
- Modify: `src/slic3r/GUI/wxMediaCtrl2.cpp:101` (remove the event define)
|
||||
- Modify: `src/slic3r/CMakeLists.txt` (APPLE source list ~lines 779–792; FFmpeg link block ~lines 905–910)
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: nothing new (all classes already exist).
|
||||
- Produces: `wxMediaCtrl3` class compiled on macOS with the same interface as Linux/Windows — `Load(wxURI)`, `Play()`, `Stop()`, `SetIdleImage(wxString)`, `GetState()`, `GetLastError()`, `GetVideoSize()`, event `EVT_MEDIA_CTRL_STAT` defined once in the lib (from `wxMediaCtrl3.cpp`).
|
||||
|
||||
- [ ] **Step 1: Remove the macOS alias in wxMediaCtrl3.h**
|
||||
|
||||
Current (lines 16–23 of `src/slic3r/GUI/wxMediaCtrl3.h`):
|
||||
|
||||
```cpp
|
||||
void wxMediaCtrl_OnSize(wxWindow * ctrl, wxSize const & videoSize, int width, int height);
|
||||
|
||||
#ifdef __WXMAC__
|
||||
|
||||
#include "wxMediaCtrl2.h"
|
||||
#define wxMediaCtrl3 wxMediaCtrl2
|
||||
|
||||
#else
|
||||
|
||||
#define BAMBU_DYNAMIC
|
||||
```
|
||||
|
||||
New:
|
||||
|
||||
```cpp
|
||||
void wxMediaCtrl_OnSize(wxWindow * ctrl, wxSize const & videoSize, int width, int height);
|
||||
|
||||
#define BAMBU_DYNAMIC
|
||||
```
|
||||
|
||||
Also remove the matching `#endif` that closed the `#else` branch (the one before the final `#endif /* wxMediaCtrl3_h */`), so the file's `#ifndef`/`#endif` guard pair stays balanced.
|
||||
|
||||
- [ ] **Step 2: Move the EVT_MEDIA_CTRL_STAT definition into wxMediaCtrl3.cpp**
|
||||
|
||||
In `src/slic3r/GUI/wxMediaCtrl3.cpp:13`, uncomment:
|
||||
|
||||
```cpp
|
||||
//wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
|
||||
```
|
||||
|
||||
becomes:
|
||||
|
||||
```cpp
|
||||
wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
|
||||
```
|
||||
|
||||
In `src/slic3r/GUI/wxMediaCtrl2.cpp:101`, delete:
|
||||
|
||||
```cpp
|
||||
wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
|
||||
```
|
||||
|
||||
(One definition total in the lib — `MediaPlayCtrl.cpp:59` binds this event on the media ctrl.)
|
||||
|
||||
- [ ] **Step 3: Update the APPLE source list in CMakeLists.txt**
|
||||
|
||||
In `src/slic3r/CMakeLists.txt`, the APPLE branch (currently compiles `wxMediaCtrl2.mm`, which becomes dead on macOS):
|
||||
|
||||
```cmake
|
||||
GUI/wxMediaCtrl2.mm
|
||||
GUI/wxMediaCtrl2.h
|
||||
GUI/wxMediaCtrl3.h
|
||||
)
|
||||
```
|
||||
|
||||
becomes:
|
||||
|
||||
```cmake
|
||||
GUI/AVVideoDecoder.cpp
|
||||
GUI/AVVideoDecoder.hpp
|
||||
GUI/wxMediaCtrl3.cpp
|
||||
GUI/wxMediaCtrl3.h
|
||||
)
|
||||
```
|
||||
|
||||
(The `else ()` branch — Win/Linux — stays exactly as it is.)
|
||||
|
||||
- [ ] **Step 4: Link static FFmpeg on macOS**
|
||||
|
||||
In `src/slic3r/CMakeLists.txt`, the FFmpeg block (currently `if (NOT APPLE)`):
|
||||
|
||||
```cmake
|
||||
if (NOT APPLE)
|
||||
pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
|
||||
libavcodec
|
||||
libswscale
|
||||
libavutil
|
||||
)
|
||||
target_link_libraries(libslic3r_gui PkgConfig::LIBAV)
|
||||
endif()
|
||||
```
|
||||
|
||||
becomes:
|
||||
|
||||
```cmake
|
||||
if (APPLE)
|
||||
# Static FFmpeg from the deps install: nothing to bundle into the .app,
|
||||
# no rpath/install_name handling. Order matters: avcodec -> swscale -> avutil.
|
||||
find_library(LIBAVCODEC_LIBRARY NAMES libavcodec.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
||||
find_library(LIBSWSCALE_LIBRARY NAMES libswscale.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
||||
find_library(LIBAVUTIL_LIBRARY NAMES libavutil.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
||||
target_link_libraries(libslic3r_gui ${LIBAVCODEC_LIBRARY} ${LIBSWSCALE_LIBRARY} ${LIBAVUTIL_LIBRARY})
|
||||
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${CMAKE_PREFIX_PATH}/include)
|
||||
else ()
|
||||
pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
|
||||
libavcodec
|
||||
libswscale
|
||||
libavutil
|
||||
)
|
||||
target_link_libraries(libslic3r_gui PkgConfig::LIBAV)
|
||||
endif()
|
||||
```
|
||||
|
||||
The deps install (`${CMAKE_PREFIX_PATH}/lib`) already contains the three `.a` files from the existing arm64 deps build — no deps rebuild needed for this task.
|
||||
|
||||
- [ ] **Step 5: Reconfigure and build the app**
|
||||
|
||||
Run (Xcode generator; `cmake` re-runs automatically on build):
|
||||
|
||||
```bash
|
||||
cmake --build build_arm64 --config RelWithDebInfo --target OrcaSlicer
|
||||
```
|
||||
|
||||
Expected: configure succeeds (no `pkg_check_modules` errors on macOS, `find_library` finds all three `.a` files), compile succeeds (`wxMediaCtrl3.cpp` and `AVVideoDecoder.cpp` compile on macOS without changes), link succeeds.
|
||||
|
||||
If CMake complains that `wxMediaCtrl3.h` is included but not in the source list or similar IDE-only warnings — ignore; headers in the list are cosmetic.
|
||||
|
||||
- [ ] **Step 6: Verify no dynamic FFmpeg dependency**
|
||||
|
||||
```bash
|
||||
otool -L build_arm64/src/RelWithDebInfo/OrcaSlicer.app/Contents/MacOS/OrcaSlicer | grep -i "libav" || echo "OK: no dynamic FFmpeg"
|
||||
```
|
||||
|
||||
Expected: prints `OK: no dynamic FFmpeg` (empty grep output). This is the whole point of static linking — nothing to bundle into the `.app`.
|
||||
|
||||
- [ ] **Step 7: Quick sanity — macOS unit tests still pass**
|
||||
|
||||
```bash
|
||||
ctest --test-dir build_arm64/tests/libslic3r --output-on-failure
|
||||
```
|
||||
|
||||
Expected: passes (add `-C RelWithDebInfo` if the multi-config generator requires it). If no tests were built in this build dir, build target `tests` first (`cmake --build build_arm64 --config RelWithDebInfo --target tests`).
|
||||
|
||||
- [ ] **Step 8: Commit**
|
||||
|
||||
```bash
|
||||
git add src/slic3r/CMakeLists.txt src/slic3r/GUI/wxMediaCtrl3.h src/slic3r/GUI/wxMediaCtrl3.cpp src/slic3r/GUI/wxMediaCtrl2.cpp
|
||||
git commit -m "feat: use FFmpeg media player on macOS with static FFmpeg"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Static-only FFmpeg in the macOS deps build
|
||||
|
||||
**Files:**
|
||||
- Modify: `deps/FFMPEG/FFMPEG.cmake` (non-MSVC branch, APPLE section and CONFIGURE_COMMAND)
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: nothing.
|
||||
- Produces: a deps install on macOS containing only `libavcodec.a`, `libswscale.a`, `libavutil.a` (+ headers) — no `libav*` dylibs, so no bundling/rpath machinery is ever needed on macOS. Linux and Windows output are unchanged.
|
||||
|
||||
- [ ] **Step 1: Add the static flag variable**
|
||||
|
||||
In `deps/FFMPEG/FFMPEG.cmake`, inside the non-MSVC `else ()` branch, in the existing `if (APPLE)` block:
|
||||
|
||||
```cmake
|
||||
if (APPLE)
|
||||
set(_minos_cmd
|
||||
"CFLAGS=-mmacosx-version-min=${DEP_OSX_TARGET}"
|
||||
"LDFLAGS=-mmacosx-version-min=${DEP_OSX_TARGET}"
|
||||
)
|
||||
```
|
||||
|
||||
add after the `_minos_cmd` set:
|
||||
|
||||
```cmake
|
||||
# Static FFmpeg: nothing to bundle into the .app, no rpath handling.
|
||||
# Shared flags must come AFTER --enable-shared below so they win.
|
||||
set(_link_cmd --enable-static --disable-shared)
|
||||
```
|
||||
|
||||
and add a matching `else ()` after the `if (IS_CROSS_COMPILE) ... endif()` block inside that `if (APPLE)`, so non-Apple Unix keeps shared:
|
||||
|
||||
```cmake
|
||||
else ()
|
||||
set(_link_cmd --enable-shared)
|
||||
endif ()
|
||||
```
|
||||
|
||||
(If the existing `if (IS_CROSS_COMPILE)` block is the last thing inside `if (APPLE)`, the new `else ()` closes the `if (APPLE)` itself.)
|
||||
|
||||
- [ ] **Step 2: Use the variable in CONFIGURE_COMMAND**
|
||||
|
||||
In the `ExternalProject_Add(dep_FFMPEG ...)` configure command:
|
||||
|
||||
```cmake
|
||||
"--prefix=${DESTDIR}"
|
||||
--enable-shared
|
||||
```
|
||||
|
||||
becomes:
|
||||
|
||||
```cmake
|
||||
"--prefix=${DESTDIR}"
|
||||
--enable-shared
|
||||
${_link_cmd}
|
||||
```
|
||||
|
||||
Order matters: `--enable-shared` comes first, then `--enable-static --disable-shared` (APPLE) or `--enable-shared` (Linux) — the last flag wins in FFmpeg configure.
|
||||
|
||||
- [ ] **Step 3: Rebuild the FFmpeg dep (slow — several minutes, run in background)**
|
||||
|
||||
The changed CONFIGURE_COMMAND invalidates the ExternalProject stamp, so this re-configures and rebuilds FFmpeg:
|
||||
|
||||
```bash
|
||||
cmake --build deps/build/arm64 --target dep_FFMPEG
|
||||
```
|
||||
|
||||
For a fully clean static-only check (removes the previous shared build tree, which can leave stale `.dylib` files behind in the in-source build):
|
||||
|
||||
```bash
|
||||
rm -rf deps/build/arm64/dep_FFMPEG-prefix
|
||||
cmake --build deps/build/arm64 --target dep_FFMPEG
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Verify the artifacts**
|
||||
|
||||
```bash
|
||||
ls deps/build/arm64/dep_FFMPEG-prefix/src/dep_FFMPEG/libavcodec/*.a
|
||||
ls deps/build/arm64/dep_FFMPEG-prefix/src/dep_FFMPEG/libavcodec/*.dylib 2>/dev/null || echo "OK: no dylibs"
|
||||
```
|
||||
|
||||
Expected: `libavcodec.a` present, second command prints `OK: no dylibs`. Check `libavutil` and `libswscale` the same way.
|
||||
|
||||
- [ ] **Step 5: Verify the app still links against the static libs**
|
||||
|
||||
```bash
|
||||
cmake --build build_arm64 --config RelWithDebInfo --target OrcaSlicer
|
||||
otool -L build_arm64/src/RelWithDebInfo/OrcaSlicer.app/Contents/MacOS/OrcaSlicer | grep -i "libav" || echo "OK: no dynamic FFmpeg"
|
||||
```
|
||||
|
||||
Expected: build succeeds, `OK: no dynamic FFmpeg`.
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
git add deps/FFMPEG/FFMPEG.cmake
|
||||
git commit -m "build: build static-only FFmpeg for macOS deps"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Remove the old macOS player
|
||||
|
||||
**Files:**
|
||||
- Delete: `src/slic3r/GUI/wxMediaCtrl2.mm`
|
||||
- Delete: `src/slic3r/GUI/BambuPlayer/BambuPlayer.h` (and the empty `BambuPlayer/` dir)
|
||||
- Modify: `src/slic3r/GUI/wxMediaCtrl2.h` (remove the `#ifdef __WXMAC__` section, lines 22–60)
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: Task 1 (macOS no longer references `wxMediaCtrl2` — nothing includes `wxMediaCtrl2.h` on macOS anymore; `wxMediaCtrl2` is never instantiated on any platform).
|
||||
- Produces: a clean tree where the old BambuPlayer-based player is gone from macOS. The `BambuPlayer` ObjC class itself remains inside the network plugin (external prebuilt binary) — only the GUI-side consumer is removed.
|
||||
|
||||
- [ ] **Step 1: Delete the old player files**
|
||||
|
||||
```bash
|
||||
git rm src/slic3r/GUI/wxMediaCtrl2.mm
|
||||
git rm src/slic3r/GUI/BambuPlayer/BambuPlayer.h
|
||||
rmdir src/slic3r/GUI/BambuPlayer 2>/dev/null || true
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Strip the __WXMAC__ section from wxMediaCtrl2.h**
|
||||
|
||||
In `src/slic3r/GUI/wxMediaCtrl2.h`, remove the entire macOS branch of the `#ifdef __WXMAC__` guard — from `#ifdef __WXMAC__` (line 22) through the closing `};` of the mac class (line 60), and the `#else` marker — leaving only the non-mac `class wxMediaCtrl2 : public wxMediaCtrl { ... };` definition followed by the final `#endif /* wxMediaCtrl2_h */`. The resulting file keeps its `#ifndef`/`#endif` include guard pair balanced.
|
||||
|
||||
The file stays on disk because Win/Linux compile `wxMediaCtrl2.cpp`, which includes it.
|
||||
|
||||
- [ ] **Step 3: Grep for leftover references**
|
||||
|
||||
```bash
|
||||
grep -rn "wxMediaCtrl2.mm\|BambuPlayer/BambuPlayer.h\|BambuPlayer" src/slic3r --include="*.cpp" --include="*.h" --include="*.mm" --include="*.txt"
|
||||
```
|
||||
|
||||
Expected: no hits in `src/slic3r/GUI` (ignore `localization/i18n/list.txt:196`, which lists the Win/Linux `wxMediaCtrl2.cpp` and stays).
|
||||
|
||||
- [ ] **Step 4: Rebuild the app**
|
||||
|
||||
```bash
|
||||
cmake --build build_arm64 --config RelWithDebInfo --target OrcaSlicer
|
||||
```
|
||||
|
||||
Expected: configure + compile + link succeed with the deleted files gone.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add -A src/slic3r/GUI
|
||||
git commit -m "refactor: remove old BambuPlayer-based media player from macOS"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Runtime verification on hardware
|
||||
|
||||
**Files:** none — manual verification.
|
||||
|
||||
**Interfaces:** consumes all prior tasks. Final gate: the new player must actually stream on a Mac.
|
||||
|
||||
- [ ] **Step 1: Launch the freshly built app**
|
||||
|
||||
```bash
|
||||
open build_arm64/src/RelWithDebInfo/OrcaSlicer.app
|
||||
```
|
||||
|
||||
Expected: app launches normally; no crash in the network/device subsystem.
|
||||
|
||||
- [ ] **Step 2: Load the network plugin and open the Device tab**
|
||||
|
||||
Log in / ensure the network plugin (`libBambuSource.dylib`) loads, select a printer, open the Device tab (camera monitoring panel).
|
||||
|
||||
Expected: the camera preview area shows the idle image initially (no crash — this exercises `wxMediaCtrl3::SetIdleImage` and the `wxImage` load path on macOS for the first time).
|
||||
|
||||
- [ ] **Step 3: Start the stream and watch it render**
|
||||
|
||||
Click play / wait for `MediaPlayCtrl` to start the stream.
|
||||
|
||||
Expected: live video renders in the panel. Check the console/log output (`BOOST_LOG` goes to the terminal if run from it, or check the log file):
|
||||
- `stat_log ...` lines appear (the `EVT_MEDIA_CTRL_STAT` path is live — proves the Bambu C API dlsym worked from `libBambuSource.dylib`);
|
||||
- no repeated decode/error messages like `AVVideoDecoder: ...` or `can not find function ...` (proves `StaticBambuLib::get` resolved all Bambu functions);
|
||||
- Stop/Play toggle works; idle image reappears on stop;
|
||||
- window resize keeps aspect ratio (exercises `DoSetSize`/`adjust_frame_size`/`paintEvent`).
|
||||
|
||||
- [ ] **Step 4: Confirm the old player is really gone**
|
||||
|
||||
Expected: nothing in the logs references `BambuPlayer` (the ObjC class is no longer dlsym'd); the video path is entirely `wxMediaCtrl3` + `AVVideoDecoder`.
|
||||
|
||||
If a printer is unavailable, at minimum verify Steps 1–2 (launch + idle image) and note in the PR that live-stream verification needs hardware.
|
||||
|
||||
- [ ] **Step 5: Final review pass**
|
||||
|
||||
```bash
|
||||
git log --oneline -6
|
||||
git show --stat HEAD # and each of the three task commits
|
||||
```
|
||||
|
||||
Expected: the last 4 commits are the design doc + the 3 implementation tasks (each task commit touches only its listed files). Review the diff for scope: no Linux/Windows changes beyond the two `EVT_MEDIA_CTRL_STAT` lines in Task 1, no `StatusPanel`/`MediaPlayCtrl` changes.
|
||||
@@ -0,0 +1,110 @@
|
||||
# FFmpeg Media Player for macOS — Design
|
||||
|
||||
Date: 2026-08-14
|
||||
Branch: `dev/ffmpeg-player-macos`
|
||||
|
||||
## Problem
|
||||
|
||||
The branch's new FFmpeg-based media player (`wxMediaCtrl3` + `AVVideoDecoder`) is used on
|
||||
Windows and Linux, but macOS still runs the old player: `wxMediaCtrl2.mm`, an ObjC
|
||||
`BambuPlayer` class dlsym'd from the Bambu network plugin that renders via CALayer.
|
||||
On macOS, `wxMediaCtrl3` is currently aliased to `wxMediaCtrl2` and FFmpeg is not linked
|
||||
into the app at all.
|
||||
|
||||
Goal: make macOS use the same FFmpeg player as Windows/Linux, linking the **static**
|
||||
FFmpeg libraries from the deps build instead of dynamic ones.
|
||||
|
||||
## Current state (verified)
|
||||
|
||||
- New player (Win/Linux): `GUI/wxMediaCtrl3.cpp` + `GUI/AVVideoDecoder.cpp`. Decodes with
|
||||
FFmpeg (libavcodec/libswscale/libavutil), renders frames into `wxImage` (non-Windows) /
|
||||
`wxBitmap` (Windows) drawn in a `paintEvent`, feeds via the `Bambu_*` C API
|
||||
(`BambuTunnel.h`, `BAMBU_DYNAMIC`) dlsym'd from the network plugin through
|
||||
`StaticBambuLib::get()` (`GUI/Printer/PrinterFileSystem.cpp`, compiled on all platforms).
|
||||
- Old player (macOS): `GUI/wxMediaCtrl2.mm` uses the ObjC `BambuPlayer` class found via
|
||||
`dlsym(module, "OBJC_CLASS_$_BambuPlayer")` in `libBambuSource.dylib`.
|
||||
- The macOS network plugin `libBambuSource.dylib` already exports the full Bambu C API
|
||||
(verified with `nm`), so the new player needs zero plugin changes.
|
||||
- FFmpeg linking in `src/slic3r/CMakeLists.txt` is guarded by `if (NOT APPLE)` —
|
||||
macOS currently does not link FFmpeg.
|
||||
- `deps/FFMPEG/FFMPEG.cmake`: non-MSVC branch builds FFmpeg from source with
|
||||
`--enable-shared`. The existing arm64 deps build on the dev machine happened to be
|
||||
configured with both static and shared enabled, so `libavcodec.a` / `libswscale.a` /
|
||||
`libavutil.a` are already present at
|
||||
`deps/build/arm64/OrcaSlicer_dep/usr/local/lib/`.
|
||||
- `EVT_MEDIA_CTRL_STAT` is `wxDEFINE_EVENT`'d in `wxMediaCtrl2.cpp` (Win/Linux) and
|
||||
`wxMediaCtrl2.mm` (macOS); the define in `wxMediaCtrl3.cpp` is commented out.
|
||||
- `wxMediaCtrl2` is never instantiated anywhere on any platform — dead code.
|
||||
- `StatusPanel` already creates `wxMediaCtrl3`; `MediaPlayCtrl` only uses the
|
||||
`wxMediaCtrl3` interface (`Load/Play/Stop/GetState/GetVideoSize/GetLastError/SetIdleImage`),
|
||||
so no UI-side changes are needed.
|
||||
|
||||
## Approach (approved)
|
||||
|
||||
**Reuse the shared player on macOS.** Compile the existing `wxMediaCtrl3.cpp` +
|
||||
`AVVideoDecoder.cpp` on macOS so all three platforms run one implementation.
|
||||
Rendering uses the existing `wxImage` → `DrawBitmap` paint path, identical to Linux.
|
||||
Known trade-off: frames are scaled to the widget's logical (1x) size, so Retina is
|
||||
slightly soft compared to the old CALayer player. Accepted for now; a Retina-aware
|
||||
scaling follow-up is possible later.
|
||||
|
||||
Rejected alternative: a native CGImage/CALayer renderer for macOS — faster and
|
||||
Retina-crisp, but adds a second render implementation to maintain.
|
||||
|
||||
## Changes
|
||||
|
||||
### 1. Enable the FFmpeg player on macOS (source)
|
||||
|
||||
- `GUI/wxMediaCtrl3.h`: remove the `#ifdef __WXMAC__` branch (lines 18–22) that aliases
|
||||
`wxMediaCtrl3` → `wxMediaCtrl2`. macOS then compiles the real `wxMediaCtrl3` class,
|
||||
including the `BAMBU_DYNAMIC` BambuTunnel path used on Linux.
|
||||
- Event symbol fix: move `wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent)` into
|
||||
`wxMediaCtrl3.cpp` (uncomment the existing line) and remove it from
|
||||
`wxMediaCtrl2.cpp`. One definition total in the lib; all three platforms resolve it.
|
||||
|
||||
### 2. Static FFmpeg linking (deps + app)
|
||||
|
||||
- `deps/FFMPEG/FFMPEG.cmake`: in the non-MSVC branch, pass
|
||||
`--disable-shared --enable-static` when `APPLE`. Linux keeps `--enable-shared`;
|
||||
Windows keeps its prebuilt shared DLL zips. Fresh macOS deps builds install only
|
||||
`libavcodec.a` / `libswscale.a` / `libavutil.a` — no dylibs to bundle, no
|
||||
rpath/install_name handling. (The existing local arm64 deps build already contains
|
||||
the `.a` files, so no deps rebuild is strictly needed to try the change locally,
|
||||
but a fresh CI deps build must produce them.)
|
||||
- `src/slic3r/CMakeLists.txt`:
|
||||
- APPLE branch of `SLIC3R_GUI_SOURCES`: add `GUI/wxMediaCtrl3.cpp`,
|
||||
`GUI/wxMediaCtrl3.h`, `GUI/AVVideoDecoder.cpp`, `GUI/AVVideoDecoder.hpp`;
|
||||
remove `GUI/wxMediaCtrl2.mm` and `GUI/wxMediaCtrl2.h` (the `.h` stays on
|
||||
disk for the Win/Linux build of `wxMediaCtrl2.cpp`, but nothing on macOS
|
||||
includes it after this change).
|
||||
- Add an APPLE mirror of the `NOT APPLE` FFmpeg block: `find_library` for
|
||||
`libavcodec.a`, `libswscale.a`, `libavutil.a` under `${CMAKE_PREFIX_PATH}/lib`
|
||||
with `NO_DEFAULT_PATH`, link them (order avcodec → swscale → avutil), and add
|
||||
`${CMAKE_PREFIX_PATH}/include` as a SYSTEM include directory. Deps are built with
|
||||
`--disable-zlib` and no external codecs, so the three static libs link cleanly.
|
||||
|
||||
### 3. Remove the old player
|
||||
|
||||
- Delete `GUI/wxMediaCtrl2.mm` and `GUI/BambuPlayer/BambuPlayer.h` (header used only
|
||||
by the `.mm`; the real `BambuPlayer` lives inside the network plugin).
|
||||
- Remove the now-dead `__WXMAC__` section of `GUI/wxMediaCtrl2.h`.
|
||||
- `wxMediaCtrl2.cpp` (Win/Linux) stays in the build as-is (dead but harmless; out of
|
||||
scope to remove on this branch).
|
||||
|
||||
### 4. Verification
|
||||
|
||||
- Build on macOS: `cmake --build build_arm64` (or `build/arm64`).
|
||||
- Confirm no dynamic FFmpeg dependency: `otool -L` on the app binary shows no `libav*`
|
||||
dylib references.
|
||||
- Runtime: with the network plugin loaded, the Device tab camera preview streams via
|
||||
the FFmpeg player (check the device page / `MediaPlayCtrl`).
|
||||
- macOS `ctest` still passes — static linking means no test-executable `.so` copying
|
||||
hacks (unlike the Linux shared-lib setup).
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Linux (shared libs, AppImage/flatpak bundling) and Windows (prebuilt DLL zips)
|
||||
keep their current FFmpeg setup.
|
||||
- Retina-aware frame scaling / native CGImage rendering (follow-up if visual quality
|
||||
is judged insufficient).
|
||||
- Audio streaming (neither player plays audio in this UI path).
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-07-23 15:24-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"
|
||||
@@ -982,7 +982,7 @@ msgstr ""
|
||||
#, possible-boost-format
|
||||
msgid ""
|
||||
"Objects(%1%) have duplicated connectors. Some connectors may be missing in slicing result.\n"
|
||||
"Please report to PrusaSlicer team in which scenario this issue happened.\n"
|
||||
"Please report to the OrcaSlicer team in which scenario this issue happened.\n"
|
||||
"Thank you."
|
||||
msgstr ""
|
||||
|
||||
@@ -3385,7 +3385,6 @@ msgstr ""
|
||||
msgid "Innerloop"
|
||||
msgstr ""
|
||||
|
||||
#. TRN To be shown in the main menu View->Top
|
||||
msgid "Top"
|
||||
msgstr ""
|
||||
|
||||
@@ -3609,6 +3608,9 @@ msgstr ""
|
||||
msgid "Arranging"
|
||||
msgstr ""
|
||||
|
||||
msgid "Arranging "
|
||||
msgstr ""
|
||||
|
||||
msgid "Arranging canceled."
|
||||
msgstr ""
|
||||
|
||||
@@ -4450,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"
|
||||
@@ -4531,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 ""
|
||||
|
||||
@@ -4782,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 ""
|
||||
|
||||
@@ -5470,10 +5498,24 @@ msgstr ""
|
||||
msgid "Align to Y axis"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "Camera View"
|
||||
msgid "Front"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "Camera View"
|
||||
msgid "Back"
|
||||
msgstr ""
|
||||
|
||||
#. TRN To be shown in the main menu View->Top
|
||||
msgctxt "Camera View"
|
||||
msgid "Top"
|
||||
msgstr ""
|
||||
|
||||
#. TRN To be shown in the main menu View->Bottom
|
||||
msgctxt "Camera View"
|
||||
msgid "Bottom"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "Camera View"
|
||||
msgid "Left"
|
||||
msgstr ""
|
||||
@@ -5599,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 ""
|
||||
|
||||
@@ -5774,6 +5816,9 @@ msgstr ""
|
||||
msgid "Project"
|
||||
msgstr ""
|
||||
|
||||
msgid "Device (Web)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Yes"
|
||||
msgstr ""
|
||||
|
||||
@@ -5854,19 +5899,13 @@ msgstr ""
|
||||
msgid "Top View"
|
||||
msgstr ""
|
||||
|
||||
#. TRN To be shown in the main menu View->Bottom
|
||||
msgid "Bottom"
|
||||
msgstr ""
|
||||
|
||||
msgid "Bottom View"
|
||||
msgstr ""
|
||||
|
||||
msgid "Front"
|
||||
msgstr ""
|
||||
|
||||
msgid "Front View"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "Camera View"
|
||||
msgid "Rear"
|
||||
msgstr ""
|
||||
|
||||
@@ -7770,20 +7809,20 @@ msgstr ""
|
||||
msgid "Replaced with 3D files from directory:\n"
|
||||
msgstr ""
|
||||
|
||||
#, possible-boost-format
|
||||
msgid "✖ Skipped %1%: same file.\n"
|
||||
#, possible-c-format, possible-boost-format
|
||||
msgid "✖ Skipped %s: same file.\n"
|
||||
msgstr ""
|
||||
|
||||
#, possible-boost-format
|
||||
msgid "✖ Skipped %1%: file does not exist.\n"
|
||||
#, possible-c-format, possible-boost-format
|
||||
msgid "✖ Skipped %s: file does not exist.\n"
|
||||
msgstr ""
|
||||
|
||||
#, possible-boost-format
|
||||
msgid "✖ Skipped %1%: failed to replace.\n"
|
||||
#, possible-c-format, possible-boost-format
|
||||
msgid "✖ Skipped %s: failed to replace.\n"
|
||||
msgstr ""
|
||||
|
||||
#, possible-boost-format
|
||||
msgid "✔ Replaced %1%.\n"
|
||||
#, possible-c-format, possible-boost-format
|
||||
msgid "✔ Replaced %s.\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "Replaced volumes"
|
||||
@@ -8462,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 ""
|
||||
|
||||
@@ -8654,6 +8702,17 @@ msgstr ""
|
||||
msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness."
|
||||
msgstr ""
|
||||
|
||||
msgid "Dimmed layer brightness"
|
||||
msgstr ""
|
||||
|
||||
msgid "%"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n"
|
||||
"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option."
|
||||
msgstr ""
|
||||
|
||||
msgid "Login region"
|
||||
msgstr ""
|
||||
|
||||
@@ -8776,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 ""
|
||||
|
||||
@@ -9031,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 ""
|
||||
|
||||
@@ -9711,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 ""
|
||||
|
||||
@@ -9910,6 +9975,9 @@ msgstr ""
|
||||
msgid "Setting Overrides"
|
||||
msgstr ""
|
||||
|
||||
msgid "Retraction when switching material"
|
||||
msgstr ""
|
||||
|
||||
msgid "Basic information"
|
||||
msgstr ""
|
||||
|
||||
@@ -10036,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%"
|
||||
@@ -10158,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"
|
||||
@@ -11424,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 ""
|
||||
|
||||
@@ -11719,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 ""
|
||||
|
||||
@@ -12258,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 ""
|
||||
|
||||
@@ -12326,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 ""
|
||||
|
||||
@@ -12350,12 +12424,26 @@ msgstr ""
|
||||
msgid "Intra-layer order"
|
||||
msgstr ""
|
||||
|
||||
msgid "Print order within a single layer."
|
||||
msgid ""
|
||||
"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n"
|
||||
"\n"
|
||||
"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n"
|
||||
"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n"
|
||||
"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n"
|
||||
"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n"
|
||||
"\n"
|
||||
"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate."
|
||||
msgstr ""
|
||||
|
||||
msgid "As object list"
|
||||
msgstr ""
|
||||
|
||||
msgid "Best of all (shortest path)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Snake"
|
||||
msgstr ""
|
||||
|
||||
msgid "Slow printing down for better layer cooling"
|
||||
msgstr ""
|
||||
|
||||
@@ -13324,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 ""
|
||||
|
||||
@@ -13804,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 ""
|
||||
|
||||
@@ -14729,7 +14829,7 @@ msgstr ""
|
||||
msgid "Retract amount after wipe"
|
||||
msgstr ""
|
||||
|
||||
#, possible-c-format
|
||||
#, no-c-format, no-boost-format
|
||||
msgid ""
|
||||
"The length of fast retraction after wipe, relative to retraction length.\n"
|
||||
"The value will be clamped by 100% minus the retract amount before the wipe value."
|
||||
@@ -14765,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 ""
|
||||
|
||||
@@ -14858,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 ""
|
||||
|
||||
@@ -15243,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 ""
|
||||
|
||||
@@ -17211,6 +17326,15 @@ msgid ""
|
||||
"Please select one that should be used."
|
||||
msgstr ""
|
||||
|
||||
msgid "Auto-scale for nozzle"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n"
|
||||
"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n"
|
||||
"Turn scaling off only if you wish to print the reference model exactly as-is."
|
||||
msgstr ""
|
||||
|
||||
msgid "PA Calibration"
|
||||
msgstr ""
|
||||
|
||||
@@ -17333,6 +17457,12 @@ msgstr ""
|
||||
msgid "End speed: "
|
||||
msgstr ""
|
||||
|
||||
msgid "Auto-adjust to max volumetric speed"
|
||||
msgstr ""
|
||||
|
||||
msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead."
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Please input valid values:\n"
|
||||
"start > 10\n"
|
||||
@@ -17340,6 +17470,39 @@ msgid ""
|
||||
"end > start + step"
|
||||
msgstr ""
|
||||
|
||||
#, possible-c-format, possible-boost-format
|
||||
msgid ""
|
||||
"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n"
|
||||
" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n"
|
||||
"\n"
|
||||
"%s"
|
||||
msgstr ""
|
||||
|
||||
#, possible-c-format, possible-boost-format
|
||||
msgid ""
|
||||
"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n"
|
||||
"\n"
|
||||
"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed."
|
||||
msgstr ""
|
||||
|
||||
#, possible-c-format, possible-boost-format
|
||||
msgid ""
|
||||
"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n"
|
||||
"\n"
|
||||
"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n"
|
||||
"\n"
|
||||
"Continue?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Continue anyway?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Start retraction length: "
|
||||
msgstr ""
|
||||
|
||||
@@ -18170,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 ""
|
||||
|
||||
@@ -19004,9 +19164,6 @@ msgstr ""
|
||||
msgid "User canceled."
|
||||
msgstr ""
|
||||
|
||||
msgid "Head diameter"
|
||||
msgstr ""
|
||||
|
||||
msgid "Max angle"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Orca Slicer\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-07-23 15:24-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"
|
||||
@@ -978,7 +978,7 @@ msgstr ""
|
||||
#, boost-format
|
||||
msgid ""
|
||||
"Objects(%1%) have duplicated connectors. Some connectors may be missing in slicing result.\n"
|
||||
"Please report to PrusaSlicer team in which scenario this issue happened.\n"
|
||||
"Please report to the OrcaSlicer team in which scenario this issue happened.\n"
|
||||
"Thank you."
|
||||
msgstr ""
|
||||
|
||||
@@ -3381,7 +3381,6 @@ msgstr ""
|
||||
msgid "Innerloop"
|
||||
msgstr ""
|
||||
|
||||
#. TRN To be shown in the main menu View->Top
|
||||
msgid "Top"
|
||||
msgstr ""
|
||||
|
||||
@@ -3605,6 +3604,9 @@ msgstr ""
|
||||
msgid "Arranging"
|
||||
msgstr ""
|
||||
|
||||
msgid "Arranging "
|
||||
msgstr ""
|
||||
|
||||
msgid "Arranging canceled."
|
||||
msgstr ""
|
||||
|
||||
@@ -4446,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"
|
||||
@@ -4527,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 ""
|
||||
|
||||
@@ -4778,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 ""
|
||||
|
||||
@@ -5466,10 +5494,24 @@ msgstr ""
|
||||
msgid "Align to Y axis"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "Camera View"
|
||||
msgid "Front"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "Camera View"
|
||||
msgid "Back"
|
||||
msgstr ""
|
||||
|
||||
#. TRN To be shown in the main menu View->Top
|
||||
msgctxt "Camera View"
|
||||
msgid "Top"
|
||||
msgstr ""
|
||||
|
||||
#. TRN To be shown in the main menu View->Bottom
|
||||
msgctxt "Camera View"
|
||||
msgid "Bottom"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "Camera View"
|
||||
msgid "Left"
|
||||
msgstr ""
|
||||
@@ -5595,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 ""
|
||||
|
||||
@@ -5770,6 +5812,9 @@ msgstr ""
|
||||
msgid "Project"
|
||||
msgstr ""
|
||||
|
||||
msgid "Device (Web)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Yes"
|
||||
msgstr ""
|
||||
|
||||
@@ -5850,19 +5895,13 @@ msgstr ""
|
||||
msgid "Top View"
|
||||
msgstr ""
|
||||
|
||||
#. TRN To be shown in the main menu View->Bottom
|
||||
msgid "Bottom"
|
||||
msgstr ""
|
||||
|
||||
msgid "Bottom View"
|
||||
msgstr ""
|
||||
|
||||
msgid "Front"
|
||||
msgstr ""
|
||||
|
||||
msgid "Front View"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "Camera View"
|
||||
msgid "Rear"
|
||||
msgstr ""
|
||||
|
||||
@@ -7766,20 +7805,20 @@ msgstr ""
|
||||
msgid "Replaced with 3D files from directory:\n"
|
||||
msgstr ""
|
||||
|
||||
#, boost-format
|
||||
msgid "✖ Skipped %1%: same file.\n"
|
||||
#, c-format, boost-format
|
||||
msgid "✖ Skipped %s: same file.\n"
|
||||
msgstr ""
|
||||
|
||||
#, boost-format
|
||||
msgid "✖ Skipped %1%: file does not exist.\n"
|
||||
#, c-format, boost-format
|
||||
msgid "✖ Skipped %s: file does not exist.\n"
|
||||
msgstr ""
|
||||
|
||||
#, boost-format
|
||||
msgid "✖ Skipped %1%: failed to replace.\n"
|
||||
#, c-format, boost-format
|
||||
msgid "✖ Skipped %s: failed to replace.\n"
|
||||
msgstr ""
|
||||
|
||||
#, boost-format
|
||||
msgid "✔ Replaced %1%.\n"
|
||||
#, c-format, boost-format
|
||||
msgid "✔ Replaced %s.\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "Replaced volumes"
|
||||
@@ -8458,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 ""
|
||||
|
||||
@@ -8650,6 +8698,17 @@ msgstr ""
|
||||
msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness."
|
||||
msgstr ""
|
||||
|
||||
msgid "Dimmed layer brightness"
|
||||
msgstr ""
|
||||
|
||||
msgid "%"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n"
|
||||
"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option."
|
||||
msgstr ""
|
||||
|
||||
msgid "Login region"
|
||||
msgstr ""
|
||||
|
||||
@@ -8772,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 ""
|
||||
|
||||
@@ -9027,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 ""
|
||||
|
||||
@@ -9707,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 ""
|
||||
|
||||
@@ -9906,6 +9971,9 @@ msgstr ""
|
||||
msgid "Setting Overrides"
|
||||
msgstr ""
|
||||
|
||||
msgid "Retraction when switching material"
|
||||
msgstr ""
|
||||
|
||||
msgid "Basic information"
|
||||
msgstr ""
|
||||
|
||||
@@ -10032,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%"
|
||||
@@ -10154,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"
|
||||
@@ -11420,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 ""
|
||||
|
||||
@@ -11715,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 ""
|
||||
|
||||
@@ -12254,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 ""
|
||||
|
||||
@@ -12322,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 ""
|
||||
|
||||
@@ -12346,12 +12420,26 @@ msgstr ""
|
||||
msgid "Intra-layer order"
|
||||
msgstr ""
|
||||
|
||||
msgid "Print order within a single layer."
|
||||
msgid ""
|
||||
"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n"
|
||||
"\n"
|
||||
"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n"
|
||||
"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n"
|
||||
"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n"
|
||||
"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n"
|
||||
"\n"
|
||||
"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate."
|
||||
msgstr ""
|
||||
|
||||
msgid "As object list"
|
||||
msgstr ""
|
||||
|
||||
msgid "Best of all (shortest path)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Snake"
|
||||
msgstr ""
|
||||
|
||||
msgid "Slow printing down for better layer cooling"
|
||||
msgstr ""
|
||||
|
||||
@@ -13320,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 ""
|
||||
|
||||
@@ -13800,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 ""
|
||||
|
||||
@@ -14725,7 +14825,7 @@ msgstr ""
|
||||
msgid "Retract amount after wipe"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
#, no-c-format, no-boost-format
|
||||
msgid ""
|
||||
"The length of fast retraction after wipe, relative to retraction length.\n"
|
||||
"The value will be clamped by 100% minus the retract amount before the wipe value."
|
||||
@@ -14761,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 ""
|
||||
|
||||
@@ -14854,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 ""
|
||||
|
||||
@@ -15239,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 ""
|
||||
|
||||
@@ -17207,6 +17322,15 @@ msgid ""
|
||||
"Please select one that should be used."
|
||||
msgstr ""
|
||||
|
||||
msgid "Auto-scale for nozzle"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n"
|
||||
"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n"
|
||||
"Turn scaling off only if you wish to print the reference model exactly as-is."
|
||||
msgstr ""
|
||||
|
||||
msgid "PA Calibration"
|
||||
msgstr ""
|
||||
|
||||
@@ -17329,6 +17453,12 @@ msgstr ""
|
||||
msgid "End speed: "
|
||||
msgstr ""
|
||||
|
||||
msgid "Auto-adjust to max volumetric speed"
|
||||
msgstr ""
|
||||
|
||||
msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead."
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Please input valid values:\n"
|
||||
"start > 10\n"
|
||||
@@ -17336,6 +17466,39 @@ msgid ""
|
||||
"end > start + step"
|
||||
msgstr ""
|
||||
|
||||
#, c-format, boost-format
|
||||
msgid ""
|
||||
"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n"
|
||||
" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n"
|
||||
"\n"
|
||||
"%s"
|
||||
msgstr ""
|
||||
|
||||
#, c-format, boost-format
|
||||
msgid ""
|
||||
"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n"
|
||||
"\n"
|
||||
"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed."
|
||||
msgstr ""
|
||||
|
||||
#, c-format, boost-format
|
||||
msgid ""
|
||||
"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n"
|
||||
"\n"
|
||||
"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n"
|
||||
"\n"
|
||||
"Continue?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Continue anyway?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Start retraction length: "
|
||||
msgstr ""
|
||||
|
||||
@@ -18166,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 ""
|
||||
|
||||
@@ -19000,9 +19160,6 @@ msgstr ""
|
||||
msgid "User canceled."
|
||||
msgstr ""
|
||||
|
||||
msgid "Head diameter"
|
||||
msgstr ""
|
||||
|
||||
msgid "Max angle"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Orca Slicer\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-07-23 15:24-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"
|
||||
@@ -983,11 +983,11 @@ msgstr "Conector"
|
||||
#, boost-format
|
||||
msgid ""
|
||||
"Objects(%1%) have duplicated connectors. Some connectors may be missing in slicing result.\n"
|
||||
"Please report to PrusaSlicer team in which scenario this issue happened.\n"
|
||||
"Please report to the OrcaSlicer team in which scenario this issue happened.\n"
|
||||
"Thank you."
|
||||
msgstr ""
|
||||
"Los objetos(%1%) tienen conectores duplicados. Es posible que falten algunos conectores en el resultado del laminado.\n"
|
||||
"Informe al equipo de PrusaSlicer sobre el escenario en el que se produjo este problema.\n"
|
||||
"Informe al equipo de OrcaSlicer sobre el escenario en el que se produjo este problema.\n"
|
||||
"Gracias."
|
||||
|
||||
msgid "Cut by Plane"
|
||||
@@ -3459,7 +3459,6 @@ msgstr "Recámara"
|
||||
msgid "Innerloop"
|
||||
msgstr "Bucle interno"
|
||||
|
||||
#. TRN To be shown in the main menu View->Top
|
||||
msgid "Top"
|
||||
msgstr "Superior"
|
||||
|
||||
@@ -3687,6 +3686,10 @@ msgstr "Organizando..."
|
||||
msgid "Arranging"
|
||||
msgstr "Organizando"
|
||||
|
||||
# AI Translated
|
||||
msgid "Arranging "
|
||||
msgstr "Organizando "
|
||||
|
||||
msgid "Arranging canceled."
|
||||
msgstr "Organización cancelada."
|
||||
|
||||
@@ -4561,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"
|
||||
@@ -4681,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."
|
||||
|
||||
@@ -4935,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"
|
||||
|
||||
@@ -5630,10 +5665,27 @@ msgstr "Evitar la zona de calibración del extrusor"
|
||||
msgid "Align to Y axis"
|
||||
msgstr "Alinear con el eje Y"
|
||||
|
||||
# AI Translated
|
||||
msgctxt "Camera View"
|
||||
msgid "Front"
|
||||
msgstr "Frontal"
|
||||
|
||||
msgctxt "Camera View"
|
||||
msgid "Back"
|
||||
msgstr "Posterior"
|
||||
|
||||
# AI Translated
|
||||
#. TRN To be shown in the main menu View->Top
|
||||
msgctxt "Camera View"
|
||||
msgid "Top"
|
||||
msgstr "Superior"
|
||||
|
||||
# AI Translated
|
||||
#. TRN To be shown in the main menu View->Bottom
|
||||
msgctxt "Camera View"
|
||||
msgid "Bottom"
|
||||
msgstr "Inferior"
|
||||
|
||||
msgctxt "Camera View"
|
||||
msgid "Left"
|
||||
msgstr "Izquierda"
|
||||
@@ -5759,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)."
|
||||
|
||||
@@ -5940,6 +5992,10 @@ msgstr "Multi-dispositivo"
|
||||
msgid "Project"
|
||||
msgstr "Proyecto"
|
||||
|
||||
# AI Translated
|
||||
msgid "Device (Web)"
|
||||
msgstr "Dispositivo (Web)"
|
||||
|
||||
msgid "Yes"
|
||||
msgstr "Sí"
|
||||
|
||||
@@ -6020,19 +6076,14 @@ msgstr "Vista por Defecto"
|
||||
msgid "Top View"
|
||||
msgstr "Vista superior"
|
||||
|
||||
#. TRN To be shown in the main menu View->Bottom
|
||||
msgid "Bottom"
|
||||
msgstr "Inferior"
|
||||
|
||||
msgid "Bottom View"
|
||||
msgstr "Vista inferior"
|
||||
|
||||
msgid "Front"
|
||||
msgstr "Frontal"
|
||||
|
||||
msgid "Front View"
|
||||
msgstr "Vista frontal"
|
||||
|
||||
# AI Translated
|
||||
msgctxt "Camera View"
|
||||
msgid "Rear"
|
||||
msgstr "Posterior"
|
||||
|
||||
@@ -7982,21 +8033,21 @@ msgstr "No se seleccionó el directorio para el reemplazo"
|
||||
msgid "Replaced with 3D files from directory:\n"
|
||||
msgstr "Reemplazado con archivos 3D desde el directorio:\n"
|
||||
|
||||
#, boost-format
|
||||
msgid "✖ Skipped %1%: same file.\n"
|
||||
msgstr "✖ Omitido %1%: mismo archivo.\n"
|
||||
#, c-format, boost-format
|
||||
msgid "✖ Skipped %s: same file.\n"
|
||||
msgstr "✖ Omitido %s: mismo archivo.\n"
|
||||
|
||||
#, boost-format
|
||||
msgid "✖ Skipped %1%: file does not exist.\n"
|
||||
msgstr "✖ Omitido %1%: el archivo no existe.\n"
|
||||
#, c-format, boost-format
|
||||
msgid "✖ Skipped %s: file does not exist.\n"
|
||||
msgstr "✖ Omitido %s: el archivo no existe.\n"
|
||||
|
||||
#, boost-format
|
||||
msgid "✖ Skipped %1%: failed to replace.\n"
|
||||
msgstr "✖ Omitido %1%: fallo al reemplazar.\n"
|
||||
#, c-format, boost-format
|
||||
msgid "✖ Skipped %s: failed to replace.\n"
|
||||
msgstr "✖ Omitido %s: fallo al reemplazar.\n"
|
||||
|
||||
#, boost-format
|
||||
msgid "✔ Replaced %1%.\n"
|
||||
msgstr "✔ Reemplazado %1%.\n"
|
||||
#, c-format, boost-format
|
||||
msgid "✔ Replaced %s.\n"
|
||||
msgstr "✔ Reemplazado %s.\n"
|
||||
|
||||
msgid "Replaced volumes"
|
||||
msgstr "Volúmenes reemplazados"
|
||||
@@ -8710,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"
|
||||
|
||||
@@ -8920,6 +8983,21 @@ msgstr "Atenuar las capas inferiores"
|
||||
msgid "When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness."
|
||||
msgstr "Al desplazar el control deslizante de capas en la vista previa laminada, oscurece las capas inferiores a la actual para que solo la capa visualizada se muestre a pleno brillo."
|
||||
|
||||
# AI Translated
|
||||
msgid "Dimmed layer brightness"
|
||||
msgstr "Brillo de las capas atenuadas"
|
||||
|
||||
msgid "%"
|
||||
msgstr "%"
|
||||
|
||||
# AI Translated
|
||||
msgid ""
|
||||
"How brightly the dimmed layers are rendered when \"Dim lower layers\" is enabled.\n"
|
||||
"99% is barely darkened, 0% renders them black. Capped at 99% because 100% would be the same as disabling the option."
|
||||
msgstr ""
|
||||
"Con qué brillo se muestran las capas atenuadas cuando \"Atenuar las capas inferiores\" está activado.\n"
|
||||
"99% apenas se oscurece y 0% las muestra en negro. Está limitado al 99% porque el 100% equivaldría a desactivar la opción."
|
||||
|
||||
msgid "Login region"
|
||||
msgstr "Región de inicio de sesión"
|
||||
|
||||
@@ -9044,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"
|
||||
|
||||
@@ -9303,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."
|
||||
|
||||
@@ -10001,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."
|
||||
|
||||
@@ -10208,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"
|
||||
|
||||
@@ -10334,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%"
|
||||
@@ -10459,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"
|
||||
@@ -11779,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."
|
||||
|
||||
@@ -12086,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."
|
||||
|
||||
@@ -12764,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."
|
||||
|
||||
@@ -12846,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"
|
||||
|
||||
@@ -12870,12 +12972,37 @@ msgstr "Por objeto"
|
||||
msgid "Intra-layer order"
|
||||
msgstr "Orden dentro de la capa"
|
||||
|
||||
msgid "Print order within a single layer."
|
||||
msgstr "Orden de impresión dentro de cada capa."
|
||||
# AI Translated
|
||||
msgid ""
|
||||
"Order in which object instances are visited within a single layer, which controls how much travel is spent moving between them.\n"
|
||||
"\n"
|
||||
"Default: nearest-neighbor chaining, refined with 2-opt and crossing removal. A good general choice.\n"
|
||||
"As object list: instances are printed in the same order as the object list, without any path optimization. Use it when you need a predictable, manually controlled order.\n"
|
||||
"Best of all (shortest path): every strategy is evaluated and the shortest one is used. The object instance order is decided once for the whole print, while the ordering of individual islands is decided per layer, so different layers may end up using different strategies. Slightly slower to slice.\n"
|
||||
"Snake: serpentine row-by-row traversal, refined with 2-opt. Well suited to regular grids of many small parts.\n"
|
||||
"\n"
|
||||
"With multiple filaments or tools in the same layer, minimizing tool changes takes priority: objects are grouped by filament first and this setting only orders the instances within each filament group, so the overall sequence may not look like the shortest path across the plate."
|
||||
msgstr ""
|
||||
"Orden en el que se recorren las instancias de objeto dentro de una misma capa, lo que determina cuánto desplazamiento se emplea para moverse entre ellas.\n"
|
||||
"\n"
|
||||
"Por defecto: encadenado por vecino más cercano, refinado con 2-opt y eliminación de cruces. Una buena opción general.\n"
|
||||
"Como lista de objetos: las instancias se imprimen en el mismo orden que la lista de objetos, sin ninguna optimización de trayectoria. Úselo cuando necesite un orden predecible y controlado manualmente.\n"
|
||||
"La mejor de todas (trayectoria más corta): se evalúan todas las estrategias y se utiliza la más corta. El orden de las instancias de objeto se decide una sola vez para toda la impresión, mientras que el orden de las islas individuales se decide capa por capa, por lo que distintas capas pueden acabar usando estrategias diferentes. El laminado es algo más lento.\n"
|
||||
"Serpentina: recorrido serpenteante fila por fila, refinado con 2-opt. Muy adecuado para rejillas regulares de muchas piezas pequeñas.\n"
|
||||
"\n"
|
||||
"Con varios filamentos o herramientas en la misma capa, minimizar los cambios de herramienta tiene prioridad: los objetos se agrupan primero por filamento y este ajuste solo ordena las instancias dentro de cada grupo de filamento, por lo que la secuencia global puede no parecer la trayectoria más corta a lo largo de la cama."
|
||||
|
||||
msgid "As object list"
|
||||
msgstr "Como lista de objetos"
|
||||
|
||||
# AI Translated
|
||||
msgid "Best of all (shortest path)"
|
||||
msgstr "La mejor de todas (trayectoria más corta)"
|
||||
|
||||
# AI Translated
|
||||
msgid "Snake"
|
||||
msgstr "Serpentina"
|
||||
|
||||
msgid "Slow printing down for better layer cooling"
|
||||
msgstr "Reducir la velocidad de impresión para mejorar la refrigeración de las capas"
|
||||
|
||||
@@ -13956,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."
|
||||
|
||||
@@ -14489,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"
|
||||
|
||||
@@ -15490,7 +15633,7 @@ msgstr "La longitud de la retracción rápida antes de la purga, en relación co
|
||||
msgid "Retract amount after wipe"
|
||||
msgstr "Cantidad de retracción después de la limpieza"
|
||||
|
||||
#, c-format
|
||||
#, no-c-format, no-boost-format
|
||||
msgid ""
|
||||
"The length of fast retraction after wipe, relative to retraction length.\n"
|
||||
"The value will be clamped by 100% minus the retract amount before the wipe value."
|
||||
@@ -15528,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"
|
||||
|
||||
@@ -15621,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."
|
||||
|
||||
@@ -16027,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)"
|
||||
|
||||
@@ -18111,6 +18274,20 @@ msgstr ""
|
||||
"Hay varias direcciones IP resueltas del nombre del host %1%.\n"
|
||||
"Por favor, seleccione la que debe usarse."
|
||||
|
||||
# AI Translated
|
||||
msgid "Auto-scale for nozzle"
|
||||
msgstr "Escalar automáticamente para la boquilla"
|
||||
|
||||
# AI Translated
|
||||
msgid ""
|
||||
"This model is designed around a 0.4 mm nozzle with a 0.2 mm layer height. \n"
|
||||
"When the scaling option is enabled (recommended), it dynamically resizes to match your current nozzle diameter and an appropriate layer height, making the test both accurate and easy to read.\n"
|
||||
"Turn scaling off only if you wish to print the reference model exactly as-is."
|
||||
msgstr ""
|
||||
"Este modelo está diseñado para una boquilla de 0,4 mm con una altura de la capa de 0,2 mm. \n"
|
||||
"Cuando la opción de escalado está activada (recomendado), el modelo se redimensiona dinámicamente para adaptarse al diámetro de boquilla actual y a una altura de capa adecuada, lo que hace que la prueba sea precisa y fácil de leer.\n"
|
||||
"Desactive el escalado solo si desea imprimir el modelo de referencia exactamente tal cual."
|
||||
|
||||
msgid "PA Calibration"
|
||||
msgstr "Calibración PA"
|
||||
|
||||
@@ -18247,6 +18424,14 @@ msgstr "Velocidad inicial: "
|
||||
msgid "End speed: "
|
||||
msgstr "Velocidad final: "
|
||||
|
||||
# AI Translated
|
||||
msgid "Auto-adjust to max volumetric speed"
|
||||
msgstr "Ajustar automáticamente a la velocidad volumétrica máxima"
|
||||
|
||||
# AI Translated
|
||||
msgid "If the end speed would exceed the filament's maximum volumetric speed, automatically lower the layer height (keeping standard values and staying within the machine's limits) to reach it. If even the minimum layer height is not enough, lower the end speed instead."
|
||||
msgstr "Si la velocidad final superara la velocidad volumétrica máxima del filamento, se reduce automáticamente la altura de la capa (manteniendo valores estándar y dentro de los límites de la máquina) para alcanzarla. Si ni siquiera la altura de capa mínima es suficiente, se reduce la velocidad final."
|
||||
|
||||
msgid ""
|
||||
"Please input valid values:\n"
|
||||
"start > 10\n"
|
||||
@@ -18258,6 +18443,57 @@ msgstr ""
|
||||
"incremento >=0\n"
|
||||
"final > inicio + paso"
|
||||
|
||||
# AI Translated
|
||||
#, c-format, boost-format
|
||||
msgid ""
|
||||
"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s), which limits the outer wall to about %.0f mm/s at this line width and layer height.\n"
|
||||
" Speeds above this will be clamped, so the upper blocks of the tower will not print at the requested speed.\n"
|
||||
"\n"
|
||||
"%s"
|
||||
msgstr ""
|
||||
"La velocidad final (%.0f mm/s) supera la velocidad volumétrica máxima del filamento (%.1f mm³/s), lo que limita el perímetro externo a unos %.0f mm/s con este ancho de línea y esta altura de capa.\n"
|
||||
" Las velocidades superiores se recortarán, por lo que los bloques superiores de la torre no se imprimirán a la velocidad solicitada.\n"
|
||||
"\n"
|
||||
"%s"
|
||||
|
||||
# AI Translated
|
||||
#, c-format, boost-format
|
||||
msgid ""
|
||||
"The end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s) at the default layer height (%.2f mm).\n"
|
||||
"\n"
|
||||
"The layer height has been reduced to %.2f mm (a value used by this printer's profiles) so the tower can reach the requested speed."
|
||||
msgstr ""
|
||||
"La velocidad final (%.0f mm/s) supera la velocidad volumétrica máxima del filamento (%.1f mm³/s) con la altura de capa predeterminada (%.2f mm).\n"
|
||||
"\n"
|
||||
"La altura de la capa se ha reducido a %.2f mm (un valor usado por los perfiles de esta impresora) para que la torre pueda alcanzar la velocidad solicitada."
|
||||
|
||||
# AI Translated
|
||||
#, c-format, boost-format
|
||||
msgid ""
|
||||
"Even at the smallest layer height used by this printer's profiles (%.2f mm) the end speed (%.0f mm/s) exceeds the filament's maximum volumetric speed (%.1f mm³/s).\n"
|
||||
"\n"
|
||||
"The layer height will be set to %.2f mm and the end speed lowered to %.0f mm/s.\n"
|
||||
"\n"
|
||||
"Continue?"
|
||||
msgstr ""
|
||||
"Incluso con la altura de capa más pequeña usada por los perfiles de esta impresora (%.2f mm), la velocidad final (%.0f mm/s) supera la velocidad volumétrica máxima del filamento (%.1f mm³/s).\n"
|
||||
"\n"
|
||||
"La altura de la capa se establecerá en %.2f mm y la velocidad final se reducirá a %.0f mm/s.\n"
|
||||
"\n"
|
||||
"¿Continuar?"
|
||||
|
||||
# AI Translated
|
||||
msgid "Continue anyway?"
|
||||
msgstr "¿Continuar de todos modos?"
|
||||
|
||||
# AI Translated
|
||||
msgid "Enable \"Auto-adjust\" to fix this automatically, or continue anyway?"
|
||||
msgstr "¿Activar \"Ajuste automático\" para corregir esto automáticamente o continuar de todos modos?"
|
||||
|
||||
# AI Translated
|
||||
msgid "Enable \"Auto-scale for nozzle\" and \"Auto-adjust\" to fix this automatically, or continue anyway?"
|
||||
msgstr "¿Activar \"Escalar automáticamente para la boquilla\" y \"Ajuste automático\" para corregir esto automáticamente o continuar de todos modos?"
|
||||
|
||||
msgid "Start retraction length: "
|
||||
msgstr "Longitud de retracción inicial: "
|
||||
|
||||
@@ -19153,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"
|
||||
|
||||
@@ -19997,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"
|
||||
|
||||
@@ -20733,6 +20963,34 @@ 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."
|
||||
|
||||
#~ msgid "Bottom"
|
||||
#~ msgstr "Inferior"
|
||||
|
||||
#~ msgid "Front"
|
||||
#~ msgstr "Frontal"
|
||||
|
||||
#~ msgid "Rear"
|
||||
#~ msgstr "Posterior"
|
||||
|
||||
#~ msgid "Enter"
|
||||
#~ msgstr "Enter"
|
||||
|
||||
@@ -20817,9 +21075,6 @@ msgstr ""
|
||||
#~ msgid "°C"
|
||||
#~ msgstr "°C"
|
||||
|
||||
#~ msgid "%"
|
||||
#~ msgstr "%"
|
||||
|
||||
#~ msgid "Anisotropic surfaces"
|
||||
#~ msgstr "Superficies anisótropas"
|
||||
|
||||
|
||||
@@ -193,7 +193,6 @@ src/slic3r/GUI/ObjColorDialog.cpp
|
||||
src/slic3r/GUI/SyncAmsInfoDialog.cpp
|
||||
src/slic3r/GUI/WipeTowerDialog.cpp
|
||||
src/slic3r/GUI/wxExtensions.cpp
|
||||
src/slic3r/GUI/wxMediaCtrl2.cpp
|
||||
src/slic3r/GUI/WebUserLoginDialog.cpp
|
||||
src/slic3r/GUI/WebGuideDialog.cpp
|
||||
src/slic3r/GUI/KBShortcutsDialog.hpp
|
||||
|
||||
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 579 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><circle cx="7.5" cy="7.5" r="7" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="7.5" y1="4" x2="7.5" y2="11" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/><line x1="4" y1="7.5" x2="11" y2="7.5" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 431 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><circle cx="7.5" cy="7.5" r="7" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="4" y1="7.5" x2="11" y2="7.5" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 315 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><rect x="5.5" y="5.5" width="4" height="4" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/><path d="M7.5 0.5v4M7.5 10.5v4M0.5 7.5h4M10.5 7.5h4M5.5 2.5l2-2 2 2M5.5 12.5l2 2 2-2M2.5 5.5l-2 2 2 2M12.5 5.5l2 2-2 2" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 407 B |
@@ -0,0 +1,330 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="40"
|
||||
height="40"
|
||||
viewBox="0 0 40 40"
|
||||
version="1.1"
|
||||
id="svg17"
|
||||
sodipodi:docname="texture_displacement_group.svg"
|
||||
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
|
||||
xml:space="preserve"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs17"><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect31"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 | F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect30"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.2615305,0,1 @ F,0,0,1,0,1.2615305,0,1 @ F,0,1,1,0,1.2615305,0,1 @ F,0,1,1,0,1.2615305,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect29"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,1.015625,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect27"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,1.059034,0,1 @ F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,0,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect25"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,1.059034,0,1 @ F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,0,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect24"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,1.015625,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect23"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,1,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect21"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect19"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect17"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect15"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><linearGradient
|
||||
id="swatch7"
|
||||
inkscape:swatch="solid"><stop
|
||||
style="stop-color:#77eaa3;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop7" /></linearGradient><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect3"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0.49883385,0,1 @ F,0,0,1,0,0.48672135,0,1 @ F,0,0,1,0,0.5261776,0,1 @ F,0,0,1,0,0.50001454,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect2"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect31-9"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 | F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect31-9-1"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 | F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /></defs><sodipodi:namedview
|
||||
id="namedview17"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="32"
|
||||
inkscape:cx="25.28125"
|
||||
inkscape:cy="18.359375"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2126"
|
||||
inkscape:window-x="-11"
|
||||
inkscape:window-y="-11"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg17" /><path
|
||||
d="m 33.973006,35.500013 h -0.999987 a 0.500013,0.500013 0 0 1 0,-1.000026 h 0.999987 A 0.49999998,0.49999998 0 0 0 34.473,33.999994 v -5.000013 a 0.5000126,0.5000126 0 0 1 1.000025,0 v 5.000013 a 1.5,1.5 0 0 1 -1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6" /><path
|
||||
d="m 35.473026,33.999994 v -0.999987 a 0.500013,0.500013 0 0 0 -1.000026,0 v 0.999987 a 0.49999998,0.49999998 0 0 1 -0.499993,0.499994 h -5.000013 a 0.5000126,0.5000126 0 0 0 0,1.000025 h 5.000013 a 1.5,1.5 0 0 0 1.500019,-1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7" /><path
|
||||
d="m 5.9730079,35.500013 h 0.999987 a 0.500013,0.500013 0 0 0 0,-1.000026 h -0.999987 a 0.49999998,0.49999998 0 0 1 -0.499994,-0.499993 v -5.000013 a 0.5000126,0.5000126 0 0 0 -1.000025,0 v 5.000013 a 1.5,1.5 0 0 0 1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3" /><path
|
||||
d="m 4.4729879,33.999994 v -0.999987 a 0.500013,0.500013 0 0 1 1.000026,0 v 0.999987 a 0.49999998,0.49999998 0 0 0 0.499993,0.499994 H 10.97302 a 0.5000126,0.5000126 0 0 1 0,1.000025 H 5.9730069 a 1.5,1.5 0 0 1 -1.500019,-1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5" /><path
|
||||
d="m 5.9730079,4.499987 h 0.999987 a 0.50001302,0.50001302 0 0 1 0,1.000026 h -0.999987 a 0.49999998,0.49999998 0 0 0 -0.499994,0.499993 v 5.000013 a 0.5000126,0.5000126 0 0 1 -1.0000251,0 V 6.000006 A 1.5,1.5 0 0 1 5.9730079,4.499987 Z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3-9" /><path
|
||||
d="m 4.4729878,6.000006 v 0.999987 a 0.50001302,0.50001302 0 0 0 1.0000261,0 V 6.000006 A 0.49999998,0.49999998 0 0 1 5.9730068,5.500012 H 10.97302 a 0.5000126,0.5000126 0 0 0 0,-1.000025 H 5.9730068 a 1.5,1.5 0 0 0 -1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5-8" /><path
|
||||
d="m 33.973006,4.499986 h -0.999987 a 0.50001302,0.50001302 0 0 0 0,1.000026 h 0.999987 A 0.49999998,0.49999998 0 0 1 34.473,6.000005 v 5.000013 a 0.5000126,0.5000126 0 0 0 1.000025,0 V 6.000005 A 1.5,1.5 0 0 0 33.973006,4.499986 Z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3-9-8" /><path
|
||||
d="m 35.473026,6.000005 v 0.999987 a 0.50001305,0.50001305 0 0 1 -1.000026,0 V 6.000005 A 0.49999998,0.49999998 0 0 0 33.973007,5.500011 h -5.000013 a 0.5000126,0.5000126 0 0 1 0,-1.000025 h 5.000013 a 1.5,1.5 0 0 1 1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5-8-2" /><g
|
||||
id="g5"><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-3-9"
|
||||
id="use4" /><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-7-5-8"
|
||||
id="use5" /></g><g
|
||||
id="g31"
|
||||
transform="translate(-1.2926181,-1.328125)"><path
|
||||
d="m 11.472656,12.726388 v 6.047224 A 1.2263883,1.2263883 45 0 0 12.699044,20 h 6.074568 A 1.2263883,1.2263883 135 0 0 20,18.773612 V 12.726388 A 1.2263883,1.2263883 45 0 0 18.773612,11.5 h -6.074568 a 1.2263883,1.2263883 135 0 0 -1.226388,1.226388 z m 1.730947,-0.0096 h 5.065451 a 0.47508735,0.47508735 45 0 1 0.475087,0.475087 v 5.303732 a 0.47508735,0.47508735 135 0 1 -0.475087,0.475087 h -5.065451 a 0.47508735,0.47508735 45 0 1 -0.475087,-0.475087 l 0,-5.303732 a 0.47508735,0.47508735 135 0 1 0.475087,-0.475087 z"
|
||||
style="fill:#009688;stroke-width:0.1;paint-order:stroke fill markers"
|
||||
id="path30"
|
||||
inkscape:path-effect="#path-effect31"
|
||||
inkscape:original-d="M 11.472656,11.5 V 20 H 20 v -8.5 z m 1.25586,1.216797 h 6.015625 v 6.253906 h -6.015625 z" /><path
|
||||
d="m 11.472656,12.726388 v 6.047224 A 1.2263883,1.2263883 45 0 0 12.699044,20 h 6.074568 A 1.2263883,1.2263883 135 0 0 20,18.773612 V 12.726388 A 1.2263883,1.2263883 45 0 0 18.773612,11.5 h -6.074568 a 1.2263883,1.2263883 135 0 0 -1.226388,1.226388 z m 1.730947,-0.0096 h 5.065451 a 0.47508735,0.47508735 45 0 1 0.475087,0.475087 v 5.303732 a 0.47508735,0.47508735 135 0 1 -0.475087,0.475087 h -5.065451 a 0.47508735,0.47508735 45 0 1 -0.475087,-0.475087 l 0,-5.303732 a 0.47508735,0.47508735 135 0 1 0.475087,-0.475087 z"
|
||||
style="fill:#009688;stroke-width:0.1;paint-order:stroke fill markers"
|
||||
id="path30-4"
|
||||
inkscape:path-effect="#path-effect31-9"
|
||||
inkscape:original-d="M 11.472656,11.5 V 20 H 20 v -8.5 z m 1.25586,1.216797 h 6.015625 v 6.253906 h -6.015625 z"
|
||||
transform="translate(11.058594)" /><path
|
||||
d="m 11.472656,12.726388 v 6.047224 A 1.2263883,1.2263883 45 0 0 12.699044,20 h 6.074568 A 1.2263883,1.2263883 135 0 0 20,18.773612 V 12.726388 A 1.2263883,1.2263883 45 0 0 18.773612,11.5 h -6.074568 a 1.2263883,1.2263883 135 0 0 -1.226388,1.226388 z m 1.730947,-0.0096 h 5.065451 a 0.47508735,0.47508735 45 0 1 0.475087,0.475087 v 5.303732 a 0.47508735,0.47508735 135 0 1 -0.475087,0.475087 h -5.065451 a 0.47508735,0.47508735 45 0 1 -0.475087,-0.475087 l 0,-5.303732 a 0.47508735,0.47508735 135 0 1 0.475087,-0.475087 z"
|
||||
style="fill:#009688;stroke-width:0.1;paint-order:stroke fill markers"
|
||||
id="path30-4-3"
|
||||
inkscape:path-effect="#path-effect31-9-1"
|
||||
inkscape:original-d="M 11.472656,11.5 V 20 H 20 v -8.5 z m 1.25586,1.216797 h 6.015625 v 6.253906 h -6.015625 z"
|
||||
transform="translate(0,11.15625)" /></g></svg>
|
||||
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="12.5 0.5 15.5 3.5 10 9 7 6" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><path d="M6.5 7C4.7 6.8 3.2 8 2.9 9.9c-.2 1.3-.8 2.2-2.4 3 2.8 1.5 6.6 1 7.5-1.6.5-1.5.3-3.1-1.5-4.3Z" style="fill:#009688"/></svg>
|
||||
|
After Width: | Height: | Size: 337 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><rect x="0.5" y="0.5" width="7" height="7" style="fill:#009688"/><rect x="7.5" y="7.5" width="7" height="7" style="fill:#009688"/><rect x="0.5" y="0.5" width="14" height="14" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="7.5" y1="0.5" x2="7.5" y2="14.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="0.5" y1="7.5" x2="14.5" y2="7.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 582 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M7.5 7.5 L14.5 7.5 L11 13.5 Z" style="fill:#009688"/><path d="M7.5 7.5 L11 13.5 L4 13.5 Z" style="fill:#009688"/><path d="M7.5 7.5 L4 13.5 L0.5 7.5 Z" style="fill:#009688"/><polygon points="14.5 7.5 11 13.5 4 13.5 0.5 7.5 4 1.5 11 1.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="7.5" y1="7.5" x2="14.5" y2="7.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="7.5" y1="7.5" x2="11" y2="13.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="7.5" y1="7.5" x2="4" y2="13.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="7.5" y1="7.5" x2="0.5" y2="7.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="7.5" y1="7.5" x2="4" y2="1.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="7.5" y1="7.5" x2="11" y2="1.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><line x1="2.5" y1="2.5" x2="12.5" y2="12.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="12.5" y1="2.5" x2="2.5" y2="12.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 332 B |
@@ -0,0 +1,359 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="40"
|
||||
height="40"
|
||||
viewBox="0 0 40 40"
|
||||
version="1.1"
|
||||
id="svg17"
|
||||
sodipodi:docname="texture_displacement_cut.svg"
|
||||
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
|
||||
xml:space="preserve"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs17"><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect34"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0.965625,0,1 @ F,0,0,1,0,0.965625,0,1 @ F,0,0,1,0,0.965625,0,1 @ F,0,0,1,0,0.965625,0,1 | F,0,0,1,0,0.3257813,0,1 @ F,0,1,1,0,0.3257813,0,1 @ F,0,1,1,0,0.3257813,0,1 @ F,0,1,1,0,0.3257813,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect33"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect31"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 | F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect30"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.2615305,0,1 @ F,0,0,1,0,1.2615305,0,1 @ F,0,1,1,0,1.2615305,0,1 @ F,0,1,1,0,1.2615305,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect29"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,1.015625,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect27"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,1.059034,0,1 @ F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,0,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect25"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,1.059034,0,1 @ F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,0,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect24"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,1.015625,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect23"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,1,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect21"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect19"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect17"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect15"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><linearGradient
|
||||
id="swatch7"
|
||||
inkscape:swatch="solid"><stop
|
||||
style="stop-color:#77eaa3;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop7" /></linearGradient><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect3"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0.49883385,0,1 @ F,0,0,1,0,0.48672135,0,1 @ F,0,0,1,0,0.5261776,0,1 @ F,0,0,1,0,0.50001454,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect2"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect31-9"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 | F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect31-9-1"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 | F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /></defs><sodipodi:namedview
|
||||
id="namedview17"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="32"
|
||||
inkscape:cx="15.375"
|
||||
inkscape:cy="16.140625"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2126"
|
||||
inkscape:window-x="-11"
|
||||
inkscape:window-y="-11"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg17" /><path
|
||||
d="m 33.973006,35.500013 h -0.999987 a 0.500013,0.500013 0 0 1 0,-1.000026 h 0.999987 A 0.49999998,0.49999998 0 0 0 34.473,33.999994 v -5.000013 a 0.5000126,0.5000126 0 0 1 1.000025,0 v 5.000013 a 1.5,1.5 0 0 1 -1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6" /><path
|
||||
d="m 35.473026,33.999994 v -0.999987 a 0.500013,0.500013 0 0 0 -1.000026,0 v 0.999987 a 0.49999998,0.49999998 0 0 1 -0.499993,0.499994 h -5.000013 a 0.5000126,0.5000126 0 0 0 0,1.000025 h 5.000013 a 1.5,1.5 0 0 0 1.500019,-1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7" /><path
|
||||
d="m 5.9730079,35.500013 h 0.999987 a 0.500013,0.500013 0 0 0 0,-1.000026 h -0.999987 a 0.49999998,0.49999998 0 0 1 -0.499994,-0.499993 v -5.000013 a 0.5000126,0.5000126 0 0 0 -1.000025,0 v 5.000013 a 1.5,1.5 0 0 0 1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3" /><path
|
||||
d="m 4.4729879,33.999994 v -0.999987 a 0.500013,0.500013 0 0 1 1.000026,0 v 0.999987 a 0.49999998,0.49999998 0 0 0 0.499993,0.499994 H 10.97302 a 0.5000126,0.5000126 0 0 1 0,1.000025 H 5.9730069 a 1.5,1.5 0 0 1 -1.500019,-1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5" /><path
|
||||
d="m 5.9730079,4.499987 h 0.999987 a 0.50001302,0.50001302 0 0 1 0,1.000026 h -0.999987 a 0.49999998,0.49999998 0 0 0 -0.499994,0.499993 v 5.000013 a 0.5000126,0.5000126 0 0 1 -1.0000251,0 V 6.000006 A 1.5,1.5 0 0 1 5.9730079,4.499987 Z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3-9" /><path
|
||||
d="m 4.4729878,6.000006 v 0.999987 a 0.50001302,0.50001302 0 0 0 1.0000261,0 V 6.000006 A 0.49999998,0.49999998 0 0 1 5.9730068,5.500012 H 10.97302 a 0.5000126,0.5000126 0 0 0 0,-1.000025 H 5.9730068 a 1.5,1.5 0 0 0 -1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5-8" /><path
|
||||
d="m 33.973006,4.499986 h -0.999987 a 0.50001302,0.50001302 0 0 0 0,1.000026 h 0.999987 A 0.49999998,0.49999998 0 0 1 34.473,6.000005 v 5.000013 a 0.5000126,0.5000126 0 0 0 1.000025,0 V 6.000005 A 1.5,1.5 0 0 0 33.973006,4.499986 Z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3-9-8" /><path
|
||||
d="m 35.473026,6.000005 v 0.999987 a 0.50001305,0.50001305 0 0 1 -1.000026,0 V 6.000005 A 0.49999998,0.49999998 0 0 0 33.973007,5.500011 h -5.000013 a 0.5000126,0.5000126 0 0 1 0,-1.000025 h 5.000013 a 1.5,1.5 0 0 1 1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5-8-2" /><g
|
||||
id="g5"><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-3-9"
|
||||
id="use4" /><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-7-5-8"
|
||||
id="use5" /></g><path
|
||||
d="m 16.082031,8.7625 v 22.475 a 0.965625,0.965625 45 0 0 0.965625,0.965625 h 5.85 A 0.965625,0.965625 135 0 0 23.863281,31.2375 V 8.7625 A 0.965625,0.965625 45 0 0 22.897656,7.796875 h -5.85 A 0.965625,0.965625 135 0 0 16.082031,8.7625 Z m 1.325781,-0.032031 h 5.184376 a 0.3257813,0.3257813 45 0 1 0.325781,0.3257813 V 30.94375 a 0.3257813,0.3257813 135 0 1 -0.325781,0.325781 H 17.407812 A 0.3257813,0.3257813 45 0 1 17.082031,30.94375 V 9.0562501 a 0.3257813,0.3257813 135 0 1 0.325781,-0.3257813 z"
|
||||
style="fill:#009688;stroke-width:0.1;paint-order:stroke fill markers"
|
||||
id="path33"
|
||||
inkscape:path-effect="#path-effect34"
|
||||
inkscape:original-d="m 16.082031,7.796875 v 24.40625 h 7.78125 V 7.796875 Z m 1,0.9335938 h 5.835938 V 31.269531 h -5.835938 z" /><path
|
||||
style="fill:#009688;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.1;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
id="rect32"
|
||||
width="1.0000267"
|
||||
height="22.719467"
|
||||
x="27.527292"
|
||||
y="-12.430544"
|
||||
transform="rotate(47.337307)"
|
||||
inkscape:path-effect="#path-effect33"
|
||||
sodipodi:type="rect"
|
||||
d="m 28.027306,-12.430544 c 0.277007,0 0.500013,0.223006 0.500013,0.500013 V 9.7889099 c 0,0.2770071 -0.223006,0.5000131 -0.500013,0.5000131 -0.277008,0 -0.500014,-0.223006 -0.500014,-0.5000131 V -11.930531 c 0,-0.277007 0.223006,-0.500013 0.500014,-0.500013 z"
|
||||
ry="0.50001335" /></svg>
|
||||
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><rect x="0.5" y="0.5" width="14" height="14" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="0.5" y1="7.5" x2="14.5" y2="7.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="2.5" y1="0.5" x2="2.5" y2="14.5" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/><line x1="5" y1="0.5" x2="5" y2="14.5" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/><line x1="8.5" y1="0.5" x2="8.5" y2="14.5" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 688 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><circle cx="5.5" cy="3.5" r="1.25" style="fill:#949494"/><circle cx="9.5" cy="3.5" r="1.25" style="fill:#949494"/><circle cx="5.5" cy="7.5" r="1.25" style="fill:#949494"/><circle cx="9.5" cy="7.5" r="1.25" style="fill:#949494"/><circle cx="5.5" cy="11.5" r="1.25" style="fill:#949494"/><circle cx="9.5" cy="11.5" r="1.25" style="fill:#949494"/></svg>
|
||||
|
After Width: | Height: | Size: 434 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="0.5 13.5 7.5 1.5 14.5 13.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><polygon points="4 7.5 11 7.5 7.5 13.5" style="fill:#009688;stroke:#009688;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 311 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><rect x="0.5" y="10.5" width="14" height="4" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><polygon points="9 0.5 4.5 5.5 7.5 5.5 6 9 10.5 4 7.5 4" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 346 B |
@@ -0,0 +1,242 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="40"
|
||||
height="40"
|
||||
viewBox="0 0 40 40"
|
||||
version="1.1"
|
||||
id="svg17"
|
||||
sodipodi:docname="texture_displacement_frame.svg"
|
||||
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
|
||||
xml:space="preserve"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs17"><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect21"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect19"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect17"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect15"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><linearGradient
|
||||
id="swatch7"
|
||||
inkscape:swatch="solid"><stop
|
||||
style="stop-color:#77eaa3;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop7" /></linearGradient><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect3"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0.49883385,0,1 @ F,0,0,1,0,0.48672135,0,1 @ F,0,0,1,0,0.5261776,0,1 @ F,0,0,1,0,0.50001454,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect2"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /></defs><sodipodi:namedview
|
||||
id="namedview17"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="16"
|
||||
inkscape:cx="11.6875"
|
||||
inkscape:cy="6.28125"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2126"
|
||||
inkscape:window-x="-11"
|
||||
inkscape:window-y="-11"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg17" /><path
|
||||
d="m 33.973006,35.500013 h -0.999987 a 0.500013,0.500013 0 0 1 0,-1.000026 h 0.999987 A 0.49999998,0.49999998 0 0 0 34.473,33.999994 v -5.000013 a 0.5000126,0.5000126 0 0 1 1.000025,0 v 5.000013 a 1.5,1.5 0 0 1 -1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6" /><path
|
||||
d="m 35.473026,33.999994 v -0.999987 a 0.500013,0.500013 0 0 0 -1.000026,0 v 0.999987 a 0.49999998,0.49999998 0 0 1 -0.499993,0.499994 h -5.000013 a 0.5000126,0.5000126 0 0 0 0,1.000025 h 5.000013 a 1.5,1.5 0 0 0 1.500019,-1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7" /><path
|
||||
d="m 5.9730079,35.500013 h 0.999987 a 0.500013,0.500013 0 0 0 0,-1.000026 h -0.999987 a 0.49999998,0.49999998 0 0 1 -0.499994,-0.499993 v -5.000013 a 0.5000126,0.5000126 0 0 0 -1.000025,0 v 5.000013 a 1.5,1.5 0 0 0 1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3" /><path
|
||||
d="m 4.4729879,33.999994 v -0.999987 a 0.500013,0.500013 0 0 1 1.000026,0 v 0.999987 a 0.49999998,0.49999998 0 0 0 0.499993,0.499994 H 10.97302 a 0.5000126,0.5000126 0 0 1 0,1.000025 H 5.9730069 a 1.5,1.5 0 0 1 -1.500019,-1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5" /><path
|
||||
d="m 5.9730079,4.499987 h 0.999987 a 0.50001302,0.50001302 0 0 1 0,1.000026 h -0.999987 a 0.49999998,0.49999998 0 0 0 -0.499994,0.499993 v 5.000013 a 0.5000126,0.5000126 0 0 1 -1.0000251,0 V 6.000006 A 1.5,1.5 0 0 1 5.9730079,4.499987 Z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3-9" /><path
|
||||
d="m 4.4729878,6.000006 v 0.999987 a 0.50001302,0.50001302 0 0 0 1.0000261,0 V 6.000006 A 0.49999998,0.49999998 0 0 1 5.9730068,5.500012 H 10.97302 a 0.5000126,0.5000126 0 0 0 0,-1.000025 H 5.9730068 a 1.5,1.5 0 0 0 -1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5-8" /><path
|
||||
d="m 33.973006,4.499986 h -0.999987 a 0.50001302,0.50001302 0 0 0 0,1.000026 h 0.999987 A 0.49999998,0.49999998 0 0 1 34.473,6.000005 v 5.000013 a 0.5000126,0.5000126 0 0 0 1.000025,0 V 6.000005 A 1.5,1.5 0 0 0 33.973006,4.499986 Z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3-9-8" /><path
|
||||
d="m 35.473026,6.000005 v 0.999987 a 0.50001305,0.50001305 0 0 1 -1.000026,0 V 6.000005 A 0.49999998,0.49999998 0 0 0 33.973007,5.500011 h -5.000013 a 0.5000126,0.5000126 0 0 1 0,-1.000025 h 5.000013 a 1.5,1.5 0 0 1 1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5-8-2" /><g
|
||||
id="g5"><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-3-9"
|
||||
id="use4" /><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-7-5-8"
|
||||
id="use5" /></g><g
|
||||
id="g5-0"
|
||||
transform="translate(6.4998844,6.0000382)"
|
||||
style="fill:#ff2323;fill-opacity:1"><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-3-9"
|
||||
id="use4-1"
|
||||
style="fill:#ff2323;fill-opacity:1" /><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-7-5-8"
|
||||
id="use5-2"
|
||||
style="fill:#4e2ca6;fill-opacity:1;fill-rule:nonzero" /></g><g
|
||||
id="g5-0-8"
|
||||
transform="matrix(-1,0,0,1,33.44613,6.0000382)"
|
||||
style="fill:#ff2323;fill-opacity:1"><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-3-9"
|
||||
id="use4-1-3"
|
||||
style="fill:#ff2323;fill-opacity:1" /><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-7-5-8"
|
||||
id="use5-2-5"
|
||||
style="fill:#ff2323;fill-opacity:1" /></g><g
|
||||
id="g5-0-8-2"
|
||||
transform="rotate(180,16.723064,16.999981)"
|
||||
style="fill:#ff2323;fill-opacity:1"><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-3-9"
|
||||
id="use4-1-3-0"
|
||||
style="fill:#ff2323;fill-opacity:1" /><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-7-5-8"
|
||||
id="use5-2-5-1"
|
||||
style="fill:#ff2323;fill-opacity:1" /></g><g
|
||||
id="g5-0-8-2-4"
|
||||
transform="matrix(1,0,0,-1,6.4998854,33.999963)"
|
||||
style="fill:#ff2323;fill-opacity:1"><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-3-9"
|
||||
id="use4-1-3-0-0"
|
||||
style="fill:#ff2323;fill-opacity:1" /><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-7-5-8"
|
||||
id="use5-2-5-1-6"
|
||||
style="fill:#ff2323;fill-opacity:1" /></g><path
|
||||
id="path13"
|
||||
style="fill:#009688;stroke-width:0.1;paint-order:stroke fill markers"
|
||||
d="m 10.972656,11.5 v 4.101562 1.407813 A 0.490625,0.490625 45 0 0 11.463281,17.5 h 0.0094 a 0.4999428,0.4999428 135 0 0 0.499943,-0.499943 V 15.601562 12.000236 A 0.5002363,0.5002363 135 0 1 12.472892,11.5 h 0.241952 0.503906 4.255468 a 0.4984375,0.4984375 135 0 0 0.498438,-0.498437 v -0.0018 A 0.4997516,0.4997516 45 0 0 17.472904,10.5 H 13.21875 12.714844 11.972656 a 1,1 135 0 0 -1,1 z"
|
||||
inkscape:original-d="m 10.972656,10.5 v 1 4.101562 V 17.5 h 1 V 15.601562 11.5 h 0.742188 0.503906 4.753906 v -1 H 13.21875 12.714844 11.972656 Z"
|
||||
inkscape:path-effect="#path-effect15" /><path
|
||||
id="path16"
|
||||
style="fill:#009688;stroke-width:0.1;paint-order:stroke fill markers"
|
||||
d="m 10.972656,11.5 v 4.101562 1.439063 A 0.459375,0.459375 45 0 0 11.432031,17.5 h 0.04066 a 0.499968,0.499968 135 0 0 0.499968,-0.499968 l 0,-1.39847 V 12.000236 A 0.5002363,0.5002363 135 0 1 12.472892,11.5 h 0.241952 0.503906 4.271094 a 0.4828125,0.4828125 135 0 0 0.482812,-0.482812 V 11.00584 A 0.50584,0.50584 45 0 0 17.466816,10.5 H 13.21875 12.714844 11.972656 a 1,1 135 0 0 -1,1 z"
|
||||
inkscape:original-d="m 10.972656,10.5 v 1 4.101562 V 17.5 h 1 V 15.601562 11.5 h 0.742188 0.503906 4.753906 v -1 H 13.21875 12.714844 11.972656 Z"
|
||||
inkscape:path-effect="#path-effect17"
|
||||
transform="matrix(-1,0,0,1,39.939926,2.52e-5)" /><path
|
||||
id="path17"
|
||||
style="fill:#009688;stroke-width:0.1;paint-order:stroke fill markers"
|
||||
d="m 10.972656,11.5 v 4.101562 1.439063 A 0.459375,0.459375 45 0 0 11.432031,17.5 h 0.04066 a 0.499968,0.499968 135 0 0 0.499968,-0.499968 l 0,-1.39847 V 12.000236 A 0.5002363,0.5002363 135 0 1 12.472892,11.5 h 0.241952 0.503906 4.271094 a 0.4828125,0.4828125 135 0 0 0.482812,-0.482812 V 11.00584 A 0.50584,0.50584 45 0 0 17.466816,10.5 H 13.21875 12.714844 11.972656 a 1,1 135 0 0 -1,1 z"
|
||||
inkscape:original-d="m 10.972656,10.5 v 1 4.101562 V 17.5 h 1 V 15.601562 11.5 h 0.742188 0.503906 4.753906 v -1 H 13.21875 12.714844 11.972656 Z"
|
||||
inkscape:path-effect="#path-effect19"
|
||||
transform="rotate(180,19.972885,20.000096)" /><path
|
||||
id="path19"
|
||||
style="fill:#009688;stroke-width:0.1;paint-order:stroke fill markers"
|
||||
d="m 10.972656,11.5 v 4.101562 1.439063 A 0.459375,0.459375 45 0 0 11.432031,17.5 h 0.04066 a 0.499968,0.499968 135 0 0 0.499968,-0.499968 l 0,-1.39847 V 12.000236 A 0.5002363,0.5002363 135 0 1 12.472892,11.5 h 0.241952 0.503906 4.271094 a 0.4828125,0.4828125 135 0 0 0.482812,-0.482812 V 11.00584 A 0.50584,0.50584 45 0 0 17.466816,10.5 H 13.21875 12.714844 11.972656 a 1,1 135 0 0 -1,1 z"
|
||||
inkscape:original-d="m 10.972656,10.5 v 1 4.101562 V 17.5 h 1 V 15.601562 11.5 h 0.742188 0.503906 4.753906 v -1 H 13.21875 12.714844 11.972656 Z"
|
||||
inkscape:path-effect="#path-effect21"
|
||||
transform="matrix(1,0,0,-1,0.0060898,39.99995)" /></svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,387 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="40"
|
||||
height="40"
|
||||
viewBox="0 0 40 40"
|
||||
version="1.1"
|
||||
id="svg17"
|
||||
sodipodi:docname="texture_displacement_join.svg"
|
||||
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
|
||||
xml:space="preserve"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs17"><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect35"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 | F,0,1,1,0,0.24375,0,1 @ F,0,1,1,0,0.24375,0,1 @ F,0,1,1,0,0.24375,0,1 @ F,0,0,1,0,0.24375,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect34"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0.965625,0,1 @ F,0,0,1,0,0.965625,0,1 @ F,0,0,1,0,0.965625,0,1 @ F,0,0,1,0,0.965625,0,1 | F,0,0,1,0,0.3257813,0,1 @ F,0,1,1,0,0.3257813,0,1 @ F,0,1,1,0,0.3257813,0,1 @ F,0,1,1,0,0.3257813,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect33"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect31"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 | F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect30"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.2615305,0,1 @ F,0,0,1,0,1.2615305,0,1 @ F,0,1,1,0,1.2615305,0,1 @ F,0,1,1,0,1.2615305,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect29"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,1.015625,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect27"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,1.059034,0,1 @ F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,0,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect25"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,1.059034,0,1 @ F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,0,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect24"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,1.015625,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect23"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,1,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect21"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect19"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect17"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect15"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><linearGradient
|
||||
id="swatch7"
|
||||
inkscape:swatch="solid"><stop
|
||||
style="stop-color:#77eaa3;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop7" /></linearGradient><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect3"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0.49883385,0,1 @ F,0,0,1,0,0.48672135,0,1 @ F,0,0,1,0,0.5261776,0,1 @ F,0,0,1,0,0.50001454,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect2"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect31-9"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 | F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect31-9-1"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 | F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect35-7"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 | F,0,1,1,0,0.24375,0,1 @ F,0,1,1,0,0.24375,0,1 @ F,0,1,1,0,0.24375,0,1 @ F,0,0,1,0,0.24375,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /></defs><sodipodi:namedview
|
||||
id="namedview17"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="32"
|
||||
inkscape:cx="18.3125"
|
||||
inkscape:cy="22.328125"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2126"
|
||||
inkscape:window-x="-11"
|
||||
inkscape:window-y="-11"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg17" /><path
|
||||
d="m 33.973006,35.500013 h -0.999987 a 0.500013,0.500013 0 0 1 0,-1.000026 h 0.999987 A 0.49999998,0.49999998 0 0 0 34.473,33.999994 v -5.000013 a 0.5000126,0.5000126 0 0 1 1.000025,0 v 5.000013 a 1.5,1.5 0 0 1 -1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6" /><path
|
||||
d="m 35.473026,33.999994 v -0.999987 a 0.500013,0.500013 0 0 0 -1.000026,0 v 0.999987 a 0.49999998,0.49999998 0 0 1 -0.499993,0.499994 h -5.000013 a 0.5000126,0.5000126 0 0 0 0,1.000025 h 5.000013 a 1.5,1.5 0 0 0 1.500019,-1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7" /><path
|
||||
d="m 5.9730079,35.500013 h 0.999987 a 0.500013,0.500013 0 0 0 0,-1.000026 h -0.999987 a 0.49999998,0.49999998 0 0 1 -0.499994,-0.499993 v -5.000013 a 0.5000126,0.5000126 0 0 0 -1.000025,0 v 5.000013 a 1.5,1.5 0 0 0 1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3" /><path
|
||||
d="m 4.4729879,33.999994 v -0.999987 a 0.500013,0.500013 0 0 1 1.000026,0 v 0.999987 a 0.49999998,0.49999998 0 0 0 0.499993,0.499994 H 10.97302 a 0.5000126,0.5000126 0 0 1 0,1.000025 H 5.9730069 a 1.5,1.5 0 0 1 -1.500019,-1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5" /><path
|
||||
d="m 5.9730079,4.499987 h 0.999987 a 0.50001302,0.50001302 0 0 1 0,1.000026 h -0.999987 a 0.49999998,0.49999998 0 0 0 -0.499994,0.499993 v 5.000013 a 0.5000126,0.5000126 0 0 1 -1.0000251,0 V 6.000006 A 1.5,1.5 0 0 1 5.9730079,4.499987 Z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3-9" /><path
|
||||
d="m 4.4729878,6.000006 v 0.999987 a 0.50001302,0.50001302 0 0 0 1.0000261,0 V 6.000006 A 0.49999998,0.49999998 0 0 1 5.9730068,5.500012 H 10.97302 a 0.5000126,0.5000126 0 0 0 0,-1.000025 H 5.9730068 a 1.5,1.5 0 0 0 -1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5-8" /><path
|
||||
d="m 33.973006,4.499986 h -0.999987 a 0.50001302,0.50001302 0 0 0 0,1.000026 h 0.999987 A 0.49999998,0.49999998 0 0 1 34.473,6.000005 v 5.000013 a 0.5000126,0.5000126 0 0 0 1.000025,0 V 6.000005 A 1.5,1.5 0 0 0 33.973006,4.499986 Z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3-9-8" /><path
|
||||
d="m 35.473026,6.000005 v 0.999987 a 0.50001305,0.50001305 0 0 1 -1.000026,0 V 6.000005 A 0.49999998,0.49999998 0 0 0 33.973007,5.500011 h -5.000013 a 0.5000126,0.5000126 0 0 1 0,-1.000025 h 5.000013 a 1.5,1.5 0 0 1 1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5-8-2" /><g
|
||||
id="g5"><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-3-9"
|
||||
id="use4" /><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-7-5-8"
|
||||
id="use5" /></g><path
|
||||
id="rect35"
|
||||
style="fill:#009688;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.1;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="m 11.154297,12.015625 c -0.277007,0 -0.5,0.222993 -0.5,0.5 v 9.050781 c 0,0.0019 -2.2e-5,0.0039 0,0.0059 -2.3e-5,0.002 0,0.0039 0,0.0059 3.45e-4,0.01513 0.0023,0.03016 0.0039,0.04492 0.02282,0.255546 0.234414,0.455078 0.496094,0.455078 h 9.050781 c 0.277007,0 0.5,-0.222993 0.5,-0.5 v -0.002 -9.048828 c 9e-5,-0.0039 0,-0.0078 0,-0.01172 0,-0.277007 -0.222993,-0.5 -0.5,-0.5 z m 0.74375,1 h 7.563281 a 0.24375,0.24375 45 0 1 0.24375,0.24375 v 7.575 a 0.24375,0.24375 135 0 1 -0.24375,0.24375 h -7.563281 a 0.24375,0.24375 45 0 1 -0.24375,-0.24375 v -7.575 a 0.24375,0.24375 135 0 1 0.24375,-0.24375 z"
|
||||
inkscape:path-effect="#path-effect35"
|
||||
inkscape:original-d="m 11.154297,12.015625 c -0.277007,0 -0.5,0.222993 -0.5,0.5 v 9.050781 c 0,0.0019 -2.2e-5,0.0039 0,0.0059 -2.3e-5,0.002 0,0.0039 0,0.0059 3.45e-4,0.01513 0.0023,0.03016 0.0039,0.04492 0.02282,0.255546 0.234414,0.455078 0.496094,0.455078 h 9.050781 c 0.277007,0 0.5,-0.222993 0.5,-0.5 v -0.002 -9.048828 c 9e-5,-0.0039 0,-0.0078 0,-0.01172 0,-0.277007 -0.222993,-0.5 -0.5,-0.5 z m 0.5,1 h 8.050781 v 8.0625 h -8.050781 z"
|
||||
transform="translate(0.294922,2.953125)" /><path
|
||||
id="rect35-3"
|
||||
style="fill:#009688;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.1;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="m 11.154297,12.015625 c -0.277007,0 -0.5,0.222993 -0.5,0.5 v 9.050781 c 0,0.0019 -2.2e-5,0.0039 0,0.0059 -2.3e-5,0.002 0,0.0039 0,0.0059 3.45e-4,0.01513 0.0023,0.03016 0.0039,0.04492 0.02282,0.255546 0.234414,0.455078 0.496094,0.455078 h 9.050781 c 0.277007,0 0.5,-0.222993 0.5,-0.5 v -0.002 -9.048828 c 9e-5,-0.0039 0,-0.0078 0,-0.01172 0,-0.277007 -0.222993,-0.5 -0.5,-0.5 z m 0.74375,1 h 7.563281 a 0.24375,0.24375 45 0 1 0.24375,0.24375 v 7.575 a 0.24375,0.24375 135 0 1 -0.24375,0.24375 h -7.563281 a 0.24375,0.24375 45 0 1 -0.24375,-0.24375 v -7.575 a 0.24375,0.24375 135 0 1 0.24375,-0.24375 z"
|
||||
inkscape:path-effect="#path-effect35-7"
|
||||
inkscape:original-d="m 11.154297,12.015625 c -0.277007,0 -0.5,0.222993 -0.5,0.5 v 9.050781 c 0,0.0019 -2.2e-5,0.0039 0,0.0059 -2.3e-5,0.002 0,0.0039 0,0.0059 3.45e-4,0.01513 0.0023,0.03016 0.0039,0.04492 0.02282,0.255546 0.234414,0.455078 0.496094,0.455078 h 9.050781 c 0.277007,0 0.5,-0.222993 0.5,-0.5 v -0.002 -9.048828 c 9e-5,-0.0039 0,-0.0078 0,-0.01172 0,-0.277007 -0.222993,-0.5 -0.5,-0.5 z m 0.5,1 h 8.050781 v 8.0625 h -8.050781 z"
|
||||
transform="translate(9.345703,2.953125)" /></svg>
|
||||
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><rect x="5.5" y="5.5" width="4" height="4" style="fill:#009688"/><rect x="5.5" y="1.5" width="4" height="4" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><rect x="1.5" y="5.5" width="4" height="4" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><rect x="5.5" y="5.5" width="4" height="4" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><rect x="9.5" y="5.5" width="4" height="4" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><rect x="5.5" y="9.5" width="4" height="4" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 755 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><circle cx="2.5" cy="7.5" r="2" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="4.3" y1="6.5" x2="11.5" y2="1.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="4.3" y1="8.5" x2="11.5" y2="13.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><rect x="11.5" y="1.5" width="3" height="12" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 562 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><line x1="7.5" y1="1.5" x2="7.5" y2="12" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><polyline points="3.5 8.5 7.5 12.5 11.5 8.5" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 330 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><line x1="7.5" y1="3" x2="7.5" y2="13.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><polyline points="3.5 6.5 7.5 2.5 11.5 6.5" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 329 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polyline points="0.5 7.5 0.5 14.5 14.5 14.5 14.5 7.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><path d="M0.5 7.5c1.2-3 2.3-3 3.5 0s2.3 3 3.5 0 2.3-3 3.5 0 2.3 3 3.5 0" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 372 B |
@@ -0,0 +1,260 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="40"
|
||||
height="40"
|
||||
viewBox="0 0 40 40"
|
||||
version="1.1"
|
||||
id="svg17"
|
||||
sodipodi:docname="texture_displacement_snap.svg"
|
||||
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
|
||||
xml:space="preserve"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs17"><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect29"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,1.015625,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect27"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,1.059034,0,1 @ F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,0,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect25"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,1.059034,0,1 @ F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,0,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect24"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,1.015625,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect23"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,1,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect21"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect19"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect17"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect15"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><linearGradient
|
||||
id="swatch7"
|
||||
inkscape:swatch="solid"><stop
|
||||
style="stop-color:#77eaa3;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop7" /></linearGradient><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect3"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0.49883385,0,1 @ F,0,0,1,0,0.48672135,0,1 @ F,0,0,1,0,0.5261776,0,1 @ F,0,0,1,0,0.50001454,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect2"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /></defs><sodipodi:namedview
|
||||
id="namedview17"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="45.254834"
|
||||
inkscape:cx="14.363106"
|
||||
inkscape:cy="12.827359"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2126"
|
||||
inkscape:window-x="-11"
|
||||
inkscape:window-y="-11"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg17" /><path
|
||||
d="m 33.973006,35.500013 h -0.999987 a 0.500013,0.500013 0 0 1 0,-1.000026 h 0.999987 A 0.49999998,0.49999998 0 0 0 34.473,33.999994 v -5.000013 a 0.5000126,0.5000126 0 0 1 1.000025,0 v 5.000013 a 1.5,1.5 0 0 1 -1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6" /><path
|
||||
d="m 35.473026,33.999994 v -0.999987 a 0.500013,0.500013 0 0 0 -1.000026,0 v 0.999987 a 0.49999998,0.49999998 0 0 1 -0.499993,0.499994 h -5.000013 a 0.5000126,0.5000126 0 0 0 0,1.000025 h 5.000013 a 1.5,1.5 0 0 0 1.500019,-1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7" /><path
|
||||
d="m 5.9730079,35.500013 h 0.999987 a 0.500013,0.500013 0 0 0 0,-1.000026 h -0.999987 a 0.49999998,0.49999998 0 0 1 -0.499994,-0.499993 v -5.000013 a 0.5000126,0.5000126 0 0 0 -1.000025,0 v 5.000013 a 1.5,1.5 0 0 0 1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3" /><path
|
||||
d="m 4.4729879,33.999994 v -0.999987 a 0.500013,0.500013 0 0 1 1.000026,0 v 0.999987 a 0.49999998,0.49999998 0 0 0 0.499993,0.499994 H 10.97302 a 0.5000126,0.5000126 0 0 1 0,1.000025 H 5.9730069 a 1.5,1.5 0 0 1 -1.500019,-1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5" /><path
|
||||
d="m 5.9730079,4.499987 h 0.999987 a 0.50001302,0.50001302 0 0 1 0,1.000026 h -0.999987 a 0.49999998,0.49999998 0 0 0 -0.499994,0.499993 v 5.000013 a 0.5000126,0.5000126 0 0 1 -1.0000251,0 V 6.000006 A 1.5,1.5 0 0 1 5.9730079,4.499987 Z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3-9" /><path
|
||||
d="m 4.4729878,6.000006 v 0.999987 a 0.50001302,0.50001302 0 0 0 1.0000261,0 V 6.000006 A 0.49999998,0.49999998 0 0 1 5.9730068,5.500012 H 10.97302 a 0.5000126,0.5000126 0 0 0 0,-1.000025 H 5.9730068 a 1.5,1.5 0 0 0 -1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5-8" /><path
|
||||
d="m 33.973006,4.499986 h -0.999987 a 0.50001302,0.50001302 0 0 0 0,1.000026 h 0.999987 A 0.49999998,0.49999998 0 0 1 34.473,6.000005 v 5.000013 a 0.5000126,0.5000126 0 0 0 1.000025,0 V 6.000005 A 1.5,1.5 0 0 0 33.973006,4.499986 Z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3-9-8" /><path
|
||||
d="m 35.473026,6.000005 v 0.999987 a 0.50001305,0.50001305 0 0 1 -1.000026,0 V 6.000005 A 0.49999998,0.49999998 0 0 0 33.973007,5.500011 h -5.000013 a 0.5000126,0.5000126 0 0 1 0,-1.000025 h 5.000013 a 1.5,1.5 0 0 1 1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5-8-2" /><g
|
||||
id="g5"><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-3-9"
|
||||
id="use4" /><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-7-5-8"
|
||||
id="use5" /></g><path
|
||||
d="M 20.422985,9.2501548 V 29.968905 H 28.78236 A 1.015625,1.015625 135 0 0 29.797985,28.95328 V 9.2501548 A 1.015625,1.015625 45 0 0 28.78236,8.2345298 h -7.34375 a 1.015625,1.015625 135 0 0 -1.015625,1.015625 z m 1.015625,-0.015625 h 7.34375 V 28.968905 h -7.34375 z"
|
||||
style="fill:#009688;stroke-width:0.1;paint-order:stroke fill markers"
|
||||
id="path23"
|
||||
inkscape:path-effect="#path-effect24"
|
||||
inkscape:original-d="M 20.422985,8.2345298 V 29.968905 h 9.375 V 8.2345298 Z m 1.015625,1 h 7.34375 V 28.968905 h -7.34375 z" /><path
|
||||
d="m 11.047985,11.324808 v 19.616307 a 1.059034,1.059034 45 0 0 1.059034,1.059034 h 7.256932 a 1.059034,1.059034 135 0 0 1.059034,-1.059034 V 10.265774 h -8.315966 a 1.059034,1.059034 135 0 0 -1.059034,1.059034 z m 1.015625,-0.05903 h 7.34375 v 19.734375 h -7.34375 z"
|
||||
style="fill:#009688;stroke-width:0.1;paint-order:stroke fill markers"
|
||||
id="path23-8"
|
||||
inkscape:path-effect="#path-effect25"
|
||||
inkscape:original-d="m 11.047985,10.265774 v 21.734375 h 9.375 V 10.265774 Z m 1.015625,1 h 7.34375 v 19.734375 h -7.34375 z" /><path
|
||||
id="use25"
|
||||
style="fill:#009688;stroke-width:0.1;paint-order:stroke fill markers"
|
||||
d="M 21.439453 8.234375 A 1.015625 1.015625 0 0 0 20.423828 9.25 L 20.423828 10.265625 L 12.107422 10.265625 A 1.059034 1.059034 0 0 0 11.048828 11.324219 L 11.048828 30.941406 A 1.059034 1.059034 0 0 0 12.107422 32 L 19.363281 32 A 1.059034 1.059034 0 0 0 20.423828 30.941406 L 20.423828 29.96875 L 28.783203 29.96875 A 1.015625 1.015625 0 0 0 29.798828 28.953125 L 29.798828 9.25 A 1.015625 1.015625 0 0 0 28.783203 8.234375 L 21.439453 8.234375 z M 21.439453 9.234375 L 28.783203 9.234375 L 28.783203 28.96875 L 21.439453 28.96875 L 21.439453 9.234375 z M 12.064453 11.265625 L 19.408203 11.265625 L 19.408203 31 L 12.064453 31 L 12.064453 11.265625 z " /></svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="0.5 14.5 1.5 14.5 5.5 7.5 1.5 0.5 0.5 0.5 0.5 14.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><rect x="7" width="1" height="3" style="fill:#009688"/><rect x="7" y="4" width="1" height="1" style="fill:#009688"/><rect x="7" y="6" width="1" height="3" style="fill:#009688"/><rect x="7" y="10" width="1" height="1" style="fill:#009688"/><rect x="7" y="12" width="1" height="3" style="fill:#009688"/><polygon points="9.5 14.5 10.5 14.5 14.5 7.5 10.5 0.5 9.5 0.5 9.5 14.5" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 686 B |
@@ -0,0 +1,387 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="40"
|
||||
height="40"
|
||||
viewBox="0 0 40 40"
|
||||
version="1.1"
|
||||
id="svg17"
|
||||
sodipodi:docname="texture_displacement_unjoin.svg"
|
||||
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
|
||||
xml:space="preserve"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs17"><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect35"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 | F,0,1,1,0,0.24375,0,1 @ F,0,1,1,0,0.24375,0,1 @ F,0,1,1,0,0.24375,0,1 @ F,0,0,1,0,0.24375,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect34"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0.965625,0,1 @ F,0,0,1,0,0.965625,0,1 @ F,0,0,1,0,0.965625,0,1 @ F,0,0,1,0,0.965625,0,1 | F,0,0,1,0,0.3257813,0,1 @ F,0,1,1,0,0.3257813,0,1 @ F,0,1,1,0,0.3257813,0,1 @ F,0,1,1,0,0.3257813,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect33"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect31"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 | F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect30"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.2615305,0,1 @ F,0,0,1,0,1.2615305,0,1 @ F,0,1,1,0,1.2615305,0,1 @ F,0,1,1,0,1.2615305,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect29"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,1.015625,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect27"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,1.059034,0,1 @ F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,0,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect25"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,1.059034,0,1 @ F,0,1,1,0,1.059034,0,1 @ F,0,0,1,0,0,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect24"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,1.015625,0,1 @ F,0,0,1,0,1.015625,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect23"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,1,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect21"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect19"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect17"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.459375,0,1 @ F,0,0,1,0,0.499968,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.4828125,0,1 @ F,0,0,1,0,0.50584,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect15"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5002363,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><linearGradient
|
||||
id="swatch7"
|
||||
inkscape:swatch="solid"><stop
|
||||
style="stop-color:#77eaa3;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop7" /></linearGradient><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect3"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0.49883385,0,1 @ F,0,0,1,0,0.48672135,0,1 @ F,0,0,1,0,0.5261776,0,1 @ F,0,0,1,0,0.50001454,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect2"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect31-9"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 | F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect31-9-1"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 @ F,0,0,1,0,1.2263883,0,1 | F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1 @ F,0,1,1,0,0.47508735,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /><inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect35-7"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 | F,0,1,1,0,0.24375,0,1 @ F,0,1,1,0,0.24375,0,1 @ F,0,1,1,0,0.24375,0,1 @ F,0,0,1,0,0.24375,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" /></defs><sodipodi:namedview
|
||||
id="namedview17"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="32"
|
||||
inkscape:cx="18.3125"
|
||||
inkscape:cy="22.328125"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2126"
|
||||
inkscape:window-x="-11"
|
||||
inkscape:window-y="-11"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg17" /><path
|
||||
d="m 33.973006,35.500013 h -0.999987 a 0.500013,0.500013 0 0 1 0,-1.000026 h 0.999987 A 0.49999998,0.49999998 0 0 0 34.473,33.999994 v -5.000013 a 0.5000126,0.5000126 0 0 1 1.000025,0 v 5.000013 a 1.5,1.5 0 0 1 -1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6" /><path
|
||||
d="m 35.473026,33.999994 v -0.999987 a 0.500013,0.500013 0 0 0 -1.000026,0 v 0.999987 a 0.49999998,0.49999998 0 0 1 -0.499993,0.499994 h -5.000013 a 0.5000126,0.5000126 0 0 0 0,1.000025 h 5.000013 a 1.5,1.5 0 0 0 1.500019,-1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7" /><path
|
||||
d="m 5.9730079,35.500013 h 0.999987 a 0.500013,0.500013 0 0 0 0,-1.000026 h -0.999987 a 0.49999998,0.49999998 0 0 1 -0.499994,-0.499993 v -5.000013 a 0.5000126,0.5000126 0 0 0 -1.000025,0 v 5.000013 a 1.5,1.5 0 0 0 1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3" /><path
|
||||
d="m 4.4729879,33.999994 v -0.999987 a 0.500013,0.500013 0 0 1 1.000026,0 v 0.999987 a 0.49999998,0.49999998 0 0 0 0.499993,0.499994 H 10.97302 a 0.5000126,0.5000126 0 0 1 0,1.000025 H 5.9730069 a 1.5,1.5 0 0 1 -1.500019,-1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5" /><path
|
||||
d="m 5.9730079,4.499987 h 0.999987 a 0.50001302,0.50001302 0 0 1 0,1.000026 h -0.999987 a 0.49999998,0.49999998 0 0 0 -0.499994,0.499993 v 5.000013 a 0.5000126,0.5000126 0 0 1 -1.0000251,0 V 6.000006 A 1.5,1.5 0 0 1 5.9730079,4.499987 Z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3-9" /><path
|
||||
d="m 4.4729878,6.000006 v 0.999987 a 0.50001302,0.50001302 0 0 0 1.0000261,0 V 6.000006 A 0.49999998,0.49999998 0 0 1 5.9730068,5.500012 H 10.97302 a 0.5000126,0.5000126 0 0 0 0,-1.000025 H 5.9730068 a 1.5,1.5 0 0 0 -1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5-8" /><path
|
||||
d="m 33.973006,4.499986 h -0.999987 a 0.50001302,0.50001302 0 0 0 0,1.000026 h 0.999987 A 0.49999998,0.49999998 0 0 1 34.473,6.000005 v 5.000013 a 0.5000126,0.5000126 0 0 0 1.000025,0 V 6.000005 A 1.5,1.5 0 0 0 33.973006,4.499986 Z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-3-9-8" /><path
|
||||
d="m 35.473026,6.000005 v 0.999987 a 0.50001305,0.50001305 0 0 1 -1.000026,0 V 6.000005 A 0.49999998,0.49999998 0 0 0 33.973007,5.500011 h -5.000013 a 0.5000126,0.5000126 0 0 1 0,-1.000025 h 5.000013 a 1.5,1.5 0 0 1 1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6-7-5-8-2" /><g
|
||||
id="g5"><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-3-9"
|
||||
id="use4" /><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path3-6-7-5-8"
|
||||
id="use5" /></g><path
|
||||
id="rect35"
|
||||
style="fill:#009688;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.1;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="m 11.154297,12.015625 c -0.277007,0 -0.5,0.222993 -0.5,0.5 v 9.050781 c 0,0.0019 -2.2e-5,0.0039 0,0.0059 -2.3e-5,0.002 0,0.0039 0,0.0059 3.45e-4,0.01513 0.0023,0.03016 0.0039,0.04492 0.02282,0.255546 0.234414,0.455078 0.496094,0.455078 h 9.050781 c 0.277007,0 0.5,-0.222993 0.5,-0.5 v -0.002 -9.048828 c 9e-5,-0.0039 0,-0.0078 0,-0.01172 0,-0.277007 -0.222993,-0.5 -0.5,-0.5 z m 0.74375,1 h 7.563281 a 0.24375,0.24375 45 0 1 0.24375,0.24375 v 7.575 a 0.24375,0.24375 135 0 1 -0.24375,0.24375 h -7.563281 a 0.24375,0.24375 45 0 1 -0.24375,-0.24375 v -7.575 a 0.24375,0.24375 135 0 1 0.24375,-0.24375 z"
|
||||
inkscape:path-effect="#path-effect35"
|
||||
inkscape:original-d="m 11.154297,12.015625 c -0.277007,0 -0.5,0.222993 -0.5,0.5 v 9.050781 c 0,0.0019 -2.2e-5,0.0039 0,0.0059 -2.3e-5,0.002 0,0.0039 0,0.0059 3.45e-4,0.01513 0.0023,0.03016 0.0039,0.04492 0.02282,0.255546 0.234414,0.455078 0.496094,0.455078 h 9.050781 c 0.277007,0 0.5,-0.222993 0.5,-0.5 v -0.002 -9.048828 c 9e-5,-0.0039 0,-0.0078 0,-0.01172 0,-0.277007 -0.222993,-0.5 -0.5,-0.5 z m 0.5,1 h 8.050781 v 8.0625 h -8.050781 z"
|
||||
transform="translate(-1.142612,2.9530855)" /><path
|
||||
id="rect35-3"
|
||||
style="fill:#009688;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.1;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="m 11.154297,12.015625 c -0.277007,0 -0.5,0.222993 -0.5,0.5 v 9.050781 c 0,0.0019 -2.2e-5,0.0039 0,0.0059 -2.3e-5,0.002 0,0.0039 0,0.0059 3.45e-4,0.01513 0.0023,0.03016 0.0039,0.04492 0.02282,0.255546 0.234414,0.455078 0.496094,0.455078 h 9.050781 c 0.277007,0 0.5,-0.222993 0.5,-0.5 v -0.002 -9.048828 c 9e-5,-0.0039 0,-0.0078 0,-0.01172 0,-0.277007 -0.222993,-0.5 -0.5,-0.5 z m 0.74375,1 h 7.563281 a 0.24375,0.24375 45 0 1 0.24375,0.24375 v 7.575 a 0.24375,0.24375 135 0 1 -0.24375,0.24375 h -7.563281 a 0.24375,0.24375 45 0 1 -0.24375,-0.24375 v -7.575 a 0.24375,0.24375 135 0 1 0.24375,-0.24375 z"
|
||||
inkscape:path-effect="#path-effect35-7"
|
||||
inkscape:original-d="m 11.154297,12.015625 c -0.277007,0 -0.5,0.222993 -0.5,0.5 v 9.050781 c 0,0.0019 -2.2e-5,0.0039 0,0.0059 -2.3e-5,0.002 0,0.0039 0,0.0059 3.45e-4,0.01513 0.0023,0.03016 0.0039,0.04492 0.02282,0.255546 0.234414,0.455078 0.496094,0.455078 h 9.050781 c 0.277007,0 0.5,-0.222993 0.5,-0.5 v -0.002 -9.048828 c 9e-5,-0.0039 0,-0.0078 0,-0.01172 0,-0.277007 -0.222993,-0.5 -0.5,-0.5 z m 0.5,1 h 8.050781 v 8.0625 h -8.050781 z"
|
||||
transform="translate(10.783203,2.9530855)" /></svg>
|
||||
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><rect x="1" y="5.5" width="4" height="4" fill="none" stroke="#949494" stroke-linecap="round" stroke-linejoin="round"/><rect x="6" y="5.5" width="4" height="4" fill="none" stroke="#009688" stroke-linecap="round" stroke-linejoin="round"/><rect x="11" y="5.5" width="4" height="4" fill="none" stroke="#949494" stroke-linecap="round" stroke-linejoin="round"/><path d="M2 12.5h12" fill="none" stroke="#949494" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1 1.6"/></svg>
|
||||
|
After Width: | Height: | Size: 568 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><rect x="1.5" y="1.5" width="13" height="13" fill="none" stroke="#949494" stroke-linecap="round" stroke-linejoin="round"/><path d="M1.5 10c2-3 3.5-3 5 0s3 3 5 0c1-1.5 2-1.5 3-.5" fill="none" stroke="#009688" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
|
After Width: | Height: | Size: 346 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M4 6.5h6a3.5 3.5 0 0 1 0 7H6" fill="none" stroke="#949494" stroke-linecap="round" stroke-linejoin="round"/><polyline points="6.5 4 4 6.5 6.5 9" fill="none" stroke="#009688" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
|
After Width: | Height: | Size: 320 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><rect x="2.5" y="2.5" width="11" height="11" fill="none" stroke="#949494" stroke-linecap="round" stroke-linejoin="round"/><line x1="1" y1="15" x2="15" y2="1" fill="none" stroke="#009688" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
|
After Width: | Height: | Size: 325 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M1.5 5V1.5H5M11 1.5h3.5V5M14.5 11v3.5H11M5 14.5H1.5V11" fill="none" stroke="#949494" stroke-linecap="round" stroke-linejoin="round"/><rect x="5.5" y="5.5" width="5" height="5" fill="none" stroke="#009688" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
|
After Width: | Height: | Size: 352 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><rect x="1.5" y="4.5" width="6" height="7" fill="none" stroke="#949494" stroke-linecap="round" stroke-linejoin="round"/><rect x="7.5" y="4.5" width="7" height="7" fill="none" stroke="#949494" stroke-linecap="round" stroke-linejoin="round"/><line x1="7.5" y1="4.5" x2="7.5" y2="11.5" stroke="#009688" stroke-width="1.8"/></svg>
|
||||
|
After Width: | Height: | Size: 410 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polyline points="2.5 12.5 6 8 9.5 9.5 13 3.5" fill="none" stroke="#949494" stroke-linecap="round" stroke-linejoin="round"/><circle cx="2.5" cy="12.5" r="1.7" fill="#009688"/><circle cx="13" cy="3.5" r="1.7" fill="#009688"/></svg>
|
||||
|
After Width: | Height: | Size: 314 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="1.5 13.5 7.5 1.5 13.5 13.5" fill="none" stroke="#949494" stroke-linecap="round" stroke-linejoin="round"/><line x1="7.5" y1="1.5" x2="7.5" y2="13.5" stroke="#009688" stroke-width="1.6" stroke-linecap="round" stroke-dasharray="2 1.7"/></svg>
|
||||
|
After Width: | Height: | Size: 340 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="1.5 13.5 3.5 2.5 13.5 1.5 12.5 12.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="3.5" y1="2.5" x2="12.5" y2="12.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="3.5" y1="2.5" x2="13.5" y2="1.5" style="fill:none;stroke:#009688;stroke-width:2;stroke-linecap:round"/></svg>
|
||||
|
After Width: | Height: | Size: 455 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="0.5 1.5 6.5 0.5 7.5 6.5 1.5 7.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><polygon points="9.5 1.5 14.5 2.5 11.5 6.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><polygon points="1.5 9.5 5.5 9 6 14.5 0.5 13.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><polygon points="8.5 8.5 14.5 7.5 13.5 14.5 7.5 13.5" style="fill:#009688;stroke:#009688;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 576 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="1.5 13.5 3.5 2.5 13.5 1.5 12.5 12.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><line x1="3.5" y1="2.5" x2="12.5" y2="12.5" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><circle cx="1.5" cy="13.5" r="1" style="fill:#949494"/><circle cx="12.5" cy="12.5" r="1" style="fill:#949494"/><circle cx="3.5" cy="2.5" r="1" style="fill:#949494"/><circle cx="13.5" cy="1.5" r="1.8" style="fill:#009688"/></svg>
|
||||
|
After Width: | Height: | Size: 564 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M3 2v5.5a5 5 0 0 0 10 0V2" fill="none" stroke="#949494" stroke-linecap="round" stroke-linejoin="round"/><path d="M5.4 2v5.5a2.6 2.6 0 0 0 5.2 0V2" fill="none" stroke="#949494" stroke-linecap="round" stroke-linejoin="round"/><path d="M3 2h2.4M10.6 2H13" stroke="#009688" stroke-width="2" stroke-linecap="round"/></svg>
|
||||
|
After Width: | Height: | Size: 410 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><rect x="0.5" y="4.5" width="5.5" height="7" fill="none" stroke="#949494" stroke-linecap="round" stroke-linejoin="round"/><rect x="10" y="4.5" width="5.5" height="7" fill="none" stroke="#949494" stroke-linecap="round" stroke-linejoin="round"/><line x1="8" y1="3" x2="8" y2="13" stroke="#009688" stroke-dasharray="1.6 1.6"/></svg>
|
||||
|
After Width: | Height: | Size: 413 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><rect x="0.5" y="0.5" width="14" height="14" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><path d="M0.5 7.5h14M7.5 0.5v14M0.5 0.5l14 14M14.5 0.5l-14 14" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||
|
After Width: | Height: | Size: 352 B |
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="40"
|
||||
height="40"
|
||||
viewBox="0 0 40 40"
|
||||
version="1.1"
|
||||
id="svg17"
|
||||
sodipodi:docname="toolbar_big_brush.svg"
|
||||
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs17" />
|
||||
<sodipodi:namedview
|
||||
id="namedview17"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="5.6568543"
|
||||
inkscape:cx="-13.081475"
|
||||
inkscape:cy="98.994949"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2126"
|
||||
inkscape:window-x="-11"
|
||||
inkscape:window-y="-11"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg17" />
|
||||
<path
|
||||
d="m 33.973006,35.500013 h -0.999987 a 0.500013,0.500013 0 0 1 0,-1.000026 h 0.999987 A 0.49999998,0.49999998 0 0 0 34.473,33.999994 v -5.000013 a 0.5000126,0.5000126 0 0 1 1.000025,0 v 5.000013 a 1.5,1.5 0 0 1 -1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6" />
|
||||
<path
|
||||
d="M 19.973012,35.500013 H 5.9730109 a 1.5,1.5 0 0 1 -1.5,-1.500019 V 6.000006 a 1.5,1.5 0 0 1 1.5,-1.500019 H 33.973006 a 1.5,1.5 0 0 1 1.500019,1.500019 v 12.999987 a 0.5000126,0.5000126 0 0 1 -1.000025,0 V 6.000006 A 0.49999998,0.49999998 0 0 0 33.973006,5.500012 H 5.9730109 a 0.49999998,0.49999998 0 0 0 -0.499997,0.499994 v 27.999988 a 0.49999998,0.49999998 0 0 0 0.499997,0.499993 H 19.973012 a 0.500013,0.500013 0 0 1 0,1.000026 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999;fill-opacity:1"
|
||||
id="path4-6" />
|
||||
<path
|
||||
id="path30"
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:0;stroke-opacity:0;paint-order:stroke fill markers"
|
||||
d="M 30.109375 6.9648438 A 1.8710937 1.8710937 0 0 0 28.705078 7.5996094 A 1.8710937 1.8710937 0 0 0 28.591797 7.7421875 L 18.103516 20.615234 A 6.1070809 6.1070809 0 0 0 17.226562 20.552734 A 6.1070809 6.1070809 0 0 0 11.513672 24.503906 A 6.1070809 6.1070809 0 0 0 11.121094 26.658203 A 6.1070809 6.1070809 0 0 0 11.121094 26.757812 A 4.4931102 4.4931102 0 0 1 11.15625 27.3125 A 4.4931102 4.4931102 0 0 1 7.7890625 31.662109 A 4.4931102 4.4931102 0 0 1 7.5839844 31.708984 A 0.55609465 0.55242634 0 0 0 7.2558594 32.212891 A 0.55609465 0.55242634 0 0 0 7.8105469 32.765625 A 0.55609465 0.55242634 0 0 0 7.8125 32.765625 L 7.9570312 32.765625 L 17.224609 32.765625 L 17.226562 32.765625 A 6.1070809 6.1070809 0 0 0 23.333984 26.658203 A 6.1070809 6.1070809 0 0 0 22.792969 24.144531 L 31.666016 9.875 A 1.8710937 1.8710937 0 0 1 31.638672 9.9101562 A 1.8710937 1.8710937 0 0 0 31.699219 9.8242188 A 1.8710937 1.8710937 0 0 0 31.980469 8.8359375 A 1.8710937 1.8710937 0 0 0 31.724609 7.890625 A 1.8710937 1.8710937 0 0 0 30.480469 7.0019531 A 1.8710937 1.8710937 0 0 0 30.109375 6.9648438 z M 28.525391 7.8476562 A 1.8710937 1.8710937 0 0 0 28.472656 7.9335938 A 1.8710937 1.8710937 0 0 1 28.478516 7.9199219 A 1.8710937 1.8710937 0 0 1 28.525391 7.8476562 z M 30.109375 7.9570312 A 0.87817276 0.87817276 0 0 1 30.988281 8.8359375 A 0.87817276 0.87817276 0 0 1 30.90625 9.2050781 A 0.87817276 0.87817276 0 0 1 30.791016 9.390625 L 29.974609 10.703125 L 22.230469 23.15625 A 6.1070809 6.1070809 0 0 0 19.183594 20.873047 L 28.388672 9.5703125 L 29.359375 8.3808594 A 0.87817276 0.87817276 0 0 1 29.511719 8.1933594 A 0.87817276 0.87817276 0 0 1 30.109375 7.9570312 z M 28.457031 7.9628906 A 1.8710937 1.8710937 0 0 0 28.373047 8.1425781 A 1.8710937 1.8710937 0 0 1 28.457031 7.9628906 z M 28.300781 8.359375 A 1.8710937 1.8710937 0 0 0 28.263672 8.5507812 A 1.8710937 1.8710937 0 0 1 28.298828 8.3613281 A 1.8710937 1.8710937 0 0 1 28.300781 8.359375 z M 17.226562 21.65625 A 5.0022264 5.0022264 0 0 1 22.230469 26.658203 A 5.0022264 5.0022264 0 0 1 17.226562 31.662109 L 13.724609 31.662109 L 10.199219 31.662109 A 5.6057596 5.6057596 0 0 0 11.822266 29.501953 A 5.6057596 5.6057596 0 0 0 12.267578 27.3125 A 5.0022264 5.0022264 0 0 1 12.224609 26.658203 A 5.0022264 5.0022264 0 0 1 12.224609 26.621094 A 5.0022264 5.0022264 0 0 1 17.226562 21.65625 z " />
|
||||
<rect
|
||||
style="fill:#b6b6b6;fill-opacity:1;stroke:none;stroke-width:0;stroke-linejoin:miter;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0;paint-order:stroke fill markers"
|
||||
id="rect40"
|
||||
width="15.363631"
|
||||
height="1.000026"
|
||||
x="18.609375"
|
||||
y="34.499989" />
|
||||
<rect
|
||||
style="fill:#b6b6b6;fill-opacity:1;stroke:none;stroke-width:0;stroke-linejoin:miter;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0;paint-order:stroke fill markers"
|
||||
id="rect41"
|
||||
width="1.000025"
|
||||
height="11.921875"
|
||||
x="34.473"
|
||||
y="18.546875" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
@@ -0,0 +1,97 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="40"
|
||||
height="40"
|
||||
viewBox="0 0 40 40"
|
||||
version="1.1"
|
||||
id="svg17"
|
||||
sodipodi:docname="toolbar_face.svg"
|
||||
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs17">
|
||||
<inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect48"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,1.0055868,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,1.4911902,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,1.0376412,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 | F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" />
|
||||
<inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect47"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="namedview17"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="22.627417"
|
||||
inkscape:cx="23.113553"
|
||||
inkscape:cy="18.318485"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2126"
|
||||
inkscape:window-x="-11"
|
||||
inkscape:window-y="-11"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg17" />
|
||||
<path
|
||||
d="m 33.973006,35.500013 h -0.999987 a 0.500013,0.500013 0 0 1 0,-1.000026 h 0.999987 A 0.49999998,0.49999998 0 0 0 34.473,33.999994 v -5.000013 a 0.5000126,0.5000126 0 0 1 1.000025,0 v 5.000013 a 1.5,1.5 0 0 1 -1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6" />
|
||||
<path
|
||||
d="M 19.973012,35.500013 H 5.9730109 a 1.5,1.5 0 0 1 -1.5,-1.500019 V 6.000006 a 1.5,1.5 0 0 1 1.5,-1.500019 H 33.973006 a 1.5,1.5 0 0 1 1.500019,1.500019 v 12.999987 a 0.5000126,0.5000126 0 0 1 -1.000025,0 V 6.000006 A 0.49999998,0.49999998 0 0 0 33.973006,5.500012 H 5.9730109 a 0.49999998,0.49999998 0 0 0 -0.499997,0.499994 v 27.999988 a 0.49999998,0.49999998 0 0 0 0.499997,0.499993 H 19.973012 a 0.500013,0.500013 0 0 1 0,1.000026 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999;fill-opacity:1"
|
||||
id="path4-6" />
|
||||
<rect
|
||||
style="fill:#b6b6b6;fill-opacity:1;stroke:none;stroke-width:0;stroke-linejoin:miter;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0;paint-order:stroke fill markers"
|
||||
id="rect40"
|
||||
width="15.363631"
|
||||
height="1.000026"
|
||||
x="18.609375"
|
||||
y="34.499989" />
|
||||
<rect
|
||||
style="fill:#b6b6b6;fill-opacity:1;stroke:none;stroke-width:0;stroke-linejoin:miter;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0;paint-order:stroke fill markers"
|
||||
id="rect41"
|
||||
width="1.000025"
|
||||
height="11.921875"
|
||||
x="34.473"
|
||||
y="18.546875" />
|
||||
<path
|
||||
id="path42"
|
||||
style="fill:#009688;stroke-width:0;stroke-opacity:0;paint-order:stroke fill markers;fill-opacity:1"
|
||||
d="M 19.58431,7.9401469 19.519531,8.0820312 9.1699219,30.736328 a 0.61329334,0.61329334 42.827026 0 0 0.828125,0.767578 l 0,0 20.7832031,-7.320312 0.0019,-6.61e-4 a 0.7874119,0.7874119 107.77086 0 0 0.382891,-1.194652 L 20.714844,8.0449219 20.578195,7.8494958 A 0.57476577,0.57476577 174.78854 0 0 19.58431,7.9401469 Z M 20.232422,9.1015625 30.1875,23.332031 10.576172,30.240234 Z"
|
||||
inkscape:path-effect="#path-effect48"
|
||||
inkscape:original-d="M 20.001953,7.0253906 19.519531,8.0820312 9.1699219,30.736328 8.5917969,32 9.9980469,31.503906 30.78125,24.183594 31.761719,23.837891 31.166016,22.988281 20.714844,8.0449219 Z M 20.232422,9.1015625 30.1875,23.332031 10.576172,30.240234 Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,240 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="40"
|
||||
height="40"
|
||||
viewBox="0 0 40 40"
|
||||
version="1.1"
|
||||
id="svg17"
|
||||
sodipodi:docname="toolbar_texture_displacement.svg"
|
||||
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs17" />
|
||||
<sodipodi:namedview
|
||||
id="namedview17"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="32"
|
||||
inkscape:cx="27.578125"
|
||||
inkscape:cy="27.671875"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2126"
|
||||
inkscape:window-x="-11"
|
||||
inkscape:window-y="-11"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg17" />
|
||||
<g
|
||||
id="g17"
|
||||
transform="translate(0.69176086,0.249987)">
|
||||
<path
|
||||
d="m 27.659236,35.176022 h -4.399987 c -0.508996,0 -0.844996,0 -0.954999,-0.394015 a 0.59299998,0.59299998 0 0 1 0.36,-0.669997 2.3,2.3 0 0 0 1.2,-2.188989 3.253,3.253 0 1 1 3.800012,3.205984 z M 24.12125,34.175997 h 2.988 a 2.253,2.253 0 1 0 -2.252999,-2.252976 3.445,3.445 0 0 1 -0.735001,2.252976 z"
|
||||
style="fill:#009688;stroke-width:0.999999"
|
||||
id="path1-6" />
|
||||
<path
|
||||
d="m 30.281245,30.538996 -0.846009,-0.534993 4.364031,-6.899981 A 0.222,0.222 0 0 0 33.439456,22.84588 l -5.4,6.644032 -0.776013,-0.63103 5.400001,-6.643994 a 1.222,1.222 0 0 1 1.981984,1.422992 z"
|
||||
style="fill:#009688;stroke-width:0.999999"
|
||||
id="path2-0" />
|
||||
<path
|
||||
d="m 33.281245,35.250026 h -0.999987 a 0.500013,0.500013 0 0 1 0,-1.000026 h 0.999987 a 0.49999998,0.49999998 0 0 0 0.499994,-0.499993 v -5.000013 a 0.5000126,0.5000126 0 0 1 1.000025,0 v 5.000013 a 1.5,1.5 0 0 1 -1.500019,1.500019 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path3-6" />
|
||||
<path
|
||||
d="M 19.281251,35.250026 H 5.28125 a 1.5,1.5 0 0 1 -1.5,-1.500019 V 5.750019 A 1.5,1.5 0 0 1 5.28125,4.25 h 27.999995 a 1.5,1.5 0 0 1 1.500019,1.500019 v 12.999987 a 0.5000126,0.5000126 0 0 1 -1.000025,0 V 5.750019 A 0.49999998,0.49999998 0 0 0 33.281245,5.250025 H 5.28125 A 0.49999998,0.49999998 0 0 0 4.781253,5.750019 V 33.750007 A 0.49999998,0.49999998 0 0 0 5.28125,34.25 h 14.000001 a 0.500013,0.500013 0 0 1 0,1.000026 z"
|
||||
style="fill:#b6b6b6;stroke-width:0.999999"
|
||||
id="path4-6" />
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:1.00157;stroke-dasharray:none"
|
||||
id="rect6-1"
|
||||
width="39.379108"
|
||||
height="0.99609375"
|
||||
x="-19.909107"
|
||||
y="27.094706"
|
||||
ry="0.49804688"
|
||||
transform="rotate(-45)" />
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:1.00157;stroke-dasharray:none"
|
||||
id="rect6-2"
|
||||
width="27.566595"
|
||||
height="0.99609375"
|
||||
x="7.9031763"
|
||||
y="-0.27849278"
|
||||
ry="0.49487707"
|
||||
transform="rotate(45)" />
|
||||
<g
|
||||
id="g7"
|
||||
transform="matrix(3.7795276,0,0,3.7795276,-350.69182,-427.25001)">
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:0.264999;stroke-dasharray:none"
|
||||
id="rect6-2-2"
|
||||
width="2.8453603"
|
||||
height="0.2635498"
|
||||
x="150.08304"
|
||||
y="13.289762"
|
||||
ry="0.1317749"
|
||||
transform="rotate(45)"
|
||||
rx="0.1317749" />
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:0.264999;stroke-dasharray:none"
|
||||
id="rect6-2-2-2"
|
||||
width="1.7498204"
|
||||
height="0.2635498"
|
||||
x="12.763216"
|
||||
y="-149.44461"
|
||||
ry="0.1317749"
|
||||
transform="rotate(135)"
|
||||
rx="0.1317749" />
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:0.264999;stroke-dasharray:none"
|
||||
id="rect6-2-2-2-2"
|
||||
width="0.82876241"
|
||||
height="0.27337581"
|
||||
x="13.654455"
|
||||
y="-148.49495"
|
||||
ry="0.1317749"
|
||||
transform="rotate(135)"
|
||||
rx="0.1317749" />
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:0.264999;stroke-dasharray:none"
|
||||
id="rect6-2-2-6"
|
||||
width="2.5927844"
|
||||
height="0.25224927"
|
||||
x="150.38367"
|
||||
y="12.286384"
|
||||
ry="0.12612464"
|
||||
transform="rotate(45)"
|
||||
rx="0.12612464" />
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:0.264999;stroke-dasharray:none"
|
||||
id="rect6-2-2-6-1"
|
||||
width="1.9647908"
|
||||
height="0.2635498"
|
||||
x="151.01166"
|
||||
y="11.21043"
|
||||
ry="0.1317749"
|
||||
transform="rotate(45)"
|
||||
rx="0.1317749" />
|
||||
</g>
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:1.00157;stroke-dasharray:none"
|
||||
id="rect6-2-2-8"
|
||||
width="10.754118"
|
||||
height="0.99609375"
|
||||
x="-10.211728"
|
||||
y="-31.661213"
|
||||
ry="0.49804688"
|
||||
transform="rotate(135)"
|
||||
rx="0.49804688" />
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:1.00157;stroke-dasharray:none"
|
||||
id="rect6-2-2-2-9"
|
||||
width="6.6134944"
|
||||
height="0.99609375"
|
||||
x="-33.794979"
|
||||
y="12.679931"
|
||||
ry="0.49804688"
|
||||
transform="rotate(-135)"
|
||||
rx="0.49804688" />
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:1.00157;stroke-dasharray:none"
|
||||
id="rect6-2-2-2-2-3"
|
||||
width="3.1323304"
|
||||
height="1.0332314"
|
||||
x="-30.282875"
|
||||
y="16.213961"
|
||||
ry="0.49804688"
|
||||
transform="rotate(-135)"
|
||||
rx="0.49804688" />
|
||||
<g
|
||||
id="g7-1"
|
||||
transform="matrix(0,-3.7795276,3.7795276,0,-427.55829,389.70233)">
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:0.264999;stroke-dasharray:none"
|
||||
id="rect6-2-2-9"
|
||||
width="2.8453603"
|
||||
height="0.2635498"
|
||||
x="150.08304"
|
||||
y="13.289762"
|
||||
ry="0.1317749"
|
||||
transform="rotate(45)"
|
||||
rx="0.1317749" />
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:0.264999;stroke-dasharray:none"
|
||||
id="rect6-2-2-2-8"
|
||||
width="1.7498204"
|
||||
height="0.2635498"
|
||||
x="12.763216"
|
||||
y="-149.44461"
|
||||
ry="0.1317749"
|
||||
transform="rotate(135)"
|
||||
rx="0.1317749" />
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:0.264999;stroke-dasharray:none"
|
||||
id="rect6-2-2-2-2-6"
|
||||
width="0.82876241"
|
||||
height="0.27337581"
|
||||
x="13.654455"
|
||||
y="-148.49495"
|
||||
ry="0.1317749"
|
||||
transform="rotate(135)"
|
||||
rx="0.1317749" />
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:0.264999;stroke-dasharray:none"
|
||||
id="rect6-2-2-6-5"
|
||||
width="2.5927844"
|
||||
height="0.25224927"
|
||||
x="150.38367"
|
||||
y="12.286384"
|
||||
ry="0.12612464"
|
||||
transform="rotate(45)"
|
||||
rx="0.12612464" />
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:0.264999;stroke-dasharray:none"
|
||||
id="rect6-2-2-6-1-0"
|
||||
width="1.9647908"
|
||||
height="0.2635498"
|
||||
x="151.01166"
|
||||
y="11.21043"
|
||||
ry="0.1317749"
|
||||
transform="rotate(45)"
|
||||
rx="0.1317749" />
|
||||
</g>
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:1.00157;stroke-dasharray:none"
|
||||
id="rect6-2-2-9-4"
|
||||
width="9.0822706"
|
||||
height="0.99609375"
|
||||
x="-36.379971"
|
||||
y="-4.5927153"
|
||||
ry="0.49804688"
|
||||
transform="rotate(-135)"
|
||||
rx="0.49804688" />
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:1.00157;stroke-dasharray:none"
|
||||
id="rect6-2-2-6-5-5"
|
||||
width="9.7995005"
|
||||
height="0.95338309"
|
||||
x="-36.915619"
|
||||
y="-8.385005"
|
||||
ry="0.47669154"
|
||||
transform="rotate(-135)"
|
||||
rx="0.47669154" />
|
||||
<rect
|
||||
style="fill:#009688;fill-opacity:1;stroke-width:1.00157;stroke-dasharray:none"
|
||||
id="rect6-2-2-6-1-0-0"
|
||||
width="7.425981"
|
||||
height="0.99609375"
|
||||
x="-34.54211"
|
||||
y="-12.451604"
|
||||
ry="0.49804688"
|
||||
transform="rotate(-135)"
|
||||
rx="0.49804688" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.1 KiB |