Merge remote-tracking branch 'origin/main' into optimized-prime-tower

This commit is contained in:
Erwan MATHIEU 2024-01-10 16:30:34 +01:00
commit f00636d374
194 changed files with 4484 additions and 9341 deletions

View file

@ -23,14 +23,14 @@ body:
- type: input
attributes:
label: Cura Version
placeholder: 5.3.1
placeholder: 5.6.0
validations:
required: true
- type: markdown
attributes:
value: |
We work hard on improving our slicing crashes. Our most recent release is 5.3.1.
If you are not on the latest version of Cura, [you can download it here](https://github.com/Ultimaker/Cura/releases/tag/5.3.1)
We work hard on improving our slicing crashes. Our most recent release is 5.6.0.
If you are not on the latest version of Cura, [you can download it here](https://github.com/Ultimaker/Cura/releases/latest)
- type: input
attributes:
label: Operating System

View file

@ -1,153 +0,0 @@
name: Create and Upload Conan package
on:
workflow_call:
inputs:
project_name:
required: true
type: string
recipe_id_full:
required: true
type: string
build_id:
required: true
type: number
build_info:
required: false
default: true
type: boolean
recipe_id_latest:
required: false
type: string
runs_on:
required: true
type: string
python_version:
required: true
type: string
conan_config_branch:
required: false
type: string
conan_logging_level:
required: false
type: string
conan_clean_local_cache:
required: false
type: boolean
default: false
conan_upload_community:
required: false
default: true
type: boolean
env:
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_USER }}
CONAN_PASSWORD: ${{ secrets.CONAN_PASS }}
CONAN_LOG_RUN_TO_OUTPUT: 1
CONAN_LOGGING_LEVEL: ${{ inputs.conan_logging_level }}
CONAN_NON_INTERACTIVE: 1
jobs:
conan-package-create:
runs-on: ${{ inputs.runs_on }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Python and pip
uses: actions/setup-python@v4
with:
python-version: ${{ inputs.python_version }}
cache: 'pip'
cache-dependency-path: .github/workflows/requirements-conan-package.txt
- name: Install Python requirements for runner
run: pip install -r https://raw.githubusercontent.com/Ultimaker/Cura/main/.github/workflows/requirements-conan-package.txt
# Note the runner requirements are always installed from the main branch in the Ultimaker/Cura repo
- name: Use Conan download cache (Bash)
if: ${{ runner.os != 'Windows' }}
run: conan config set storage.download_cache="$HOME/.conan/conan_download_cache"
- name: Use Conan download cache (Powershell)
if: ${{ runner.os == 'Windows' }}
run: conan config set storage.download_cache="C:\Users\runneradmin\.conan\conan_download_cache"
- name: Cache Conan local repository packages (Bash)
uses: actions/cache@v3
if: ${{ runner.os != 'Windows' }}
with:
path: |
$HOME/.conan/data
$HOME/.conan/conan_download_cache
key: conan-${{ inputs.runs_on }}-${{ runner.arch }}-create-cache
- name: Cache Conan local repository packages (Powershell)
uses: actions/cache@v3
if: ${{ runner.os == 'Windows' }}
with:
path: |
C:\Users\runneradmin\.conan\data
C:\.conan
C:\Users\runneradmin\.conan\conan_download_cache
key: conan-${{ inputs.runs_on }}-${{ runner.arch }}-create-cache
- name: Install MacOS system requirements
if: ${{ runner.os == 'Macos' }}
run: brew install autoconf automake ninja
# NOTE: Due to what are probably github issues, we have to remove the cache and reconfigure before the rest.
# This is maybe because grub caches the disk it uses last time, which is recreated each time.
- name: Install Linux system requirements
if: ${{ runner.os == 'Linux' }}
run: |
sudo rm /var/cache/debconf/config.dat
sudo dpkg --configure -a
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
sudo apt update
sudo apt upgrade
sudo apt install build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config flex bison -y
- name: Install GCC-13 on ubuntu
if: ${{ startsWith(inputs.runs_on, 'ubuntu') }}
run: |
sudo apt install g++-13 gcc-13 -y
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
- name: Create the default Conan profile
run: conan profile new default --detect
- name: Get Conan configuration from branch
if: ${{ inputs.conan_config_branch != '' }}
run: conan config install https://github.com/Ultimaker/conan-config.git -a "-b ${{ inputs.conan_config_branch }}"
- name: Get Conan configuration
run: |
conan config install https://github.com/Ultimaker/conan-config.git
conan config install https://github.com/Ultimaker/conan-config.git -a "-b runner/${{ runner.os }}/${{ runner.arch }}"
- name: Add Cura private Artifactory remote
run: conan remote add cura-private https://ultimaker.jfrog.io/artifactory/api/conan/cura-private True
- name: Create the Packages
run: conan install ${{ inputs.recipe_id_full }} --build=missing --update -c tools.build:skip_test=True
- name: Upload the Package(s)
if: ${{ always() && inputs.conan_upload_community }}
run: conan upload ${{ inputs.recipe_id_full }} -r cura --all -c
- name: Upload the Package(s) to the private Artifactory
if: ${{ always() && ! inputs.conan_upload_community }}
run: conan upload ${{ inputs.recipe_id_full }} -r cura-private --all -c

View file

@ -1,27 +1,6 @@
---
name: conan-package
# Exports the recipe, sources and binaries for Mac, Windows and Linux and upload these to the server such that these can
# be used downstream.
#
# It should run on pushes against main or CURA-* branches, but it will only create the binaries for main and release branches
on:
workflow_dispatch:
inputs:
create_binaries_windows:
required: true
default: false
description: 'create binaries Windows'
create_binaries_linux:
required: true
default: false
description: 'create binaries Linux'
create_binaries_macos:
required: true
default: false
description: 'create binaries Macos'
push:
paths:
- 'plugins/**'
@ -32,114 +11,40 @@ on:
- 'packaging/**'
- '.github/workflows/conan-*.yml'
- '.github/workflows/notify.yml'
- '.github/workflows/requirements-conan-package.txt'
- '.github/workflows/requirements-runner.txt'
- 'requirements*.txt'
- 'conanfile.py'
- 'conandata.yml'
- 'GitVersion.yml'
- '*.jinja'
branches:
- main
- 'main'
- 'CURA-*'
- '[1-9].[0-9]'
- '[1-9].[0-9][0-9]'
tags:
- '[1-9].[0-9].[0-9]*'
- '[1-9].[0-9].[0-9]'
- '[1-9].[0-9][0-9].[0-9]*'
- 'PP-*'
- '[0-9].[0-9]*'
- '[0-9].[0-9][0-9]*'
env:
CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }}
CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }}
CONAN_LOGIN_USERNAME_CURA_CE: ${{ secrets.CONAN_USER }}
CONAN_PASSWORD_CURA_CE: ${{ secrets.CONAN_PASS }}
CONAN_LOG_RUN_TO_OUTPUT: 1
CONAN_LOGGING_LEVEL: ${{ inputs.conan_logging_level }}
CONAN_NON_INTERACTIVE: 1
permissions: { }
jobs:
conan-recipe-version:
permissions:
contents: read
uses: ultimaker/cura/.github/workflows/conan-recipe-version.yml@main
uses: ultimaker/cura-workflows/.github/workflows/conan-recipe-version.yml@main
with:
project_name: cura
conan-package-create-linux:
conan-package-export:
needs: [ conan-recipe-version ]
runs-on: 'ubuntu-latest'
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cache Conan data
id: cache-conan
uses: actions/cache@v3
with:
path: ~/.conan
key: ${{ runner.os }}-conan
- name: Setup Python and pip
uses: actions/setup-python@v4
with:
python-version: '3.11.x'
cache: 'pip'
cache-dependency-path: .github/workflows/requirements-conan-package.txt
- name: Install Python requirements for runner
run: pip install -r .github/workflows/requirements-conan-package.txt
# NOTE: Due to what are probably github issues, we have to remove the cache and reconfigure before the rest.
# This is maybe because grub caches the disk it uses last time, which is recreated each time.
- name: Install Linux system requirements
if: ${{ runner.os == 'Linux' }}
run: |
sudo rm /var/cache/debconf/config.dat
sudo dpkg --configure -a
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
sudo apt update
sudo apt upgrade
sudo apt install efibootmgr build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config flex bison g++-12 gcc-12 -y
- name: Install GCC-13
run: |
sudo apt install g++-13 gcc-13 -y
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
- name: Create the default Conan profile
run: conan profile new default --detect --force
- name: Get Conan configuration
run: |
conan config install https://github.com/Ultimaker/conan-config.git
conan config install https://github.com/Ultimaker/conan-config.git -a "-b runner/${{ runner.os }}/${{ runner.arch }}"
- name: Create the Packages
run: conan create . ${{ needs.conan-recipe-version.outputs.recipe_id_full }} --build=missing --update -o ${{ needs.conan-recipe-version.outputs.project_name }}:devtools=True -c tools.build:skip_test=True
- name: Create the latest alias
if: always()
run: conan alias ${{ needs.conan-recipe-version.outputs.recipe_id_latest }} ${{ needs.conan-recipe-version.outputs.recipe_id_full }}
- name: Upload the Package(s)
if: always()
run: |
conan upload ${{ needs.conan-recipe-version.outputs.recipe_id_full }} -r cura --all -c
conan upload ${{ needs.conan-recipe-version.outputs.recipe_id_latest }} -r cura -c
notify-create:
if: ${{ always() && (github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) }}
needs: [ conan-recipe-version, conan-package-create-linux ]
uses: ultimaker/cura/.github/workflows/notify.yml@main
uses: ultimaker/cura-workflows/.github/workflows/conan-recipe-export.yml@main
with:
success: ${{ contains(join(needs.*.result, ','), 'success') }}
success_title: "New binaries created in ${{ github.repository }}"
success_body: "Created binaries for ${{ needs.conan-recipe-version.outputs.recipe_id_full }}"
failure_title: "Failed to create binaries in ${{ github.repository }}"
failure_body: "Failed to created binaries for ${{ needs.conan-recipe-version.outputs.recipe_id_full }}"
recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }}
recipe_id_latest: ${{ needs.conan-recipe-version.outputs.recipe_id_latest }}
secrets: inherit
conan-package-create:
needs: [ conan-recipe-version, conan-package-export ]
uses: ultimaker/cura-workflows/.github/workflows/conan-package-create-linux.yml@main
with:
recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }}
conan_extra_args: "-o cura:enable_i18n=True"
secrets: inherit

View file

@ -1,107 +0,0 @@
name: Export Conan Recipe to server
on:
workflow_call:
inputs:
recipe_id_full:
required: true
type: string
recipe_id_latest:
required: false
type: string
runs_on:
required: true
type: string
python_version:
required: true
type: string
conan_config_branch:
required: false
type: string
conan_logging_level:
required: false
type: string
conan_export_binaries:
required: false
type: boolean
conan_upload_community:
required: false
default: true
type: boolean
env:
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_USER }}
CONAN_PASSWORD: ${{ secrets.CONAN_PASS }}
CONAN_LOG_RUN_TO_OUTPUT: 1
CONAN_LOGGING_LEVEL: ${{ inputs.conan_logging_level }}
CONAN_NON_INTERACTIVE: 1
jobs:
package-export:
runs-on: ${{ inputs.runs_on }}
steps:
- name: Checkout project
uses: actions/checkout@v3
- name: Setup Python and pip
uses: actions/setup-python@v4
with:
python-version: ${{ inputs.python_version }}
cache: 'pip'
cache-dependency-path: .github/workflows/requirements-conan-package.txt
- name: Install Python requirements and Create default Conan profile
run: |
pip install -r https://raw.githubusercontent.com/Ultimaker/Cura/main/.github/workflows/requirements-conan-package.txt
conan profile new default --detect
# Note the runner requirements are always installed from the main branch in the Ultimaker/Cura repo
- name: Cache Conan local repository packages
uses: actions/cache@v3
with:
path: $HOME/.conan/data
key: ${{ runner.os }}-conan-export-cache
- name: Get Conan configuration from branch
if: ${{ inputs.conan_config_branch != '' }}
run: conan config install https://github.com/Ultimaker/conan-config.git -a "-b ${{ inputs.conan_config_branch }}"
- name: Get Conan configuration
run: |
conan config install https://github.com/Ultimaker/conan-config.git
conan config install https://github.com/Ultimaker/conan-config.git -a "-b runner/${{ runner.os }}/${{ runner.arch }}"
- name: Add Cura private Artifactory remote
run: conan remote add cura-private https://ultimaker.jfrog.io/artifactory/api/conan/cura-private True
- name: Export the Package (binaries)
if: ${{ inputs.conan_export_binaries }}
run: conan create . ${{ inputs.recipe_id_full }} --build=missing --update -c tools.build:skip_test=True
- name: Export the Package
if: ${{ !inputs.conan_export_binaries }}
run: conan export . ${{ inputs.recipe_id_full }}
- name: Create the latest alias
if: always()
run: conan alias ${{ inputs.recipe_id_latest }} ${{ inputs.recipe_id_full }}
- name: Upload the Package(s)
if: ${{ always() && inputs.conan_upload_community }}
run: |
conan upload ${{ inputs.recipe_id_full }} -r cura --all -c
conan upload ${{ inputs.recipe_id_latest }} -r cura -c
- name: Upload the Package(s) to the private Artifactory
if: ${{ always() && ! inputs.conan_upload_community }}
run: |
conan upload ${{ inputs.recipe_id_full }} -r cura-private --all -c
conan upload ${{ inputs.recipe_id_latest }} -r cura-private -c

View file

@ -1,217 +0,0 @@
name: Get Conan Recipe Version
on:
workflow_call:
inputs:
project_name:
required: true
type: string
user:
required: false
default: ultimaker
type: string
additional_buildmetadata:
required: false
default: ""
type: string
outputs:
recipe_id_full:
description: "The full Conan recipe id: <name>/<version>@<user>/<channel>"
value: ${{ jobs.get-semver.outputs.recipe_id_full }}
recipe_id_latest:
description: "The full Conan recipe aliased (latest) id: <name>/(latest)@<user>/<channel>"
value: ${{ jobs.get-semver.outputs.recipe_id_latest }}
recipe_semver_full:
description: "The full semver <Major>.<Minor>.<Patch>-<PreReleaseTag>+<BuildMetaData>"
value: ${{ jobs.get-semver.outputs.semver_full }}
is_release_branch:
description: "is current branch a release branch?"
value: ${{ jobs.get-semver.outputs.release_branch }}
user:
description: "The conan user"
value: ${{ jobs.get-semver.outputs.user }}
channel:
description: "The conan channel"
value: ${{ jobs.get-semver.outputs.channel }}
project_name:
description: "The conan projectname"
value: ${{ inputs.project_name }}
jobs:
get-semver:
runs-on: ubuntu-latest
outputs:
recipe_id_full: ${{ steps.get-conan-broadcast-data.outputs.recipe_id_full }}
recipe_id_latest: ${{ steps.get-conan-broadcast-data.outputs.recipe_id_latest }}
semver_full: ${{ steps.get-conan-broadcast-data.outputs.semver_full }}
is_release_branch: ${{ steps.get-conan-broadcast-data.outputs.is_release_branch }}
user: ${{ steps.get-conan-broadcast-data.outputs.user }}
channel: ${{ steps.get-conan-broadcast-data.outputs.channel }}
steps:
- name: Checkout repo
uses: actions/checkout@v3
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
with:
fetch-depth: 0
ref: ${{ github.head_ref }}
- name: Checkout repo PR
uses: actions/checkout@v3
if: ${{ github.event.pull_request.head.repo.full_name != github.repository }}
with:
fetch-depth: 0
ref: ${{ github.base_ref }}
- name: Setup Python and pip
uses: actions/setup-python@v4
with:
python-version: "3.11.x"
cache: 'pip'
cache-dependency-path: .github/workflows/requirements-conan-package.txt
- name: Install Python requirements and Create default Conan profile
run: |
pip install -r .github/workflows/requirements-conan-package.txt
pip install gitpython
- id: get-conan-broadcast-data
name: Get Conan broadcast data
run: |
import subprocess
import os
from conan.tools.scm import Version
from conan.errors import ConanException
from git import Repo
repo = Repo('.')
user = "${{ inputs.user }}".lower()
project_name = "${{ inputs.project_name }}"
event_name = "${{ github.event_name }}"
issue_number = "${{ github.ref }}".split('/')[2]
is_tag = "${{ github.ref_type }}" == "tag"
is_release_branch = False
ref_name = "${{ github.base_ref }}" if event_name == "pull_request" else "${{ github.ref_name }}"
buildmetadata = "" if "${{ inputs.additional_buildmetadata }}" == "" else "${{ inputs.additional_buildmetadata }}_"
# FIXME: for when we push a tag (such as an release)
channel = "testing"
if is_tag:
branch_version = Version(ref_name)
is_release_branch = True
channel = "_"
user = "_"
actual_version = f"{branch_version}"
else:
try:
branch_version = Version(repo.active_branch.name)
except ConanException:
branch_version = Version('0.0.0')
if ref_name == f"{branch_version.major}.{branch_version.minor}":
channel = 'stable'
is_release_branch = True
elif ref_name in ("main", "master"):
channel = 'testing'
else:
channel = "_".join(repo.active_branch.name.replace("-", "_").split("_")[:2]).lower()
if "pull_request" in event_name:
channel = f"pr_{issue_number}"
# %% Get the actual version
latest_branch_version = Version("0.0.0")
latest_branch_tag = None
for tag in repo.active_branch.repo.tags:
if str(tag).startswith("firmware") or str(tag).startswith("master"):
continue # Quick-fix for the versioning scheme name of the embedded team in fdm_materials(_private) repo
try:
version = Version(tag)
except ConanException:
continue
if version > latest_branch_version and version < Version("6.0.0"):
# FIXME: stupid old Cura tags 13.04 etc. keep popping up, als the fdm_material tag for firmware are messing with this
latest_branch_version = version
latest_branch_tag = repo.tag(tag)
if latest_branch_tag:
# %% Get the actual version
sha_commit = repo.commit().hexsha[:6]
latest_branch_version_prerelease = latest_branch_version.pre
if latest_branch_version.pre and not "." in str(latest_branch_version.pre):
# The prerealese did not contain a version number, default it to 1
latest_branch_version_prerelease = f"{latest_branch_version.pre}.1"
if event_name == "pull_request":
actual_version = f"{latest_branch_version.major}.{latest_branch_version.minor}.{latest_branch_version.patch}-{str(latest_branch_version_prerelease).lower()}+{buildmetadata}pr_{issue_number}_{sha_commit}"
channel_metadata = f"{channel}_{sha_commit}"
else:
if channel in ("stable", "_", ""):
channel_metadata = f"{sha_commit}"
else:
channel_metadata = f"{channel}_{sha_commit}"
if is_release_branch:
if (latest_branch_version.pre == "" or latest_branch_version.pre is None) and branch_version > latest_branch_version:
actual_version = f"{branch_version.major}.{branch_version.minor}.0-beta.1+{buildmetadata}{channel_metadata}"
elif latest_branch_version.pre == "":
# An actual full release has been created, we are working on patch
bump_up_patch = int(str(latest_branch_version.patch)) + 1
actual_version = f"{latest_branch_version.major}.{latest_branch_version.minor}.{bump_up_patch}-beta.1+{buildmetadata}{channel_metadata}"
elif latest_branch_version.pre is None:
actual_version = f"{latest_branch_version.major}.{latest_branch_version.minor}.{int(latest_branch_version.patch.value) + 1}-beta.1+{buildmetadata}{channel_metadata}"
else:
# An beta release has been created we are working toward a next beta or full release
bump_up_release_tag = int(str(latest_branch_version.pre).split('.')[1]) + 1
actual_version = f"{latest_branch_version.major}.{latest_branch_version.minor}.{latest_branch_version.patch}-{str(latest_branch_version.pre).split('.')[0]}.{bump_up_release_tag}+{buildmetadata}{channel_metadata}"
else:
max_branches_version = Version("0.0.0")
for branch in repo.references:
try:
if "remotes/origin" in branch.abspath:
b_version = Version(branch.name.split("/")[-1])
if b_version < Version("6.0.0") and b_version > max_branches_version:
max_branches_version = b_version
except:
pass
if max_branches_version > latest_branch_version:
actual_version = f"{max_branches_version.major}.{int(str(max_branches_version.minor)) + 1}.0-alpha+{buildmetadata}{channel}_{sha_commit}"
else:
actual_version = f"{latest_branch_version.major}.{int(str(latest_branch_version.minor)) + 1}.0-alpha+{buildmetadata}{channel_metadata}"
# %% Set the environment output
output_env = os.environ["GITHUB_OUTPUT"]
content = ""
if os.path.exists(output_env):
with open(output_env, "r") as f:
content = f.read()
with open(output_env, "w") as f:
f.write(content)
f.writelines(f"name={project_name}\n")
f.writelines(f"version={actual_version}\n")
f.writelines(f"channel={channel}\n")
f.writelines(f"recipe_id_full={project_name}/{actual_version}@{user}/{channel}\n")
f.writelines(f"recipe_id_latest={project_name}/latest@{user}/{channel}\n")
f.writelines(f"semver_full={actual_version}\n")
f.writelines(f"is_release_branch={str(is_release_branch).lower()}\n")
summary_env = os.environ["GITHUB_STEP_SUMMARY"]
with open(summary_env, "w") as f:
f.writelines(f"# {project_name}\n")
f.writelines(f"name={project_name}\n")
f.writelines(f"version={actual_version}\n")
f.writelines(f"channel={channel}\n")
f.writelines(f"recipe_id_full={project_name}/{actual_version}@{user}/{channel}\n")
f.writelines(f"recipe_id_latest={project_name}/latest@{user}/{channel}\n")
f.writelines(f"semver_full={actual_version}\n")
f.writelines(f"is_release_branch={str(is_release_branch).lower()}\n")
shell: python

View file

@ -39,56 +39,18 @@ env:
CONAN_ARGS: ${{ inputs.conan_args || '' }}
ENTERPRISE: ${{ inputs.enterprise || false }}
STAGING: ${{ inputs.staging || false }}
LATEST_RELEASE: '5.6'
LATEST_RELEASE_SCHEDULE_HOUR: 4
jobs:
default_values:
runs-on: ubuntu-latest
outputs:
cura_conan_version: ${{ steps.default.outputs.cura_conan_version }}
release_tag: ${{ steps.default.outputs.release_tag }}
steps:
- name: Output default values
id: default
shell: python
run: |
import os
import datetime
if "${{ github.event_name }}" != "schedule":
cura_conan_version = "${{ github.event.inputs.cura_conan_version }}"
else:
now = datetime.datetime.now()
cura_conan_version = "cura/latest@ultimaker/stable" if now.hour == int(os.environ['LATEST_RELEASE_SCHEDULE_HOUR']) else "cura/latest@ultimaker/testing"
release_tag = f"nightly-{os.environ['LATEST_RELEASE']}" if "/stable" in cura_conan_version else "nightly"
# Set cura_conan_version environment variable
output_env = os.environ["GITHUB_OUTPUT"]
content = ""
if os.path.exists(output_env):
with open(output_env, "r") as f:
content = f.read()
with open(output_env, "w") as f:
f.write(content)
f.writelines(f"cura_conan_version={cura_conan_version}\n")
f.writelines(f"release_tag={release_tag}\n")
summary_env = os.environ["GITHUB_STEP_SUMMARY"]
content = ""
if os.path.exists(summary_env):
with open(summary_env, "r") as f:
content = f.read()
with open(summary_env, "w") as f:
f.write(content)
f.writelines(f"# cura_conan_version = {cura_conan_version}\n")
f.writelines(f"# release_tag = {release_tag}\n")
uses: ultimaker/cura-workflows/.github/workflows/cura-installer-default-value.yml@main
with:
cura_conan_version: ${{ inputs.cura_conan_version }}
latest_release: '5.6'
latest_release_schedule_hour: 4
latest_release_tag: 'nightly'
windows-installer:
uses: ./.github/workflows/windows.yml
uses: ultimaker/cura-workflows/.github/workflows/cura-installer-windows.yml@main
needs: [ default_values ]
with:
cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }}
@ -100,7 +62,7 @@ jobs:
secrets: inherit
linux-installer:
uses: ./.github/workflows/linux.yml
uses: ultimaker/cura-workflows/.github/workflows/cura-installer-linux.yml@main
needs: [ default_values ]
with:
cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }}
@ -112,7 +74,7 @@ jobs:
secrets: inherit
macos-installer:
uses: ./.github/workflows/macos.yml
uses: ultimaker/cura-workflows/.github/workflows/cura-installer-macos.yml@main
needs: [ default_values ]
with:
cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }}
@ -124,7 +86,7 @@ jobs:
secrets: inherit
macos-arm-installer:
uses: ./.github/workflows/macos.yml
uses: ultimaker/cura-workflows/.github/workflows/cura-installer-macos.yml@main
needs: [ default_values ]
with:
cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }}
@ -142,9 +104,9 @@ jobs:
needs: [ default_values, windows-installer, linux-installer, macos-installer, macos-arm-installer ]
steps:
- name: Checkout
uses: actions/checkout@v3
# It's not necessary to download all three, but it does make sure we have at least one if an OS is skipped.
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Download the run info
uses: actions/download-artifact@v2
@ -193,7 +155,7 @@ jobs:
with:
name: ${{ steps.filename.outputs.LINUX }}-AppImage
path: installers
- name: Download linux installer jobs asc artifacts
uses: actions/download-artifact@v2
with:
@ -285,19 +247,20 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: create the release notes
shell: python
run: |
import os
import datetime
from jinja2 import Template
with open(".github/workflows/release-notes.md.jinja", "r") as f:
with open(".github/workflows/release_notes.md.jinja", "r") as f:
release_notes = Template(f.read())
current_nightly_beta = "${{ needs.default_values.outputs.release_tag }}".split("nightly-")[-1]
with open("release-notes.md", "w") as f:
f.write(release_notes.render(
timestamp=${{ steps.filename.outputs.NIGHTLY_TIME }},
branch="" if ${{ needs.default_values.outputs.release_tag == 'nightly' }} else current_nightly_beta,
timestamp="${{ steps.filename.outputs.NIGHTLY_TIME }}",
branch="" if "${{ needs.default-values.outputs.release_tag == 'nightly' }}" == 'true' else current_nightly_beta,
branch_specific="" if os.getenv("GITHUB_REF") == "refs/heads/main" else f"?branch={current_nightly_beta}",
))

View file

@ -1,5 +1,5 @@
name: Linux Installer
run-name: ${{ inputs.cura_conan_version }} for Linux-${{ inputs.architecture }} by @${{ github.actor }}
run-name: ${{ inputs.cura_conan_version }} by @${{ github.actor }}
on:
workflow_dispatch:
@ -39,232 +39,14 @@ on:
options:
- ubuntu-22.04
workflow_call:
inputs:
cura_conan_version:
description: 'Cura Conan Version'
default: 'cura/latest@ultimaker/testing'
required: true
type: string
conan_args:
description: 'Conan args: eq.: --require-override'
default: ''
required: false
type: string
enterprise:
description: 'Build Cura as an Enterprise edition'
default: false
required: true
type: boolean
staging:
description: 'Use staging API'
default: false
required: true
type: boolean
architecture:
description: 'Architecture'
required: true
default: 'X64'
type: string
operating_system:
description: 'OS'
required: true
default: 'ubuntu-22.04'
type: string
env:
CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }}
CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
CURA_CONAN_VERSION: ${{ inputs.cura_conan_version }}
ENTERPRISE: ${{ inputs.enterprise }}
STAGING: ${{ inputs.staging }}
jobs:
cura-installer-create:
runs-on: ${{ inputs.operating_system }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Python and pip
uses: actions/setup-python@v4
with:
python-version: '3.10.x'
cache: 'pip'
cache-dependency-path: .github/workflows/requirements-conan-package.txt
- name: Install Python requirements for runner
run: pip install -r .github/workflows/requirements-conan-package.txt
- name: Cache Conan local repository packages (Bash)
uses: actions/cache@v3
with:
path: |
$HOME/.conan/data
$HOME/.conan/conan_download_cache
key: conan-${{ runner.os }}-${{ runner.arch }}-installer-cache
- name: Install Linux system requirements
run: |
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
sudo apt update
sudo apt upgrade
sudo apt install build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config binutils coreutils desktop-file-utils fakeroot fuse libgdk-pixbuf2.0-dev patchelf squashfs-tools strace util-linux zsync -y
# Get the AppImage tool
wget --no-check-certificate --quiet https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O $GITHUB_WORKSPACE/appimagetool
chmod +x $GITHUB_WORKSPACE/appimagetool
echo "APPIMAGETOOL_LOCATION=$GITHUB_WORKSPACE/appimagetool" >> $GITHUB_ENV
# Get the AppImage builder
wget --no-check-certificate --quiet -O $GITHUB_WORKSPACE/appimage-builder-x86_64.AppImage https://github.com/AppImageCrafters/appimage-builder/releases/download/v1.1.0/appimage-builder-1.1.0-x86_64.AppImage
chmod +x appimage-builder-x86_64.AppImage
echo "APPIMAGEBUILDER_LOCATION=$GITHUB_WORKSPACE/appimage-builder-x86_64.AppImage" >> $GITHUB_ENV
# Make sure these tools can be found on the path
echo "$GITHUB_WORKSPACE" >> $GITHUB_PATH
- name: Install GCC-13
run: |
sudo apt install g++-13 gcc-13 -y
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
- name: Create the default Conan profile
run: conan profile new default --detect --force
- name: Configure GPG Key Linux (Bash)
run: echo -n "$GPG_PRIVATE_KEY" | base64 --decode | gpg --import
- name: Get Conan configuration
run: |
conan config install https://github.com/Ultimaker/conan-config.git
conan config install https://github.com/Ultimaker/conan-config.git -a "-b runner/${{ runner.os }}/${{ runner.arch }}"
- name: Use Conan download cache (Bash)
run: conan config set storage.download_cache="$HOME/.conan/conan_download_cache"
- name: Create the Packages (Bash)
run: conan install $CURA_CONAN_VERSION ${{ inputs.conan_args }} --build=missing --update -if cura_inst -g VirtualPythonEnv -o cura:enterprise=$ENTERPRISE -o cura:staging=$STAGING -c tools.build:skip_test=True
- name: Remove internal packages before uploading
run: |
conan remove "*@internal/*" -f || true
conan remove "cura_private_data*" -f || true
- name: Upload the Package(s)
if: always()
run: |
conan upload "*" -r cura --all -c
- name: Set Environment variables for Cura (bash)
run: |
. ./cura_inst/bin/activate_github_actions_env.sh
. ./cura_inst/bin/activate_github_actions_version_env.sh
# FIXME: This is a workaround to ensure that we use and pack a shared library for OpenSSL 1.1.1l. We currently compile
# OpenSSL statically for CPython, but our Python Dependenies (such as PyQt6) require a shared library.
# Because Conan won't allow for building the same library with two different options (easily) we need to install it explicitly
# and do a manual copy to the VirtualEnv, such that Pyinstaller can find it.
- name: Install OpenSSL shared
run: conan install openssl/1.1.1l@_/_ --build=missing --update -o openssl:shared=True -g deploy
- name: Copy OpenSSL shared (Bash)
run: |
cp ./openssl/lib/*.so* ./cura_inst/bin/ || true
cp ./openssl/lib/*.dylib* ./cura_inst/bin/ || true
- name: Create the Cura dist
run: pyinstaller ./cura_inst/UltiMaker-Cura.spec
- name: Output the name file name and extension
id: filename
shell: python
run: |
import os
enterprise = "-Enterprise" if "${{ inputs.enterprise }}" == "true" else ""
installer_filename = f"UltiMaker-Cura-{os.getenv('CURA_VERSION_FULL')}{enterprise}-linux-${{ inputs.architecture }}"
output_env = os.environ["GITHUB_OUTPUT"]
content = ""
if os.path.exists(output_env):
with open(output_env, "r") as f:
content = f.read()
with open(output_env, "w") as f:
f.write(content)
f.writelines(f"INSTALLER_FILENAME={installer_filename}\n")
- name: Summarize the used dependencies
shell: python
run: |
import os
from cura.CuraVersion import ConanInstalls, PythonInstalls
summary_env = os.environ["GITHUB_STEP_SUMMARY"]
content = ""
if os.path.exists(summary_env):
with open(summary_env, "r") as f:
content = f.read()
with open(summary_env, "w") as f:
f.write(content)
f.writelines("# ${{ steps.filename.outputs.INSTALLER_FILENAME }}\n")
f.writelines("## Conan packages:\n")
for dep_name, dep_info in ConanInstalls.items():
f.writelines(f"`{dep_name} {dep_info['version']} {dep_info['revision']}`\n")
f.writelines("## Python modules:\n")
for dep_name, dep_info in PythonInstalls.items():
f.writelines(f"`{dep_name} {dep_info['version']}`\n")
- name: Create the Linux AppImage (Bash)
run: |
python ../cura_inst/packaging/AppImage-builder/create_appimage.py ./UltiMaker-Cura $CURA_VERSION_FULL "${{ steps.filename.outputs.INSTALLER_FILENAME }}.AppImage"
chmod +x "${{ steps.filename.outputs.INSTALLER_FILENAME }}.AppImage"
working-directory: dist
- name: Upload the AppImage
uses: actions/upload-artifact@v3
with:
name: ${{ steps.filename.outputs.INSTALLER_FILENAME }}-AppImage
path: |
dist/${{ steps.filename.outputs.INSTALLER_FILENAME }}.AppImage
retention-days: 5
- name: Upload the asc
uses: actions/upload-artifact@v3
with:
name: ${{ steps.filename.outputs.INSTALLER_FILENAME }}-asc
path: |
dist/${{ steps.filename.outputs.INSTALLER_FILENAME }}.AppImage.asc
retention-days: 5
- name: Write the run info
shell: python
run: |
import os
with open("run_info.sh", "w") as f:
f.writelines(f'echo "CURA_VERSION_FULL={os.environ["CURA_VERSION_FULL"]}" >> $GITHUB_ENV\n')
- name: Upload the run info
uses: actions/upload-artifact@v3
with:
name: linux-run-info
path: |
run_info.sh
retention-days: 5
notify-export:
if: ${{ always() }}
needs: [ cura-installer-create ]
uses: ultimaker/cura/.github/workflows/notify.yml@main
linux-installer:
uses: ultimaker/cura-workflows/.github/workflows/cura-installer-linux.yml@main
with:
success: ${{ contains(join(needs.*.result, ','), 'success') }}
success_title: "Create the Cura distributions"
success_body: "Installers for ${{ inputs.cura_conan_version }}"
failure_title: "Failed to create the Cura distributions"
failure_body: "Failed to create at least 1 installer for ${{ inputs.cura_conan_version }}"
secrets: inherit
cura_conan_version: ${{ inputs.cura_conan_version }}
conan_args: ${{ inputs.conan_args }}
enterprise: ${{ inputs.enterprise }}
staging: ${{ inputs.staging }}
architecture: ${{ inputs.architecture }}
operating_system: ${{ inputs.operating_system }}
secrets: inherit

View file

@ -1,5 +1,5 @@
name: Macos Installer
run-name: ${{ inputs.cura_conan_version }} for Macos-${{ inputs.architecture }} by @${{ github.actor }}
name: MacOS Installer
run-name: ${{ inputs.cura_conan_version }} by @${{ github.actor }}
on:
workflow_dispatch:
@ -42,241 +42,15 @@ on:
- self-hosted-ARM64
- macos-11
- macos-12
workflow_call:
inputs:
cura_conan_version:
description: 'Cura Conan Version'
default: 'cura/latest@ultimaker/testing'
required: true
type: string
conan_args:
description: 'Conan args: eq.: --require-override'
default: ''
required: false
type: string
enterprise:
description: 'Build Cura as an Enterprise edition'
default: false
required: true
type: boolean
staging:
description: 'Use staging API'
default: false
required: true
type: boolean
architecture:
description: 'Architecture'
required: true
default: 'ARM64'
type: string
operating_system:
description: 'OS'
required: true
default: 'self-hosted-ARM64'
type: string
env:
CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }}
CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }}
CODESIGN_IDENTITY: ${{ secrets.CODESIGN_IDENTITY }}
MAC_NOTARIZE_USER: ${{ secrets.MAC_NOTARIZE_USER }}
MAC_NOTARIZE_PASS: ${{ secrets.MAC_NOTARIZE_PASS }}
MACOS_CERT_P12: ${{ secrets.MACOS_CERT_P12 }}
MACOS_CERT_INSTALLER_P12: ${{ secrets.MACOS_CERT_INSTALLER_P12 }}
MACOS_CERT_USER: ${{ secrets.MACOS_CERT_USER }}
MACOS_CERT_PASSPHRASE: ${{ secrets.MACOS_CERT_PASSPHRASE }}
CURA_CONAN_VERSION: ${{ inputs.cura_conan_version }}
ENTERPRISE: ${{ inputs.enterprise }}
STAGING: ${{ inputs.staging }}
jobs:
cura-installer-create:
runs-on: ${{ inputs.operating_system }}
outputs:
INSTALLER_FILENAME: ${{ steps.filename.outputs.INSTALLER_FILENAME }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Python and pip
uses: actions/setup-python@v4
with:
python-version: '3.11.x'
cache: 'pip'
cache-dependency-path: .github/workflows/requirements-conan-package.txt
- name: Install Python requirements for runner
run: pip install -r .github/workflows/requirements-conan-package.txt
- name: Cache Conan local repository packages (Bash)
uses: actions/cache@v3
with:
path: |
$HOME/.conan/data
$HOME/.conan/conan_download_cache
key: conan-${{ runner.os }}-${{ runner.arch }}-installer-cache
- name: Install MacOS system requirements
run: brew install cmake autoconf automake ninja create-dmg
- name: Create the default Conan profile
run: conan profile new default --detect --force
- name: Remove Macos keychain (Bash)
run: security delete-keychain signing_temp.keychain || true
- name: Configure Macos keychain Developer Cert(Bash)
id: macos-keychain-developer-cert
uses: apple-actions/import-codesign-certs@v1
with:
keychain-password: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
p12-file-base64: ${{ secrets.MACOS_CERT_P12 }}
p12-password: ${{ secrets.MACOS_CERT_PASSPHRASE }}
- name: Configure Macos keychain Installer Cert (Bash)
id: macos-keychain-installer-cert
uses: apple-actions/import-codesign-certs@v1
with:
keychain-password: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
create-keychain: false # keychain is created in previous use of action.
p12-file-base64: ${{ secrets.MACOS_CERT_INSTALLER_P12 }}
p12-password: ${{ secrets.MACOS_CERT_PASSPHRASE }}
- name: Remove private Artifactory
run: conan remote remove cura-conan-private || true
- name: Get Conan configuration
run: |
conan config install https://github.com/Ultimaker/conan-config.git
conan config install https://github.com/Ultimaker/conan-config.git -a "-b runner/${{ runner.os }}/${{ runner.arch }}"
- name: Use Conan download cache (Bash)
run: conan config set storage.download_cache="$HOME/.conan/conan_download_cache"
- name: Create the Packages (Bash)
run: conan install $CURA_CONAN_VERSION ${{ inputs.conan_args }} --build=missing --update -if cura_inst -g VirtualPythonEnv -o cura:enterprise=$ENTERPRISE -o cura:staging=$STAGING -c tools.build:skip_test=True
- name: Remove internal packages before uploading
run: |
conan remove "*@internal/*" -f || true
conan remove "cura_private_data*" -f || true
- name: Upload the Package(s)
run: |
conan upload "*" -r cura --all -c
- name: Set Environment variables for Cura (bash)
run: |
. ./cura_inst/bin/activate_github_actions_env.sh
. ./cura_inst/bin/activate_github_actions_version_env.sh
- name: Unlock Macos keychain (Bash)
run: security unlock -p $TEMP_KEYCHAIN_PASSWORD signing_temp.keychain
env:
TEMP_KEYCHAIN_PASSWORD: ${{ steps.macos-keychain-developer-cert.outputs.keychain-password }}
# FIXME: This is a workaround to ensure that we use and pack a shared library for OpenSSL 1.1.1l. We currently compile
# OpenSSL statically for CPython, but our Python Dependenies (such as PyQt6) require a shared library.
# Because Conan won't allow for building the same library with two different options (easily) we need to install it explicitly
# and do a manual copy to the VirtualEnv, such that Pyinstaller can find it.
- name: Install OpenSSL shared
run: conan install openssl/1.1.1l@_/_ --build=missing --update -o openssl:shared=True -g deploy
- name: Copy OpenSSL shared (Bash)
run: |
cp ./openssl/lib/*.so* ./cura_inst/bin/ || true
cp ./openssl/lib/*.dylib* ./cura_inst/bin/ || true
- name: Create the Cura dist
run: pyinstaller ./cura_inst/UltiMaker-Cura.spec
- name: Output the name file name and extension
id: filename
shell: python
run: |
import os
enterprise = "-Enterprise" if "${{ inputs.enterprise }}" == "true" else ""
installer_filename = f"UltiMaker-Cura-{os.getenv('CURA_VERSION_FULL')}{enterprise}-macos-${{ inputs.architecture }}"
output_env = os.environ["GITHUB_OUTPUT"]
content = ""
if os.path.exists(output_env):
with open(output_env, "r") as f:
content = f.read()
with open(output_env, "w") as f:
f.write(content)
f.writelines(f"INSTALLER_FILENAME={installer_filename}\n")
- name: Summarize the used dependencies
shell: python
run: |
import os
from cura.CuraVersion import ConanInstalls, PythonInstalls
summary_env = os.environ["GITHUB_STEP_SUMMARY"]
content = ""
if os.path.exists(summary_env):
with open(summary_env, "r") as f:
content = f.read()
with open(summary_env, "w") as f:
f.write(content)
f.writelines("# ${{ steps.filename.outputs.INSTALLER_FILENAME }}\n")
f.writelines("## Conan packages:\n")
for dep_name, dep_info in ConanInstalls.items():
f.writelines(f"`{dep_name} {dep_info['version']} {dep_info['revision']}`\n")
f.writelines("## Python modules:\n")
for dep_name, dep_info in PythonInstalls.items():
f.writelines(f"`{dep_name} {dep_info['version']}`\n")
- name: Create the Macos dmg (Bash)
run: python ../cura_inst/packaging/MacOS/build_macos.py --source_path ../cura_inst --dist_path . --cura_conan_version $CURA_CONAN_VERSION --filename "${{ steps.filename.outputs.INSTALLER_FILENAME }}" --build_dmg --build_pkg --app_name "$CURA_APP_NAME"
working-directory: dist
- name: Upload the dmg
uses: actions/upload-artifact@v3
with:
name: ${{ steps.filename.outputs.INSTALLER_FILENAME }}-dmg
path: |
dist/${{ steps.filename.outputs.INSTALLER_FILENAME }}.dmg
retention-days: 5
- name: Upload the pkg
uses: actions/upload-artifact@v3
with:
name: ${{ steps.filename.outputs.INSTALLER_FILENAME }}-pkg
path: |
dist/${{ steps.filename.outputs.INSTALLER_FILENAME }}.pkg
retention-days: 5
- name: Write the run info
shell: python
run: |
import os
with open("run_info.sh", "w") as f:
f.writelines(f'echo "CURA_VERSION_FULL={os.environ["CURA_VERSION_FULL"]}" >> $GITHUB_ENV\n')
- name: Upload the run info
uses: actions/upload-artifact@v3
with:
name: macos-run-info
path: |
run_info.sh
retention-days: 5
notify-export:
if: ${{ always() }}
needs: [ cura-installer-create ]
uses: ultimaker/cura/.github/workflows/notify.yml@main
macos-installer:
uses: ultimaker/cura-workflows/.github/workflows/cura-installer-macos.yml@main
with:
success: ${{ contains(join(needs.*.result, ','), 'success') }}
success_title: "Create the Cura distributions"
success_body: "Installers for ${{ inputs.cura_conan_version }}"
failure_title: "Failed to create the Cura distributions"
failure_body: "Failed to create at least 1 installer for ${{ inputs.cura_conan_version }}"
secrets: inherit
cura_conan_version: ${{ inputs.cura_conan_version }}
conan_args: ${{ inputs.conan_args }}
enterprise: ${{ inputs.enterprise }}
staging: ${{ inputs.staging }}
architecture: ${{ inputs.architecture }}
operating_system: ${{ inputs.operating_system }}
secrets: inherit

View file

@ -1,54 +0,0 @@
name: Get Conan Recipe Version
on:
workflow_call:
inputs:
success:
required: true
type: boolean
success_title:
required: true
type: string
success_body:
required: true
type: string
failure_title:
required: true
type: string
failure_body:
required: true
type: string
jobs:
slackNotification:
name: Slack Notification
runs-on: ubuntu-latest
steps:
- name: Slack notify on-success
if: ${{ inputs.success }}
uses: rtCamp/action-slack-notify@v2
env:
SLACK_USERNAME: ${{ github.repository }}
SLACK_COLOR: green
SLACK_ICON: https://github.com/Ultimaker/Cura/blob/main/icons/cura-128.png?raw=true
SLACK_TITLE: ${{ inputs.success_title }}
SLACK_MESSAGE: ${{ inputs.success_body }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
- name: Slack notify on-failure
if: ${{ !inputs.success }}
uses: rtCamp/action-slack-notify@v2
env:
SLACK_USERNAME: ${{ github.repository }}
SLACK_COLOR: red
SLACK_ICON: https://github.com/Ultimaker/Cura/blob/main/icons/cura-128.png?raw=true
SLACK_TITLE: ${{ inputs.failure_title }}
SLACK_MESSAGE: ${{ inputs.failure_body }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

View file

@ -1,15 +1,10 @@
name: process-pull-request
on:
pull_request_target:
types: [opened, reopened, edited, synchronize, review_requested, ready_for_review, assigned]
pull_request_target:
types: [ opened, reopened, edited, review_requested, ready_for_review, assigned ]
jobs:
add_label:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-ecosystem/action-add-labels@v1
if: ${{ github.event.pull_request.head.repo.full_name != github.repository }}
with:
labels: 'PR: Community Contribution :crown:'
add_label:
uses: ultimaker/cura-workflows/.github/workflows/process-pull-request.yml@main
secrets: inherit

View file

@ -1,2 +1,2 @@
conan>=1.60.2,<2.0.0
sip
sip<=6.7.12

View file

View file

@ -1,82 +1,14 @@
name: unit-test-post
on:
workflow_run:
workflows: [ "unit-test" ]
types: [ completed ]
workflow_run:
workflows: [ "unit-test" ]
types: [ completed ]
jobs:
publish-test-results:
if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
steps:
- name: Download analysis results
uses: actions/github-script@v3.1.0
with:
script: |
let artifacts = await github.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id }},
});
let matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "test-result"
})[0];
let download = await github.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: "zip",
});
let fs = require("fs");
fs.writeFileSync("${{github.workspace}}/test-result.zip", Buffer.from(download.data));
- name: Set environment variables
run: |
mkdir pr_env
unzip test-result.zip -d pr_env
echo "pr_id=$(cat pr_env/pr-id.txt)" >> $GITHUB_ENV
echo "pr_head_repo=$(cat pr_env/pr-head-repo.txt)" >> $GITHUB_ENV
echo "pr_head_ref=$(cat pr_env/pr-head-ref.txt)" >> $GITHUB_ENV
- uses: actions/checkout@v3
with:
repository: ${{ env.pr_head_repo }}
ref: ${{ env.pr_head_ref }}
persist-credentials: false
- name: Redownload analysis results
uses: actions/github-script@v3.1.0
with:
script: |
let artifacts = await github.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id }},
});
let matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "test-result"
})[0];
let download = await github.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: "zip",
});
let fs = require("fs");
fs.writeFileSync("${{github.workspace}}/test-result.zip", Buffer.from(download.data));
- name: Extract analysis results
run: |
mkdir -p tests
unzip test-result.zip -d tests
- name: Publish Unit Test Results
id: test-results
uses: EnricoMi/publish-unit-test-result-action@v1
with:
files: "tests/**/*.xml"
- name: Conclusion
run: echo "Conclusion is ${{ steps.test-results.outputs.json && fromJSON( steps.test-results.outputs.json ).conclusion }}"
publish-test-results:
uses: ultimaker/cura-workflows/.github/workflows/unit-test-post.yml@main
with:
event: ${{ github.event.workflow_run.event }}
conclusion: ${{ github.event.workflow_run.conclusion }}
secrets: inherit

View file

@ -1,4 +1,3 @@
---
name: unit-test
on:
@ -9,23 +8,18 @@ on:
- 'cura/**'
- 'icons/**'
- 'tests/**'
- 'packaging/**'
- '.github/workflows/conan-*.yml'
- '.github/workflows/unit-test.yml'
- '.github/workflows/notify.yml'
- '.github/workflows/requirements-conan-package.txt'
- '.github/workflows/requirements-runner.txt'
- 'requirements*.txt'
- 'conanfile.py'
- 'conandata.yml'
- 'GitVersion.yml'
- '*.jinja'
branches:
- main
- 'CURA-*'
- '[1-9]+.[0-9]+'
tags:
- '[0-9]+.[0-9]+.[0-9]+'
- '[0-9]+.[0-9]+-beta'
- 'PP-*'
- '[0-9]+.[0-9]+'
pull_request:
paths:
- 'plugins/**'
@ -33,134 +27,36 @@ on:
- 'cura/**'
- 'icons/**'
- 'tests/**'
- 'packaging/**'
- '.github/workflows/conan-*.yml'
- '.github/workflows/unit-test.yml'
- '.github/workflows/notify.yml'
- '.github/workflows/requirements-conan-package.txt'
- '.github/workflows/requirements-runner.txt'
- 'requirements*.txt'
- 'conanfile.py'
- 'conandata.yml'
- 'GitVersion.yml'
- '*.jinja'
branches:
- main
- '[1-9]+.[0-9]+'
tags:
- '[0-9]+.[0-9]+.[0-9]+'
- '[0-9]+.[0-9]+-beta'
env:
CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }}
CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }}
CONAN_LOGIN_USERNAME_CURA_CE: ${{ secrets.CONAN_USER }}
CONAN_PASSWORD_CURA_CE: ${{ secrets.CONAN_PASS }}
CONAN_LOG_RUN_TO_OUTPUT: 1
CONAN_LOGGING_LEVEL: info
CONAN_NON_INTERACTIVE: 1
- '[0-9]+.[0-9]+'
permissions:
contents: read
env:
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_USER }}
CONAN_PASSWORD: ${{ secrets.CONAN_PASS }}
jobs:
conan-recipe-version:
uses: ultimaker/cura/.github/workflows/conan-recipe-version.yml@main
uses: ultimaker/cura-workflows/.github/workflows/conan-recipe-version.yml@main
with:
project_name: cura
testing:
runs-on: ubuntu-22.04
uses: ultimaker/cura-workflows/.github/workflows/unit-test.yml@main
needs: [ conan-recipe-version ]
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Setup Python and pip
uses: actions/setup-python@v4
with:
python-version: '3.11.x'
architecture: 'x64'
cache: 'pip'
cache-dependency-path: .github/workflows/requirements-conan-package.txt
- name: Install Python requirements and Create default Conan profile
run: pip install -r requirements-conan-package.txt
working-directory: .github/workflows/
- name: Use Conan download cache (Bash)
if: ${{ runner.os != 'Windows' }}
run: conan config set storage.download_cache="$HOME/.conan/conan_download_cache"
- name: Cache Conan local repository packages (Bash)
uses: actions/cache@v3
if: ${{ runner.os != 'Windows' }}
with:
path: |
$HOME/.conan/data
$HOME/.conan/conan_download_cache
key: conan-${{ runner.os }}-${{ runner.arch }}-unit-cache
# NOTE: Due to what are probably github issues, we have to remove the cache and reconfigure before the rest.
# This is maybe because grub caches the disk it uses last time, which is recreated each time.
- name: Install Linux system requirements
if: ${{ runner.os == 'Linux' }}
run: |
sudo rm /var/cache/debconf/config.dat
sudo dpkg --configure -a
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
sudo apt update
sudo apt upgrade
sudo apt install build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config -y
- name: Install GCC-13
run: |
sudo apt install g++-13 gcc-13 -y
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
- name: Get Conan configuration
run: |
conan config install https://github.com/Ultimaker/conan-config.git
conan config install https://github.com/Ultimaker/conan-config.git -a "-b runner/${{ runner.os }}/${{ runner.arch }}"
- name: Get Conan profile
run: conan profile new default --detect --force
- name: Install dependencies
run: conan install . ${{ needs.conan-recipe-version.outputs.recipe_id_full }} --build=missing --update -o cura:devtools=True -g VirtualPythonEnv -if venv
- name: Upload the Dependency package(s)
run: conan upload "*" -r cura --all -c
- name: Set Environment variables for Cura (bash)
if: ${{ runner.os != 'Windows' }}
run: |
. ./venv/bin/activate_github_actions_env.sh
- name: Run Unit Test
id: run-test
run: |
pytest --junitxml=junit_cura.xml
working-directory: tests
- name: Save PR metadata
if: always()
run: |
echo ${{ github.event.number }} > pr-id.txt
echo ${{ github.event.pull_request.head.repo.full_name }} > pr-head-repo.txt
echo ${{ github.event.pull_request.head.ref }} > pr-head-ref.txt
working-directory: tests
- name: Upload Test Results
if: always()
uses: actions/upload-artifact@v3
with:
name: test-result
path: |
tests/**/*.xml
tests/pr-id.txt
tests/pr-head-repo.txt
tests/pr-head-ref.txt
with:
recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }}
conan_extra_args: '-g VirtualPythonEnv -o cura:devtools=True -c tools.build:skip_test=False'
unit_test_cmd: 'pytest --junitxml=junit_cura.xml'
unit_test_dir: 'tests'
conan_generator_dir: './venv/bin'
secrets: inherit

View file

@ -1,5 +1,5 @@
name: Windows Installer
run-name: ${{ inputs.cura_conan_version }} for Windows-${{ inputs.architecture }} by @${{ github.actor }}
run-name: ${{ inputs.cura_conan_version }} by @${{ github.actor }}
on:
workflow_dispatch:
@ -38,235 +38,15 @@ on:
type: choice
options:
- windows-2022
workflow_call:
inputs:
cura_conan_version:
description: 'Cura Conan Version'
default: 'cura/latest@ultimaker/testing'
required: true
type: string
conan_args:
description: 'Conan args: eq.: --require-override'
default: ''
required: false
type: string
enterprise:
description: 'Build Cura as an Enterprise edition'
default: false
required: true
type: boolean
staging:
description: 'Use staging API'
default: false
required: true
type: boolean
architecture:
description: 'Architecture'
required: true
default: 'X64'
type: string
operating_system:
description: 'OS'
required: true
default: 'windows-2022'
type: string
env:
CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }}
CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }}
WIN_CERT_INSTALLER_CER: ${{ secrets.WIN_CERT_INSTALLER_CER }}
WIN_CERT_INSTALLER_CER_PASS: ${{ secrets.WIN_CERT_INSTALLER_CER_PASS }}
CURA_CONAN_VERSION: ${{ inputs.cura_conan_version }}
ENTERPRISE: ${{ inputs.enterprise }}
STAGING: ${{ inputs.staging }}
jobs:
cura-installer-create:
runs-on: ${{ inputs.operating_system }}
outputs:
INSTALLER_FILENAME: ${{ steps.filename.outputs.INSTALLER_FILENAME }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Python and pip
uses: actions/setup-python@v4
with:
python-version: '3.10.x'
cache: 'pip'
cache-dependency-path: .github/workflows/requirements-conan-package.txt
- name: Install Python requirements for runner
run: pip install -r .github/workflows/requirements-conan-package.txt
- name: Cache Conan local repository packages (Powershell)
uses: actions/cache@v3
with:
path: |
C:\Users\runneradmin\.conan\data
C:\.conan
C:\Users\runneradmin\.conan\conan_download_cache
key: conan-${{ runner.os }}-${{ runner.arch }}-installer-cache
- name: Create the default Conan profile
run: conan profile new default --detect --force
- name: Get Conan configuration
run: |
conan config install https://github.com/Ultimaker/conan-config.git
conan config install https://github.com/Ultimaker/conan-config.git -a "-b runner/${{ runner.os }}/${{ runner.arch }}"
- name: Use Conan download cache (Powershell)
run: conan config set storage.download_cache="C:\Users\runneradmin\.conan\conan_download_cache"
- name: Create the Packages (Powershell)
run: conan install $Env:CURA_CONAN_VERSION ${{ inputs.conan_args }} --build=missing --update -if cura_inst -g VirtualPythonEnv -o cura:enterprise=$Env:ENTERPRISE -o cura:staging=$Env:STAGING -c tools.build:skip_test=True
- name: Remove internal packages before uploading
run: |
conan remove "*@internal/*" -f || true
conan remove "cura_private_data*" -f || true
- name: Upload the Package(s)
if: always()
run: |
conan upload "*" -r cura --all -c
- name: Set Environment variables for Cura (Powershell)
run: |
echo "${Env:WIX}\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
.\cura_inst\Scripts\activate_github_actions_env.ps1
.\cura_inst\Scripts\activate_github_actions_version_env.ps1
- name: Install OpenSSL shared
run: conan install openssl/1.1.1l@_/_ --build=missing --update -o openssl:shared=True -g deploy
- name: Copy OpenSSL shared (Powershell)
run: |
cp openssl/bin/*.dll ./cura_inst/Scripts/
cp openssl/lib/*.lib ./cura_inst/Lib/
- name: Create the Cura dist
run: pyinstaller ./cura_inst/UltiMaker-Cura.spec
- name: Output the name file name and extension
id: filename
shell: python
run: |
import os
enterprise = "-Enterprise" if "${{ inputs.enterprise }}" == "true" else ""
installer_filename = f"UltiMaker-Cura-{os.getenv('CURA_VERSION_FULL')}{enterprise}-win64-${{ inputs.architecture }}"
output_env = os.environ["GITHUB_OUTPUT"]
content = ""
if os.path.exists(output_env):
with open(output_env, "r") as f:
content = f.read()
with open(output_env, "w") as f:
f.write(content)
f.writelines(f"INSTALLER_FILENAME={installer_filename}\n")
- name: Summarize the used dependencies
shell: python
run: |
import os
from cura.CuraVersion import ConanInstalls, PythonInstalls
summary_env = os.environ["GITHUB_STEP_SUMMARY"]
content = ""
if os.path.exists(summary_env):
with open(summary_env, "r") as f:
content = f.read()
with open(summary_env, "w") as f:
f.write(content)
f.writelines("# ${{ steps.filename.outputs.INSTALLER_FILENAME }}\n")
f.writelines("## Conan packages:\n")
for dep_name, dep_info in ConanInstalls.items():
f.writelines(f"`{dep_name} {dep_info['version']} {dep_info['revision']}`\n")
f.writelines("## Python modules:\n")
for dep_name, dep_info in PythonInstalls.items():
f.writelines(f"`{dep_name} {dep_info['version']}`\n")
- name: Create PFX certificate from BASE64_PFX_CONTENT secret
id: create-pfx
env:
PFX_CONTENT: ${{ secrets.WIN_CERT_INSTALLER_CER }}
run: |
$pfxPath = Join-Path -Path $env:RUNNER_TEMP -ChildPath "cert.pfx";
$encodedBytes = [System.Convert]::FromBase64String($env:PFX_CONTENT);
Set-Content $pfxPath -Value $encodedBytes -AsByteStream;
echo "PFX_PATH=$pfxPath" >> $env:GITHUB_OUTPUT;
- name: Create the Windows msi installer (Powershell)
run: |
python ..\cura_inst\packaging\msi\create_windows_msi.py ..\cura_inst .\UltiMaker-Cura "${{steps.filename.outputs.INSTALLER_FILENAME }}.msi" "$Env:CURA_APP_NAME"
working-directory: dist
- name: Sign the Windows msi installer (Powershell)
env:
PFX_PATH: ${{ steps.create-pfx.outputs.PFX_PATH }}
run: |
& "C:/Program Files (x86)/Windows Kits/10/bin/10.0.17763.0/x86/signtool.exe" sign /f $Env:PFX_PATH /p "$Env:WIN_CERT_INSTALLER_CER_PASS" /fd SHA256 /t http://timestamp.digicert.com "${{steps.filename.outputs.INSTALLER_FILENAME }}.msi"
working-directory: dist
- name: Create the Windows exe installer (Powershell)
run: |
python ..\cura_inst\packaging\NSIS\create_windows_installer.py ../cura_inst . "${{steps.filename.outputs.INSTALLER_FILENAME }}.exe"
working-directory: dist
- name: Sign the Windows exe installer (Powershell)
env:
PFX_PATH: ${{ steps.create-pfx.outputs.PFX_PATH }}
run: |
& "C:/Program Files (x86)/Windows Kits/10/bin/10.0.17763.0/x86/signtool.exe" sign /f $Env:PFX_PATH /p "$Env:WIN_CERT_INSTALLER_CER_PASS" /fd SHA256 /t http://timestamp.digicert.com "${{steps.filename.outputs.INSTALLER_FILENAME }}.exe"
working-directory: dist
- name: Upload the msi
uses: actions/upload-artifact@v3
with:
name: ${{steps.filename.outputs.INSTALLER_FILENAME }}-msi
path: |
dist/${{steps.filename.outputs.INSTALLER_FILENAME }}.msi
retention-days: 5
- name: Upload the exe
uses: actions/upload-artifact@v3
with:
name: ${{steps.filename.outputs.INSTALLER_FILENAME }}-exe
path: |
dist/${{steps.filename.outputs.INSTALLER_FILENAME }}.exe
retention-days: 5
# NOTE: The extension is .sh, since this isn't going to build-environment, so not on the Win build image.
- name: Write the run info
shell: python
run: |
import os
with open("run_info.sh", "w") as f:
f.writelines(f'echo "CURA_VERSION_FULL={os.environ["CURA_VERSION_FULL"]}" >> $GITHUB_ENV\n')
# NOTE: The extension is .sh, since this isn't going to build-environment, so not on the Win build image.
- name: Upload the run info
uses: actions/upload-artifact@v3
with:
name: windows-run-info
path: |
run_info.sh
retention-days: 5
notify-export:
if: ${{ always() }}
needs: [ cura-installer-create ]
uses: ultimaker/cura/.github/workflows/notify.yml@main
windows-installer:
uses: ultimaker/cura-workflows/.github/workflows/cura-installer-windows.yml@main
with:
success: ${{ contains(join(needs.*.result, ','), 'success') }}
success_title: "Create the Cura distributions"
success_body: "Installers for ${{ inputs.cura_conan_version }}"
failure_title: "Failed to create the Cura distributions"
failure_body: "Failed to create at least 1 installer for ${{ inputs.cura_conan_version }}"
secrets: inherit
cura_conan_version: ${{ inputs.cura_conan_version }}
conan_args: ${{ inputs.conan_args }}
enterprise: ${{ inputs.enterprise }}
staging: ${{ inputs.staging }}
architecture: ${{ inputs.architecture }}
operating_system: ${{ inputs.operating_system }}
secrets: inherit

View file

@ -1,8 +1,6 @@
# Copyright (c) 2023 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
from pkg_resources import working_set
CuraAppName = "{{ cura_app_name }}"
CuraAppDisplayName = "{{ cura_app_display_name }}"
CuraVersion = "{{ cura_version }}"
@ -16,4 +14,4 @@ CuraDigitalFactoryURL = "{{ cura_digital_factory_url }}"
CuraLatestURL = "{{ cura_latest_url }}"
ConanInstalls = {{ conan_installs }}
PythonInstalls = {package.key: {'version': package.version} for package in working_set}
PythonInstalls = {{ python_installs }}

View file

@ -12,7 +12,7 @@
[![Badge Test]][Test]
[![Badge Conan]][Conan]
![Badge Downloads]
[![Badge Downloads]][Downloads]
<br>
<br>
@ -67,6 +67,7 @@
[Issues]: https://github.com/Ultimaker/Cura/issues
[Conan]: https://github.com/Ultimaker/Cura/actions/workflows/conan-package.yml
[Test]: https://github.com/Ultimaker/Cura/actions/workflows/unit-test.yml
[Downloads]: https://github.com/Ultimaker/Cura/releases/latest
[License]: LICENSE
[Report]: docs/Report.md
@ -81,8 +82,8 @@
[Badge License]: https://img.shields.io/badge/License-LGPL3-336887.svg?style=for-the-badge&labelColor=458cb5&logoColor=white&logo=GNU
[Badge Closed]: https://img.shields.io/github/issues-closed/ultimaker/cura?style=for-the-badge&logoColor=white&labelColor=629944&color=446a30&logo=AddThis
[Badge Issues]: https://img.shields.io/github/issues/ultimaker/cura?style=for-the-badge&logoColor=white&labelColor=c34360&color=933349&logo=AdBlock
[Badge Conan]: https://img.shields.io/github/workflow/status/Ultimaker/Cura/conan-package?style=for-the-badge&logoColor=white&labelColor=6185aa&color=4c6987&logo=Conan&label=Conan%20Package
[Badge Test]: https://img.shields.io/github/workflow/status/Ultimaker/Cura/unit-test?style=for-the-badge&logoColor=white&labelColor=4a999d&color=346c6e&logo=Codacy&label=Unit%20Test
[Badge Conan]: https://img.shields.io/github/actions/workflow/status/Ultimaker/Cura/conan-package.yml?branch=main&style=for-the-badge&logoColor=white&labelColor=6185aa&color=4c6987&logo=Conan&label=Conan%20Package
[Badge Test]: https://img.shields.io/github/actions/workflow/status/Ultimaker/Cura/unit-test.yml?branch=main&style=for-the-badge&logoColor=white&labelColor=4a999d&color=346c6e&logo=Codacy&label=Unit%20Test
[Badge Size]: https://img.shields.io/github/repo-size/ultimaker/cura?style=for-the-badge&logoColor=white&labelColor=715a97&color=584674&logo=GoogleAnalytics
[Badge Downloads]: https://img.shields.io/github/downloads-pre/Ultimaker/Cura/latest/total?style=for-the-badge

View file

@ -266,6 +266,10 @@ app = UMBUNDLE(
'CFBundlePackageType': 'APPL',
'CFBundleVersionString': {{ version }},
'CFBundleShortVersionString': {{ short_version }},
'CFBundleURLTypes': [{
'CFBundleURLName': '{{ display_name }}',
'CFBundleURLSchemes': ['cura', 'slicer'],
}],
'CFBundleDocumentTypes': [{
'CFBundleTypeRole': 'Viewer',
'CFBundleTypeExtensions': ['*'],

View file

@ -1,3 +1,18 @@
version: "5.7.0-alpha.0"
requirements:
- "uranium/(latest)@ultimaker/testing"
- "curaengine/(latest)@ultimaker/testing"
- "cura_binary_data/(latest)@ultimaker/testing"
- "fdm_materials/(latest)@ultimaker/testing"
- "curaengine_plugin_gradual_flow/(latest)@ultimaker/stable"
- "dulcificum/latest@ultimaker/testing"
- "pyarcus/5.3.0"
- "pysavitar/5.3.0"
- "pynest2d/5.3.0"
- "curaengine_grpc_definitions/(latest)@ultimaker/testing"
requirements_internal:
- "fdm_materials/(latest)@internal/testing"
- "cura_private_data/(latest)@internal/testing"
urls:
default:
cloud_api_root: "https://api.ultimaker.com"

View file

@ -4,7 +4,7 @@ from pathlib import Path
from jinja2 import Template
from conan import ConanFile
from conan.tools.files import copy, rmdir, save, mkdir, rm
from conan.tools.files import copy, rmdir, save, mkdir, rm, update_conandata
from conan.tools.microsoft import unix_path
from conan.tools.env import VirtualRunEnv, Environment, VirtualBuildEnv
from conan.tools.scm import Version
@ -25,7 +25,7 @@ class CuraConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
# FIXME: Remove specific branch once merged to main
python_requires = "translationextractor/[>=2.1.1]@ultimaker/stable"
python_requires = "translationextractor/[>=2.2.0]@ultimaker/stable"
options = {
"enterprise": ["True", "False", "true", "false"], # Workaround for GH Action passing boolean as lowercase string
@ -34,7 +34,7 @@ class CuraConan(ConanFile):
"cloud_api_version": "ANY",
"display_name": "ANY", # TODO: should this be an option??
"cura_debug_mode": [True, False], # FIXME: Use profiles
"internal": [True, False],
"internal": ["True", "False", "true", "false"], # Workaround for GH Action passing boolean as lowercase string
"enable_i18n": [True, False],
}
default_options = {
@ -44,13 +44,17 @@ class CuraConan(ConanFile):
"cloud_api_version": "1",
"display_name": "UltiMaker Cura",
"cura_debug_mode": False, # Not yet implemented
"internal": False,
"internal": "False",
"enable_i18n": False,
}
def set_version(self):
if not self.version:
self.version = "5.7.0-alpha"
self.version = self.conan_data["version"]
@property
def _i18n_options(self):
return self.conf.get("user.i18n:options", default = {"extract": True, "build": True}, check_type = dict)
@property
def _pycharm_targets(self):
@ -68,7 +72,7 @@ class CuraConan(ConanFile):
self._cura_env.define("QML2_IMPORT_PATH", str(self._site_packages.joinpath("PyQt6", "Qt6", "qml")))
self._cura_env.define("QT_PLUGIN_PATH", str(self._site_packages.joinpath("PyQt6", "Qt6", "plugins")))
if not self.in_local_cache:
self._cura_env.define( "CURA_DATA_ROOT", str(self._share_dir.joinpath("cura")))
self._cura_env.define("CURA_DATA_ROOT", str(self._share_dir.joinpath("cura")))
if self.settings.os == "Linux":
self._cura_env.define("QT_QPA_FONTDIR", "/usr/share/fonts")
@ -80,6 +84,10 @@ class CuraConan(ConanFile):
def _enterprise(self):
return self.options.enterprise in ["True", 'true']
@property
def _internal(self):
return self.options.internal in ["True", 'true']
@property
def _app_name(self):
if self._enterprise:
@ -152,6 +160,23 @@ class CuraConan(ConanFile):
}
return conan_installs
def _python_installs(self):
python_installs = {}
# list of python installs
python_ins_cmd = f"python -c \"import pkg_resources; print(';'.join([(s.key+','+ s.version) for s in pkg_resources.working_set]))\""
from six import StringIO
buffer = StringIO()
self.run(python_ins_cmd, run_environment= True, env = "conanrun", output=buffer)
packages = str(buffer.getvalue()).split("-----------------\n")
packages = packages[1].strip('\r\n').split(";")
for package in packages:
name, version = package.split(",")
python_installs[name] = {"version": version}
return python_installs
def _generate_cura_version(self, location):
with open(os.path.join(self.recipe_folder, "CuraVersion.py.jinja"), "r") as f:
cura_version_py = Template(f.read())
@ -161,7 +186,7 @@ class CuraConan(ConanFile):
cura_version = Version(self.conf.get("user.cura:version", default = self.version, check_type = str))
pre_tag = f"-{cura_version.pre}" if cura_version.pre else ""
build_tag = f"+{cura_version.build}" if cura_version.build else ""
internal_tag = f"+internal" if self.options.internal else ""
internal_tag = f"+internal" if self._internal else ""
cura_version = f"{cura_version.major}.{cura_version.minor}.{cura_version.patch}{pre_tag}{build_tag}{internal_tag}"
with open(os.path.join(location, "CuraVersion.py"), "w") as f:
@ -178,13 +203,14 @@ class CuraConan(ConanFile):
cura_digital_factory_url = self.conan_data["urls"][self._urls]["digital_factory_url"],
cura_latest_url=self.conan_data["urls"][self._urls]["cura_latest_url"],
conan_installs=self._conan_installs(),
python_installs=self._python_installs(),
))
def _generate_pyinstaller_spec(self, location, entrypoint_location, icon_path, entitlements_file):
pyinstaller_metadata = self.conan_data["pyinstaller"]
datas = []
for data in pyinstaller_metadata["datas"].values():
if not self.options.internal and data.get("internal", False):
if not self._internal and data.get("internal", False):
continue
if "package" in data: # get the paths from conan package
@ -216,7 +242,7 @@ class CuraConan(ConanFile):
self.output.warning(f"Source path for binary {binary['binary']} does not exist")
continue
for bin in Path(src_path).glob(binary["binary"] + "*[.exe|.dll|.so|.dylib|.so.]*"):
for bin in Path(src_path).glob(binary["binary"] + "*[.exe|.dll|.so|.dylib|.so.|.pdb]*"):
binaries.append((str(bin), binary["dst"]))
for bin in Path(src_path).glob(binary["binary"]):
binaries.append((str(bin), binary["dst"]))
@ -239,7 +265,7 @@ class CuraConan(ConanFile):
with open(os.path.join(self.recipe_folder, "UltiMaker-Cura.spec.jinja"), "r") as f:
pyinstaller = Template(f.read())
version = self.conf_info.get("user.cura:version", default = self.version, check_type = str)
version = self.conf.get("user.cura:version", default = self.version, check_type = str)
cura_version = Version(version)
with open(os.path.join(location, "UltiMaker-Cura.spec"), "w") as f:
@ -263,6 +289,9 @@ class CuraConan(ConanFile):
short_version = f"'{cura_version.major}.{cura_version.minor}.{cura_version.patch}'",
))
def export(self):
update_conandata(self, {"version": self.version})
def export_sources(self):
copy(self, "*", os.path.join(self.recipe_folder, "plugins"), os.path.join(self.export_sources_folder, "plugins"))
copy(self, "*", os.path.join(self.recipe_folder, "resources"), os.path.join(self.export_sources_folder, "resources"), excludes = "*.mo")
@ -288,35 +317,33 @@ class CuraConan(ConanFile):
self.options["boost"].header_only = True
if self.settings.os == "Linux":
self.options["curaengine_grpc_definitions"].shared = True
self.options["openssl"].shared = True
if self.conf.get("user.curaengine:sentry_url", "", check_type=str) != "":
self.options["curaengine"].enable_sentry = True
def validate(self):
version = self.conf_info.get("user.cura:version", default = self.version, check_type = str)
version = self.conf.get("user.cura:version", default = self.version, check_type = str)
if version and Version(version) <= Version("4"):
raise ConanInvalidConfiguration("Only versions 5+ are support")
def requirements(self):
for req in self.conan_data["requirements"]:
if self._internal and "fdm_materials" in req:
continue
self.requires(req)
if self._internal:
for req in self.conan_data["requirements_internal"]:
self.requires(req)
self.requires("cpython/3.10.4@ultimaker/stable")
self.requires("openssl/3.2.0")
self.requires("boost/1.82.0")
self.requires("fmt/9.0.0")
self.requires("curaengine_grpc_definitions/0.1.0")
self.requires("spdlog/1.12.0")
self.requires("fmt/10.1.1")
self.requires("zlib/1.2.13")
self.requires("pyarcus/5.3.0")
self.requires("dulcificum/(latest)@ultimaker/stable")
self.requires("curaengine/(latest)@ultimaker/testing")
self.requires("pysavitar/5.3.0")
self.requires("pynest2d/5.3.0")
self.requires("curaengine_plugin_gradual_flow/0.1.0")
self.requires("uranium/(latest)@ultimaker/stable")
self.requires("cura_binary_data/(latest)@ultimaker/stable")
self.requires("cpython/3.10.4")
if self.options.internal:
self.requires("cura_private_data/(latest)@internal/testing")
self.requires("fdm_materials/(latest)@internal/testing")
else:
self.requires("fdm_materials/(latest)@ultimaker/stable")
def build_requirements(self):
if self.options.get_safe("enable_i18n", False):
self.tool_requires("gettext/0.21@ultimaker/testing", force_host_context = True)
self.tool_requires("gettext/0.21", force_host_context = True)
def layout(self):
self.folders.source = "."
@ -372,18 +399,24 @@ class CuraConan(ConanFile):
copy(self, "*", fdm_materials.resdirs[0], self.source_folder)
# Copy internal resources
if self.options.internal:
if self._internal:
cura_private_data = self.dependencies["cura_private_data"].cpp_info
copy(self, "*", cura_private_data.resdirs[0], str(self._share_dir.joinpath("cura")))
if self.options.devtools:
entitlements_file = "'{}'".format(os.path.join(self.source_folder, "packaging", "MacOS", "cura.entitlements"))
self._generate_pyinstaller_spec(location = self.generators_folder,
entrypoint_location = "'{}'".format(os.path.join(self.source_folder, self.conan_data["pyinstaller"]["runinfo"]["entrypoint"])).replace("\\", "\\\\"),
icon_path = "'{}'".format(os.path.join(self.source_folder, "packaging", self.conan_data["pyinstaller"]["icon"][str(self.settings.os)])).replace("\\", "\\\\"),
entitlements_file = entitlements_file if self.settings.os == "Macos" else "None")
self._generate_pyinstaller_spec(
location=self.generators_folder,
entrypoint_location="'{}'".format(
os.path.join(self.source_folder, self.conan_data["pyinstaller"]["runinfo"]["entrypoint"])).replace(
"\\", "\\\\"),
icon_path="'{}'".format(os.path.join(self.source_folder, "packaging",
self.conan_data["pyinstaller"]["icon"][
str(self.settings.os)])).replace("\\", "\\\\"),
entitlements_file=entitlements_file if self.settings.os == "Macos" else "None"
)
if self.options.get_safe("enable_i18n", False):
if self.options.get_safe("enable_i18n", False) and self._i18n_options["extract"]:
# Update the po and pot files
vb = VirtualBuildEnv(self)
vb.generate()
@ -394,7 +427,7 @@ class CuraConan(ConanFile):
pot.generate()
def build(self):
if self.options.get_safe("enable_i18n", False):
if self.options.get_safe("enable_i18n", False) and self._i18n_options["build"]:
for po_file in self.source_path.joinpath("resources", "i18n").glob("**/*.po"):
mo_file = Path(self.build_folder, po_file.with_suffix('.mo').relative_to(self.source_path))
mo_file = mo_file.parent.joinpath("LC_MESSAGES", mo_file.name)
@ -418,7 +451,7 @@ class CuraConan(ConanFile):
copy(self, "*", uranium.libdirs[0], str(self._site_packages.joinpath("UM")), keep_path = True)
# Generate the GitHub Action version info Environment
version = self.conf_info.get("user.cura:version", default = self.version, check_type = str)
version = self.conf.get("user.cura:version", default = self.version, check_type = str)
cura_version = Version(version)
env_prefix = "Env:" if self.settings.os == "Windows" else ""
activate_github_actions_version_env = Template(r"""echo "CURA_VERSION_MAJOR={{ cura_version_major }}" >> ${{ env_prefix }}GITHUB_ENV
@ -485,6 +518,7 @@ echo "CURA_APP_NAME={{ cura_app_name }}" >> ${{ env_prefix }}GITHUB_ENV
del self.info.options.cloud_api_version
del self.info.options.display_name
del self.info.options.cura_debug_mode
self.options.rm_safe("enable_i18n")
# TODO: Use the hash of requirements.txt and requirements-ultimaker.txt, Because changing these will actually result in a different
# Cura. This is needed because the requirements.txt aren't managed by Conan and therefor not resolved in the package_id. This isn't

View file

@ -14,7 +14,7 @@ DEFAULT_CURA_LATEST_URL = "https://software.ultimaker.com/latest.json"
# Each release has a fixed SDK version coupled with it. It doesn't make sense to make it configurable because, for
# example Cura 3.2 with SDK version 6.1 will not work. So the SDK version is hard-coded here and left out of the
# CuraVersion.py.in template.
CuraSDKVersion = "8.5.0"
CuraSDKVersion = "8.6.0"
try:
from cura.CuraVersion import CuraLatestURL

View file

@ -241,14 +241,8 @@ class GridArrange(Arranger):
center_grid_x = coord_grid_x + (0.5 * self._grid_width)
center_grid_y = coord_grid_y + (0.5 * self._grid_height)
bounding_box = node.getBoundingBox()
center_node_x = (bounding_box.left + bounding_box.right) * 0.5
center_node_y = (bounding_box.back + bounding_box.front) * 0.5
delta_x = center_grid_x - center_node_x
delta_y = center_grid_y - center_node_y
return TranslateOperation(node, Vector(delta_x, 0, delta_y))
return TranslateOperation(node, Vector(center_grid_x, node.getWorldPosition().y, center_grid_y),
set_position=True)
def _getGridCornerPoints(
self,

View file

@ -120,6 +120,8 @@ class BuildVolume(SceneNode):
# Objects loaded at the moment. We are connected to the property changed events of these objects.
self._scene_objects = set() # type: Set[SceneNode]
# Number of toplevel printable meshes. If there is more than one, the build volume needs to take account of the gantry height in One at a Time printing.
self._root_printable_object_count = 0
self._scene_change_timer = QTimer()
self._scene_change_timer.setInterval(200)
@ -151,6 +153,7 @@ class BuildVolume(SceneNode):
def _onSceneChangeTimerFinished(self):
root = self._application.getController().getScene().getRoot()
new_scene_objects = set(node for node in BreadthFirstIterator(root) if node.callDecoration("isSliceable"))
if new_scene_objects != self._scene_objects:
for node in new_scene_objects - self._scene_objects: #Nodes that were added to the scene.
self._updateNodeListeners(node)
@ -166,6 +169,26 @@ class BuildVolume(SceneNode):
self.rebuild()
self._scene_objects = new_scene_objects
# This also needs to be called when objects are grouped/ungrouped,
# which is not reflected in a change in self._scene_objects
self._updateRootPrintableObjectCount()
def _updateRootPrintableObjectCount(self):
# Get the number of models in the scene root, excluding modifier meshes and counting grouped models as 1
root = self._application.getController().getScene().getRoot()
scene_objects = set(node for node in BreadthFirstIterator(root) if node.callDecoration("isSliceable") or node.callDecoration("isGroup"))
new_root_printable_object_count = len(list(node for node in scene_objects if node.getParent() == root and not (
node_stack := node.callDecoration("getStack") and (
node.callDecoration("getStack").getProperty("anti_overhang_mesh", "value") or
node.callDecoration("getStack").getProperty("support_mesh", "value") or
node.callDecoration("getStack").getProperty("cutting_mesh", "value") or
node.callDecoration("getStack").getProperty("infill_mesh", "value")
))
))
if new_root_printable_object_count != self._root_printable_object_count:
self._root_printable_object_count = new_root_printable_object_count
self._onSettingPropertyChanged("print_sequence", "value") # Create fake event, so right settings are triggered.
def _updateNodeListeners(self, node: SceneNode):
@ -489,20 +512,20 @@ class BuildVolume(SceneNode):
if not self._disallowed_areas:
return None
bounding_box = Polygon(numpy.array([[min_w, min_d], [min_w, max_d], [max_w, max_d], [max_w, min_d]], numpy.float32))
mb = MeshBuilder()
color = self._disallowed_area_color
for polygon in self._disallowed_areas:
points = polygon.getPoints()
if len(points) == 0:
intersection = polygon.intersectionConvexHulls(bounding_box)
points = numpy.flipud(intersection.getPoints())
if len(points) < 3:
continue
first = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height,
self._clamp(points[0][1], min_d, max_d))
previous_point = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height,
self._clamp(points[0][1], min_d, max_d))
for point in points:
new_point = Vector(self._clamp(point[0], min_w, max_w), disallowed_area_height,
self._clamp(point[1], min_d, max_d))
first = Vector(points[0][0], disallowed_area_height, points[0][1])
previous_point = Vector(points[1][0], disallowed_area_height, points[1][1])
for point in points[2:]:
new_point = Vector(point[0], disallowed_area_height, point[1])
mb.addFace(first, previous_point, new_point, color=color)
previous_point = new_point
@ -650,7 +673,7 @@ class BuildVolume(SceneNode):
self._width = self._global_container_stack.getProperty("machine_width", "value")
machine_height = self._global_container_stack.getProperty("machine_height", "value")
if self._global_container_stack.getProperty("print_sequence", "value") == "one_at_a_time" and len(self._scene_objects) > 1:
if self._global_container_stack.getProperty("print_sequence", "value") == "one_at_a_time" and self._root_printable_object_count > 1:
new_height = min(self._global_container_stack.getProperty("gantry_height", "value") * self._scale_vector.z, machine_height)
if self._height > new_height:
@ -692,9 +715,12 @@ class BuildVolume(SceneNode):
update_extra_z_clearance = True
for setting_key in self._changed_settings_since_last_rebuild:
if setting_key in ["print_sequence", "support_mesh", "infill_mesh", "cutting_mesh", "anti_overhang_mesh"]:
self._updateRootPrintableObjectCount()
if setting_key == "print_sequence":
machine_height = self._global_container_stack.getProperty("machine_height", "value")
if self._application.getGlobalContainerStack().getProperty("print_sequence", "value") == "one_at_a_time" and len(self._scene_objects) > 1:
if self._application.getGlobalContainerStack().getProperty("print_sequence", "value") == "one_at_a_time" and self._root_printable_object_count > 1:
new_height = min(
self._global_container_stack.getProperty("gantry_height", "value") * self._scale_vector.z,
machine_height)

View file

@ -2,15 +2,18 @@
# Cura is released under the terms of the LGPLv3 or higher.
import enum
import os
import re
import sys
import tempfile
import time
import platform
from pathlib import Path
from typing import cast, TYPE_CHECKING, Optional, Callable, List, Any, Dict
import requests
import numpy
from PyQt6.QtCore import QObject, QTimer, QUrl, pyqtSignal, pyqtProperty, QEvent, pyqtEnum, QCoreApplication
from PyQt6.QtCore import QObject, QTimer, QUrl, QUrlQuery, pyqtSignal, pyqtProperty, QEvent, pyqtEnum, QCoreApplication, \
QByteArray
from PyQt6.QtGui import QColor, QIcon
from PyQt6.QtQml import qmlRegisterUncreatableType, qmlRegisterUncreatableMetaObject, qmlRegisterSingletonType, qmlRegisterType
from PyQt6.QtWidgets import QMessageBox
@ -179,6 +182,7 @@ class CuraApplication(QtApplication):
self._use_single_instance = False
self._single_instance = None
self._open_project_mode: Optional[str] = None
self._cura_formula_functions = None # type: Optional[CuraFormulaFunctions]
@ -249,7 +253,7 @@ class CuraApplication(QtApplication):
self._additional_components = {} # Components to add to certain areas in the interface
self._open_file_queue = [] # A list of files to open (after the application has started)
self._open_url_queue = [] # A list of urls to open (after the application has started)
self._update_platform_activity_timer = None
self._sidebar_custom_menu_items = [] # type: list # Keeps list of custom menu items for the side bar
@ -273,6 +277,8 @@ class CuraApplication(QtApplication):
self._conan_installs = ApplicationMetadata.CONAN_INSTALLS
self._python_installs = ApplicationMetadata.PYTHON_INSTALLS
self._supported_url_schemes: List[str] = ["cura", "slicer"]
@pyqtProperty(str, constant=True)
def ultimakerCloudApiRootUrl(self) -> str:
return UltimakerCloudConstants.CuraCloudAPIRoot
@ -325,7 +331,11 @@ class CuraApplication(QtApplication):
assert not "This crash is triggered by the trigger_early_crash command line argument."
for filename in self._cli_args.file:
self._files_to_open.append(os.path.abspath(filename))
url = QUrl(filename)
if url.scheme() in self._supported_url_schemes:
self._open_url_queue.append(url)
else:
self._files_to_open.append(os.path.abspath(filename))
def initialize(self) -> None:
self.__addExpectedResourceDirsAndSearchPaths() # Must be added before init of super
@ -946,6 +956,8 @@ class CuraApplication(QtApplication):
self.callLater(self._openFile, file_name)
for file_name in self._open_file_queue: # Open all the files that were queued up while plug-ins were loading.
self.callLater(self._openFile, file_name)
for url in self._open_url_queue:
self.callLater(self._openUrl, url)
initializationFinished = pyqtSignal()
showAddPrintersUncancellableDialog = pyqtSignal() # Used to show the add printers dialog with a greyed background
@ -1155,9 +1167,15 @@ class CuraApplication(QtApplication):
if event.type() == QEvent.Type.FileOpen:
if self._plugins_loaded:
self._openFile(event.file())
if event.file():
self._openFile(event.file())
if event.url():
self._openUrl(event.url())
else:
self._open_file_queue.append(event.file())
if event.file():
self._open_file_queue.append(event.file())
if event.url():
self._open_url_queue.append(event.url())
if int(event.type()) == 20: # 'QEvent.Type.Quit' enum isn't there, even though it should be according to docs.
# Once we're at this point, everything should have been flushed already (past OnExitCallbackManager).
@ -1541,7 +1559,7 @@ class CuraApplication(QtApplication):
if not nodes:
return
objects_in_filename = {} # type: Dict[str, List[CuraSceneNode]]
objects_in_filename: Dict[str, List[CuraSceneNode]] = {}
for node in nodes:
mesh_data = node.getMeshData()
if mesh_data:
@ -1782,6 +1800,58 @@ class CuraApplication(QtApplication):
def _openFile(self, filename):
self.readLocalFile(QUrl.fromLocalFile(filename))
def _openUrl(self, url: QUrl) -> None:
if url.scheme() not in self._supported_url_schemes:
# only handle cura:// and slicer:// urls schemes
return
match url.host() + url.path():
case "open" | "open/":
query = QUrlQuery(url.query())
model_url = QUrl(query.queryItemValue("file", options=QUrl.ComponentFormattingOption.FullyDecoded))
def on_finish(response):
content_disposition_header_key = QByteArray("content-disposition".encode())
if not response.hasRawHeader(content_disposition_header_key):
Logger.log("w", "Could not find Content-Disposition header in response from {0}".format(
model_url.url()))
# Use the last part of the url as the filename, and assume it is an STL file
filename = model_url.path().split("/")[-1] + ".stl"
else:
# content_disposition is in the format
# ```
# content_disposition attachment; "filename=[FILENAME]"
# ```
# Use a regex to extract the filename
content_disposition = str(response.rawHeader(content_disposition_header_key).data(),
encoding='utf-8')
content_disposition_match = re.match(r'attachment; filename="(?P<filename>.*)"',
content_disposition)
assert content_disposition_match is not None
filename = content_disposition_match.group("filename")
tmp = tempfile.NamedTemporaryFile(suffix=filename, delete=False)
with open(tmp.name, "wb") as f:
f.write(response.readAll())
self.readLocalFile(QUrl.fromLocalFile(tmp.name), add_to_recent_files=False)
def on_error(*args, **kwargs):
Logger.log("w", "Could not download file from {0}".format(model_url.url()))
Message("Could not download file: " + str(model_url.url()),
title= "Loading Model failed",
message_type=Message.MessageType.ERROR).show()
return
self.getHttpRequestManager().get(
model_url.url(),
callback=on_finish,
error_callback=on_error,
)
case path:
Logger.log("w", "Unsupported url scheme path: {0}".format(path))
def _addProfileReader(self, profile_reader):
# TODO: Add the profile reader to the list of plug-ins that can be used when importing profiles.
pass
@ -1845,7 +1915,7 @@ class CuraApplication(QtApplication):
Logger.log("i", "Attempting to read file %s", file.toString())
if not file.isValid():
return
self._open_project_mode = project_mode
scene = self.getController().getScene()
for node in DepthFirstIterator(scene.getRoot()):
@ -1855,16 +1925,16 @@ class CuraApplication(QtApplication):
is_project_file = self.checkIsValidProjectFile(file)
if project_mode is None:
project_mode = self.getPreferences().getValue("cura/choice_on_open_project")
if self._open_project_mode is None:
self._open_project_mode = self.getPreferences().getValue("cura/choice_on_open_project")
if is_project_file and project_mode == "open_as_project":
if is_project_file and self._open_project_mode == "open_as_project":
# open as project immediately without presenting a dialog
workspace_handler = self.getWorkspaceFileHandler()
workspace_handler.readLocalFile(file, add_to_recent_files_hint = add_to_recent_files)
return
if is_project_file and project_mode == "always_ask":
if is_project_file and self._open_project_mode == "always_ask":
# present a dialog asking to open as project or import models
self.callLater(self.openProjectFile.emit, file, add_to_recent_files)
return
@ -1999,8 +2069,11 @@ class CuraApplication(QtApplication):
center_y = 0
node.translate(Vector(0, center_y, 0))
nodes_to_arrange.append(node)
# If the file is a project,and models are to be loaded from a that project,
# models inside file should be arranged in buildplate.
elif self._open_project_mode == "open_as_model":
nodes_to_arrange.append(node)
# This node is deep copied from some other node which already has a BuildPlateDecorator, but the deepcopy
# of BuildPlateDecorator produces one that's associated with build plate -1. So, here we need to check if

View file

@ -1,5 +1,6 @@
# Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import math
import numpy
from typing import Optional, cast
@ -66,7 +67,7 @@ class LayerPolygon:
# Buffering the colors shouldn't be necessary as it is not
# re-used and can save a lot of memory usage.
self._color_map = LayerPolygon.getColorMap()
self._colors = self._color_map[self._types] # type: numpy.ndarray
self._colors: numpy.ndarray = self._color_map[self._types]
# When type is used as index returns true if type == LayerPolygon.InfillType
# or type == LayerPolygon.SkinType
@ -74,8 +75,8 @@ class LayerPolygon:
# Should be generated in better way, not hardcoded.
self._is_infill_or_skin_type_map = numpy.array([0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0], dtype=bool)
self._build_cache_line_mesh_mask = None # type: Optional[numpy.ndarray]
self._build_cache_needed_points = None # type: Optional[numpy.ndarray]
self._build_cache_line_mesh_mask: Optional[numpy.ndarray] = None
self._build_cache_needed_points: Optional[numpy.ndarray] = None
def buildCache(self) -> None:
# For the line mesh we do not draw Infill or Jumps. Therefore those lines are filtered out.
@ -186,6 +187,11 @@ class LayerPolygon:
def types(self):
return self._types
@property
def lineLengths(self):
data_array = numpy.array(self._data)
return numpy.linalg.norm(data_array[1:] - data_array[:-1], axis=1)
@property
def data(self):
return self._data

View file

@ -61,6 +61,11 @@ class IntentCategoryModel(ListModel):
"The annealing profile requires post-processing in an oven after the print is finished. This profile retains the dimensional accuracy of the printed part after annealing and improves strength, stiffness, and thermal resistance.")
}
cls._translations["solid"] = {
"name": catalog.i18nc("@label", "Solid"),
"description": catalog.i18nc("@text",
"A highly dense and strong part but at a slower print time. Great for functional parts.")
}
return cls._translations
def __init__(self, intent_category: str) -> None:

View file

@ -57,8 +57,9 @@ class IntentSelectionModel(ListModel):
self._onChange()
_default_intent_categories = ["default", "visual", "engineering", "quick", "annealing"]
_icons = {"default": "GearCheck", "visual": "Visual", "engineering": "Nut", "quick": "SpeedOMeter", "annealing": "Anneal"}
_default_intent_categories = ["default", "visual", "engineering", "quick", "annealing", "solid"]
_icons = {"default": "GearCheck", "visual": "Visual", "engineering": "Nut", "quick": "SpeedOMeter",
"annealing": "Anneal", "solid": "Hammer"}
def _onContainerChange(self, container: ContainerInterface) -> None:
"""Updates the list of intents if an intent profile was added or removed."""

View file

@ -24,3 +24,8 @@ intent_translations["quick"] = {
"name": catalog.i18nc("@label", "Draft"),
"description": catalog.i18nc("@text", "The draft profile is designed to print initial prototypes and concept validation with the intent of significant print time reduction.")
}
intent_translations["solid"] = {
"name": catalog.i18nc("@label", "Solid"),
"description": catalog.i18nc("@text",
"A highly dense and strong part but at a slower print time. Great for functional parts.")
}

View file

@ -45,17 +45,17 @@ class PreviewPass(RenderPass):
This is useful to get a preview image of a scene taken from a different location as the active camera.
"""
def __init__(self, width: int, height: int) -> None:
def __init__(self, width: int, height: int, *, root: CuraSceneNode = None) -> None:
super().__init__("preview", width, height, 0)
self._camera = None # type: Optional[Camera]
self._camera: Optional[Camera] = None
self._renderer = Application.getInstance().getRenderer()
self._shader = None # type: Optional[ShaderProgram]
self._non_printing_shader = None # type: Optional[ShaderProgram]
self._support_mesh_shader = None # type: Optional[ShaderProgram]
self._scene = Application.getInstance().getController().getScene()
self._shader: Optional[ShaderProgram] = None
self._non_printing_shader: Optional[ShaderProgram] = None
self._support_mesh_shader: Optional[ShaderProgram] = None
self._root = Application.getInstance().getController().getScene().getRoot() if root is None else root
# Set the camera to be used by this render pass
# if it's None, the active camera is used
@ -96,7 +96,7 @@ class PreviewPass(RenderPass):
batch_support_mesh = RenderBatch(self._support_mesh_shader)
# Fill up the batch with objects that can be sliced.
for node in DepthFirstIterator(self._scene.getRoot()):
for node in DepthFirstIterator(self._root):
if hasattr(node, "_outside_buildarea") and not getattr(node, "_outside_buildarea"):
if node.callDecoration("isSliceable") and node.getMeshData() and node.isVisible():
per_mesh_stack = node.callDecoration("getStack")

View file

@ -43,7 +43,7 @@ class MaterialOutputModel(QObject):
}
if guid is None and brand is not "empty" and type in _MATERIAL_MAP:
if guid is None and brand != "empty" and type in _MATERIAL_MAP:
name = _MATERIAL_MAP[type]["name"]
guid = _MATERIAL_MAP[type]["guid"]
return name, guid

View file

@ -10,13 +10,16 @@ class VariantDatabaseHandler(DatabaseMetadataContainerController):
"""The Database handler for Variant containers"""
def __init__(self):
super().__init__(SQLQueryFactory(table = "variant",
fields = {
"id": "text",
"name": "text",
"hardware_type": "text",
"definition": "text",
"version": "text",
"setting_version": "text"
}))
super().__init__(SQLQueryFactory(
table="variant",
fields={
"id": "text",
"name": "text",
"hardware_type": "text",
"definition": "text",
"version": "text",
"setting_version": "text",
"reference_extruder_id": "text",
},
))
self._container_type = InstanceContainer

View file

@ -48,6 +48,8 @@ from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
from cura.Settings.GlobalStack import GlobalStack
if TYPE_CHECKING:
from PyQt6.QtCore import QVariantList
from cura.CuraApplication import CuraApplication
from cura.Machines.MaterialNode import MaterialNode
from cura.Machines.QualityChangesGroup import QualityChangesGroup
@ -581,6 +583,10 @@ class MachineManager(QObject):
def activeMachine(self) -> Optional["GlobalStack"]:
return self._global_container_stack
@pyqtProperty("QVariantList", notify=activeVariantChanged)
def activeMachineExtruders(self) -> Optional["QVariantList"]:
return self._global_container_stack.extruderList if self._global_container_stack else None
@pyqtProperty(str, notify = activeStackChanged)
def activeStackId(self) -> str:
if self._active_container_stack:

View file

@ -37,15 +37,24 @@ class Snapshot:
return min_x, max_x, min_y, max_y
@staticmethod
def isometricSnapshot(width: int = 300, height: int = 300) -> Optional[QImage]:
"""Create an isometric snapshot of the scene."""
def isometricSnapshot(width: int = 300, height: int = 300, *, node: Optional[SceneNode] = None) -> Optional[QImage]:
"""
Create an isometric snapshot of the scene.
root = Application.getInstance().getController().getScene().getRoot()
:param width: width of the aspect ratio default 300
:param height: height of the aspect ratio default 300
:param node: node of the scene default is the root of the scene
:return: None when there is no model on the build plate otherwise it will return an image
"""
if node is None:
node = Application.getInstance().getController().getScene().getRoot()
# the direction the camera is looking at to create the isometric view
iso_view_dir = Vector(-1, -1, -1).normalized()
bounds = Snapshot.nodeBounds(root)
bounds = Snapshot.nodeBounds(node)
if bounds is None:
Logger.log("w", "There appears to be nothing to render")
return None
@ -93,7 +102,7 @@ class Snapshot:
# Render the scene
renderer = QtRenderer()
render_pass = PreviewPass(width, height)
render_pass = PreviewPass(width, height, root=node)
renderer.setViewportSize(width, height)
renderer.setWindowSize(width, height)
render_pass.setCamera(camera)

View file

@ -38,6 +38,7 @@ AppDir:
- usr/share/doc/*/changelog.*
- usr/share/doc/*/NEWS.*
- usr/share/doc/*/TODO.*
- usr/lib/x86_64-linux-gnu/libssl.so*
runtime:
env:
APPDIR_LIBRARY_PATH: "$APPDIR:$APPDIR/runtime/compat/:$APPDIR/usr/lib/x86_64-linux-gnu:$APPDIR/lib/x86_64-linux-gnu:$APPDIR/usr/lib:$APPDIR/usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders"

View file

@ -144,6 +144,23 @@ SectionEnd
######################################################################
Section UrlProtocol
WriteRegStr HKCR "cura" "" "URL:cura"
WriteRegStr HKCR "cura" "URL Protocol" ""
WriteRegStr HKCR "cura\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE},1"
WriteRegStr HKCR "cura\shell" "" "open"
WriteRegStr HKCR "cura\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}" "%1"'
WriteRegStr HKCR "slicer" "" "URL:slicer"
WriteRegStr HKCR "slicer" "URL Protocol" ""
WriteRegStr HKCR "slicer\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE},1"
WriteRegStr HKCR "slicer\shell" "" "open"
WriteRegStr HKCR "slicer\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}" "%1"'
SectionEnd
######################################################################
Section Uninstall
${INSTALL_TYPE}{% for files in mapped_out_paths.values() %}{% for file in files %}
Delete "{{ file[1] }}"{% endfor %}{% endfor %}{% for rem_dir in rmdir_paths %}
@ -187,8 +204,13 @@ RmDir "$SMPROGRAMS\{{ app_name }}"
!insertmacro APP_UNASSOCIATE "stl" "Cura.model"
!insertmacro APP_UNASSOCIATE "3mf" "Cura.project"
; Unassociate file associations for 'cura' protocol
DeleteRegKey HKCR "cura"
; Unassociate file associations for 'slicer' protocol
DeleteRegKey HKCR "slicer"
DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}"
DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}"
SectionEnd
######################################################################

View file

@ -33,6 +33,21 @@
/>
</Upgrade>
<Property Id="ASSOCIATE_URL_PROTOCOLS">
<RegistrySearch Id="CheckCuraProtocolHandler"
Type="raw"
Root="HKCR"
Key="cura"
Name="URL Protocol"
/>
<RegistrySearch Id="CheckSlicerProtocolHandler"
Type="raw"
Root="HKCR"
Key="slicer"
Name="URL Protocol"
/>
</Property>
{% if "Enterprise" in app_name %}
<Property Id="PREVIOUS_413_INSTALLED" Secure="yes" />
<Upgrade Id="53C603BB-2B17-4206-A609-29C2E0D0B0AE">
@ -144,11 +159,32 @@
</Component>
</DirectoryRef>
<!--Url Scheme-->
<Component Id="CuraRegistration" Guid="*" Directory="APPLICATIONFOLDER">
<RegistryKey Root="HKCR" Key="cura">
<RegistryValue Type="string" Value="URL:Cura Protocol"/>
<RegistryValue Type="string" Name="URL Protocol" Value=""/>
<RegistryValue Type="string" Key="DefaultIcon" Value="[APPLICATIONFOLDER]\{{ main_app }},1"/>
<RegistryValue Type="string" Key="shell\open\command" Value="&quot;[APPLICATIONFOLDER]\{{ main_app }}&quot; &quot;%1&quot;"/>
</RegistryKey>
</Component>
<Component Id="SlicerRegistration" Guid="*" Directory="APPLICATIONFOLDER">
<RegistryKey Root="HKCR" Key="slicer">
<RegistryValue Type="string" Value="URL:Slicer Protocol"/>
<RegistryValue Type="string" Name="URL Protocol" Value=""/>
<RegistryValue Type="string" Key="DefaultIcon" Value="[APPLICATIONFOLDER]\{{ main_app }},1"/>
<RegistryValue Type="string" Key="shell\open\command" Value="&quot;[APPLICATIONFOLDER]\{{ main_app }}&quot; &quot;%1&quot;"/>
</RegistryKey>
</Component>
<Feature Id="ProductFeature" Title="{{ app_name }}" Level="1" ConfigurableDirectory="APPLICATIONFOLDER">
<ComponentRef Id="CMP_UltiMaker_Cura_exe" />
<ComponentRef Id="CMP_CuraEngine_exe" />
<ComponentGroupRef Id="NewFilesGroup" />
<ComponentRef Id="CMP_Shortcuts" />
<ComponentRef Id="CuraRegistration"/>
<ComponentRef Id="SlicerRegistration"/>
</Feature>
<Feature Id="UninstallOlderVersionFeature" Title="Uninstall previous versions" Level="{{ 1 if "Enterprise" in app_name else 0 }}" Description="..."/>
</Product>

View file

@ -233,8 +233,7 @@ class ThreeMFReader(MeshReader):
if mesh_data is not None:
extents = mesh_data.getExtents()
if extents is not None:
# We use a different coordinate space, so flip Z and Y
center_vector = Vector(extents.center.x, extents.center.z, extents.center.y)
center_vector = Vector(extents.center.x, extents.center.y, extents.center.z)
transform_matrix.setByTranslation(center_vector)
transform_matrix.multiply(um_node.getLocalTransformation())
um_node.setTransformation(transform_matrix)

View file

@ -606,7 +606,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
self._dialog.setNumVisibleSettings(num_visible_settings)
self._dialog.setQualityName(quality_name)
self._dialog.setQualityType(quality_type)
self._dialog.setIntentName(intent_name)
self._dialog.setIntentName(intent_category)
self._dialog.setNumSettingsOverriddenByQualityChanges(num_settings_overridden_by_quality_changes)
self._dialog.setNumUserSettings(num_user_settings)
self._dialog.setActiveMode(active_mode)

View file

@ -6,6 +6,7 @@ from PyQt6.QtGui import QDesktopServices
from typing import List, Optional, Dict, cast
from cura.Machines.Models.MachineListModel import MachineListModel
from cura.Machines.Models.IntentTranslations import intent_translations
from cura.Settings.GlobalStack import GlobalStack
from UM.Application import Application
from UM.FlameProfiler import pyqtSlot
@ -223,7 +224,14 @@ class WorkspaceDialog(QObject):
def setIntentName(self, intent_name: str) -> None:
if self._intent_name != intent_name:
self._intent_name = intent_name
try:
self._intent_name = intent_translations[intent_name]["name"]
except:
self._intent_name = intent_name.title()
self.intentNameChanged.emit()
if not self._intent_name:
self._intent_name = intent_translations["default"]["name"]
self.intentNameChanged.emit()
@pyqtProperty(str, notify=activeModeChanged)

View file

@ -102,12 +102,20 @@ class ThreeMFWriter(MeshWriter):
savitar_node = Savitar.SceneNode()
savitar_node.setName(um_node.getName())
node_matrix = um_node.getLocalTransformation()
node_matrix = Matrix()
mesh_data = um_node.getMeshData()
# compensate for original center position, if object(s) is/are not around its zero position
if mesh_data is not None:
extents = mesh_data.getExtents()
if extents is not None:
# We use a different coordinate space while writing, so flip Z and Y
center_vector = Vector(extents.center.x, extents.center.z, extents.center.y)
node_matrix.setByTranslation(center_vector)
node_matrix.multiply(um_node.getLocalTransformation())
matrix_string = ThreeMFWriter._convertMatrixToString(node_matrix.preMultiply(transformation))
savitar_node.setTransformation(matrix_string)
mesh_data = um_node.getMeshData()
if mesh_data is not None:
savitar_node.getMeshData().setVerticesFromBytes(mesh_data.getVerticesAsByteArray())
indices_array = mesh_data.getIndicesAsByteArray()

View file

@ -33,6 +33,8 @@ message Slice
repeated Extruder extruders = 3; // The settings sent to each extruder object
repeated SettingExtruder limit_to_extruder = 4; // From which stack the setting would inherit if not defined per object
repeated EnginePlugin engine_plugins = 5;
string sentry_id = 6; // The anonymized Sentry user id that requested the slice
string cura_version = 7; // The version of Cura that requested the slice
}
message Extruder

View file

@ -163,6 +163,7 @@ class CuraEngineBackend(QObject, Backend):
self._is_disabled: bool = False
application.getPreferences().addPreference("general/auto_slice", False)
application.getPreferences().addPreference("info/send_engine_crash", True)
self._use_timer: bool = False
@ -173,6 +174,8 @@ class CuraEngineBackend(QObject, Backend):
self._change_timer.setSingleShot(True)
self._change_timer.setInterval(500)
self.determineAutoSlicing()
application.getPreferences().preferenceChanged.connect(self._onPreferencesChanged)
self._slicing_error_message = Message(
@ -193,6 +196,9 @@ class CuraEngineBackend(QObject, Backend):
application.initializationFinished.connect(self.initialize)
# Ensure that the initial value for send_engine_crash is handled correctly.
application.callLater(self._onPreferencesChanged, "info/send_engine_crash")
def startPlugins(self) -> None:
"""
Ensure that all backend plugins are started
@ -1088,11 +1094,14 @@ class CuraEngineBackend(QObject, Backend):
self._change_timer.timeout.disconnect(self.slice)
def _onPreferencesChanged(self, preference: str) -> None:
if preference != "general/auto_slice":
if preference != "general/auto_slice" and preference != "info/send_engine_crash":
return
auto_slice = self.determineAutoSlicing()
if auto_slice:
self._change_timer.start()
if preference == "general/auto_slice":
auto_slice = self.determineAutoSlicing()
if auto_slice:
self._change_timer.start()
elif preference == "info/send_engine_crash":
os.environ["use_sentry"] = "1" if CuraApplication.getInstance().getPreferences().getValue("info/send_engine_crash") else "0"
def tickle(self) -> None:
"""Tickle the backend so in case of auto slicing, it starts the timer."""

View file

@ -1,12 +1,14 @@
# Copyright (c) 2023 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
import uuid
import os
import numpy
from string import Formatter
from enum import IntEnum
import time
from typing import Any, cast, Dict, List, Optional, Set
from typing import Any, cast, Dict, List, Optional, Set, Tuple
import re
import pyArcus as Arcus # For typing.
from PyQt6.QtCore import QCoreApplication
@ -30,6 +32,7 @@ from cura.CuraApplication import CuraApplication
from cura.Scene.CuraSceneNode import CuraSceneNode
from cura.OneAtATimeIterator import OneAtATimeIterator
from cura.Settings.ExtruderManager import ExtruderManager
from cura.CuraVersion import CuraVersion
NON_PRINTING_MESH_SETTINGS = ["anti_overhang_mesh", "infill_mesh", "cutting_mesh"]
@ -68,7 +71,23 @@ class GcodeStartEndFormatter(Formatter):
self._default_extruder_nr: int = default_extruder_nr
self._additional_per_extruder_settings: Optional[Dict[str, Dict[str, any]]] = additional_per_extruder_settings
def get_field(self, field_name, args: [str], kwargs: dict) -> Tuple[str, str]:
# get_field method parses all fields in the format-string and parses them individually to the get_value method.
# e.g. for a string "Hello {foo.bar}" would the complete field "foo.bar" would be passed to get_field, and then
# the individual parts "foo" and "bar" would be passed to get_value. This poses a problem for us, because want
# to parse the entire field as a single expression. To solve this, we override the get_field method and return
# the entire field as the expression.
return self.get_value(field_name, args, kwargs), field_name
def get_value(self, expression: str, args: [str], kwargs: dict) -> str:
# The following variables are not settings, but only become available after slicing.
# when these variables are encountered, we return them as-is. They are replaced later
# when the actual values are known.
post_slice_data_variables = ["filament_cost", "print_time", "filament_amount", "filament_weight", "jobname"]
if expression in post_slice_data_variables:
return f"{{{expression}}}"
extruder_nr = self._default_extruder_nr
# The settings may specify a specific extruder to use. This is done by
@ -102,6 +121,7 @@ class GcodeStartEndFormatter(Formatter):
setting_function = SettingFunction(expression)
value = setting_function(container_stack, additional_variables=additional_variables)
return value
@ -315,6 +335,11 @@ class StartSliceJob(Job):
self._buildGlobalSettingsMessage(stack)
self._buildGlobalInheritsStackMessage(stack)
user_id = uuid.getnode() # On all of Cura's supported platforms, this returns the MAC address which is pseudonymical information (!= anonymous).
user_id %= 2 ** 16 # So to make it anonymous, apply a bitmask selecting only the last 16 bits. This prevents it from being traceable to a specific user but still gives somewhat of an idea of whether it's just the same user hitting the same crash over and over again, or if it's widespread.
self._slice_message.sentry_id = f"{user_id}"
self._slice_message.cura_version = CuraVersion
# Build messages for extruder stacks
for extruder_stack in global_stack.extruderList:
self._buildExtruderMessage(extruder_stack)

View file

@ -139,6 +139,34 @@ Item
decimals: 0
forceUpdateOnChangeFunction: forceUpdateFunction
}
Cura.NumericTextFieldWithUnit
{
id: extruderStartCodeDurationFieldId
containerStackId: base.extruderStackId
settingKey: "machine_extruder_start_code_duration"
settingStoreIndex: propertyStoreIndex
labelText: catalog.i18nc("@label", "Extruder Start G-code duration")
labelFont: base.labelFont
labelWidth: base.labelWidth
controlWidth: base.controlWidth
unitText: catalog.i18nc("@label", "s")
forceUpdateOnChangeFunction: forceUpdateFunction
}
Cura.NumericTextFieldWithUnit
{
id: extruderEndCodeDurationFieldId
containerStackId: base.extruderStackId
settingKey: "machine_extruder_end_code_duration"
settingStoreIndex: propertyStoreIndex
labelText: catalog.i18nc("@label", "Extruder End G-code duration")
labelFont: base.labelFont
labelWidth: base.labelWidth
controlWidth: base.controlWidth
unitText: catalog.i18nc("@label", "s")
forceUpdateOnChangeFunction: forceUpdateFunction
}
}
}

View file

@ -50,59 +50,6 @@ class MakerbotWriter(MeshWriter):
{"prefix": "thumbnail", "width": 90, "height": 90},
]
_META_VERSION = "3.0.0"
_PRINT_NAME_MAP = {
"Makerbot Method": "fire_e",
"Makerbot Method X": "lava_f",
"Makerbot Method XL": "magma_10",
}
_EXTRUDER_NAME_MAP = {
"1XA": "mk14_hot",
"2XA": "mk14_hot_s",
"1C": "mk14_c",
"1A": "mk14",
"2A": "mk14_s",
}
_MATERIAL_MAP = {"2780b345-577b-4a24-a2c5-12e6aad3e690": "abs",
"88c8919c-6a09-471a-b7b6-e801263d862d": "abs-wss1",
"416eead4-0d8e-4f0b-8bfc-a91a519befa5": "asa",
"85bbae0e-938d-46fb-989f-c9b3689dc4f0": "nylon-cf",
"283d439a-3490-4481-920c-c51d8cdecf9c": "nylon",
"62414577-94d1-490d-b1e4-7ef3ec40db02": "pc",
"69386c85-5b6c-421a-bec5-aeb1fb33f060": "petg",
"0ff92885-617b-4144-a03c-9989872454bc": "pla",
"a4255da2-cb2a-4042-be49-4a83957a2f9a": "pva",
"a140ef8f-4f26-4e73-abe0-cfc29d6d1024": "wss1",
"77873465-83a9-4283-bc44-4e542b8eb3eb": "sr30",
"96fca5d9-0371-4516-9e96-8e8182677f3c": "im-pla",
"9f52c514-bb53-46a6-8c0c-d507cd6ee742": "abs",
"0f9a2a91-f9d6-4b6b-bd9b-a120a29391be": "abs",
"d3e972f2-68c0-4d2f-8cfd-91028dfc3381": "abs",
"495a0ce5-9daf-4a16-b7b2-06856d82394d": "abs-cf10",
"cb76bd6e-91fd-480c-a191-12301712ec77": "abs-wss1",
"a017777e-3f37-4d89-a96c-dc71219aac77": "abs-wss1",
"4d96000d-66de-4d54-a580-91827dcfd28f": "abs-wss1",
"0ecb0e1a-6a66-49fb-b9ea-61a8924e0cf5": "asa",
"efebc2ea-2381-4937-926f-e824524524a5": "asa",
"b0199512-5714-4951-af85-be19693430f8": "asa",
"b9f55a0a-a2b6-4b8d-8d48-07802c575bd1": "pla",
"c439d884-9cdc-4296-a12c-1bacae01003f": "pla",
"16a723e3-44df-49f4-82ec-2a1173c1e7d9": "pla",
"74d0f5c2-fdfd-4c56-baf1-ff5fa92d177e": "pla",
"64dcb783-470d-4400-91b1-7001652f20da": "pla",
"3a1b479b-899c-46eb-a2ea-67050d1a4937": "pla",
"4708ac49-5dde-4cc2-8c0a-87425a92c2b3": "pla",
"4b560eda-1719-407f-b085-1c2c1fc8ffc1": "pla",
"e10a287d-0067-4a58-9083-b7054f479991": "im-pla",
"01a6b5b0-fab1-420c-a5d9-31713cbeb404": "im-pla",
"f65df4ad-a027-4a48-a51d-975cc8b87041": "im-pla",
"f48739f8-6d96-4a3d-9a2e-8505a47e2e35": "im-pla",
"5c7d7672-e885-4452-9a78-8ba90ec79937": "petg",
"91e05a6e-2f5b-4964-b973-d83b5afe6db4": "petg",
"bdc7dd03-bf38-48ee-aeca-c3e11cee799e": "petg",
"54f66c89-998d-4070-aa60-1cb0fd887518": "nylon",
"002c84b3-84ac-4b5a-b57d-fe1f555a6351": "pva",
"e4da5fcb-f62d-48a2-aaef-0b645aa6973b": "wss1",
"77f06146-6569-437d-8380-9edb0d635a32": "sr30"}
# must be called from the main thread because of OpenGL
@staticmethod
@ -197,7 +144,7 @@ class MakerbotWriter(MeshWriter):
meta = dict()
meta["bot_type"] = MakerbotWriter._PRINT_NAME_MAP.get((name := global_stack.definition.name), name)
meta["bot_type"] = global_stack.definition.getMetaDataEntry("reference_machine_id")
bounds: Optional[AxisAlignedBox] = None
for node in nodes:
@ -239,12 +186,7 @@ class MakerbotWriter(MeshWriter):
meta["uuid"] = print_information.slice_uuid
materials = []
for extruder in extruders:
guid = extruder.material.getMetaData().get("GUID")
material_name = extruder.material.getMetaData().get("material")
material = self._MATERIAL_MAP.get(guid, material_name)
materials.append(material)
materials = [extruder.material.getMetaData().get("reference_material_id") for extruder in extruders]
meta["material"] = materials[0]
meta["materials"] = materials
@ -256,8 +198,7 @@ class MakerbotWriter(MeshWriter):
meta["model_counts"] = [{"count": 1, "name": node.getName()} for node in nodes]
tool_types = [MakerbotWriter._EXTRUDER_NAME_MAP.get((name := extruder.variant.getName()), name) for extruder in
extruders]
tool_types = [extruder.variant.getMetaDataEntry("reference_extruder_id") for extruder in extruders]
meta["tool_type"] = tool_types[0]
meta["tool_types"] = tool_types
@ -273,23 +214,29 @@ class MakerbotWriter(MeshWriter):
meta["miracle_config"] = {"gaggles": {str(node.getName()): {} for node in nodes}}
version_info = dict()
cura_engine_info = ConanInstalls.get("curaengine", {"version": "unknown", "revision": "unknown"})
meta["curaengine_version"] = cura_engine_info["version"]
meta["curaengine_commit_hash"] = cura_engine_info["revision"]
version_info["curaengine_version"] = cura_engine_info["version"]
version_info["curaengine_commit_hash"] = cura_engine_info["revision"]
dulcificum_info = ConanInstalls.get("dulcificum", {"version": "unknown", "revision": "unknown"})
meta["dulcificum_version"] = dulcificum_info["version"]
meta["dulcificum_commit_hash"] = dulcificum_info["revision"]
version_info["dulcificum_version"] = dulcificum_info["version"]
version_info["dulcificum_commit_hash"] = dulcificum_info["revision"]
meta["makerbot_writer_version"] = self.getVersion()
meta["pyDulcificum_version"] = du.__version__
version_info["makerbot_writer_version"] = self.getVersion()
version_info["pyDulcificum_version"] = du.__version__
# Add engine plugin information to the metadata
for name, package_info in ConanInstalls.items():
if not name.startswith("curaengine_"):
continue
meta[f"{name}_version"] = package_info["version"]
meta[f"{name}_commit_hash"] = package_info["revision"]
version_info[f"{name}_version"] = package_info["version"]
version_info[f"{name}_commit_hash"] = package_info["revision"]
# Add version info to the main metadata, but also to "miracle_config"
# so that it shows up in analytics
meta["miracle_config"].update(version_info)
meta.update(version_info)
# TODO add the following instructions
# num_tool_changes

View file

@ -0,0 +1,837 @@
# Designed in January 2023 by GregValiant (Greg Foresi)
## My design intent was to make this as full featured and "industrial strength" as I could. People printing exotic materials on large custom printers may want to turn the fans off for certain layers, and then back on again later in the print. This script allows that.
# Functions:
## Remove all fan speed lines from the file (optional). This should be enabled for the first instance of the script. It is disabled by default in any following instances.
## "By Layer" allows the user to adjust the fan speed up, or down, or off, within the print. "By Feature" allows different fan speeds for different features (;TYPE:WALL-OUTER, etc.).
## If 'By Feature' then a Start Layer and/or an End Layer can be defined.
## Fan speeds are scaled PWM (0 - 255) or RepRap (0.0 - 1.0) depending on {machine_scale_fan_speed_zero_to_one}.
## A minimum fan speed of 12% is enforced. It is the slowest speed that my cooling fan will turn on so that's what I used. 'M106 S14' (as Cura might insert) was pretty useless.
## If multiple extruders have separate fan circuits the speeds are set at tool changes and conform to the layer or feature setting. There is support for up to 4 layer cooling fan circuits.
## My thanks to @5axes(@CUQ), @fieldOfView(@AHoeben), @Ghostkeeper, and @Torgeir. A special thanks to @RBurema for his patience in reviewing my 'non-pythonic' script.
## 9/14/23 (Greg Foresi) Added support for One-at-a-Time print sequence.
## 12/15/23 (Greg Foresi) Split off 'Single Fan By Layer', 'Multi-fan By Layer', 'Single Fan By Feature', and 'Multi-fan By Feature' from the main 'execute' script.
## 1/5/24 (Greg Foresi) Revised the regex replacements.
from ..Script import Script
from UM.Application import Application
import re
class AddCoolingProfile(Script):
def getSettingDataString(self):
return """{
"name": "Advanced Cooling Fan Control",
"key": "AddCoolingProfile",
"metadata": {},
"version": 2,
"settings":
{
"fan_layer_or_feature":
{
"label": "Cooling Control by:",
"description": "A fan percentage of ''0'' turns the fan off. Minimum Fan is 12% (when on). All layer entries are the Cura Preview number. ''By Layer'': Enter as ''Layer#/Fan%'' (foreslash is the delimiter). Your final layer speed will continue to the end of the Gcode. ''By Feature'': If you enable an 'End Layer' then the ''Final %'' is available and is the speed that will finish the file. 'By Feature' is better for large slow prints than it is for short fast prints.",
"type": "enum",
"options": {
"by_layer": "Layer Numbers",
"by_feature": "Feature Types"},
"default_value": "by_layer"
},
"delete_existing_m106":
{
"label": "Remove M106 lines prior to inserting new.",
"description": "If you have 2 or more instances of 'Advanced Cooling Fan Control' running (to cool a portion of a print differently), then you must uncheck this box or the followup instances will remove all the lines inserted by the first instance. Pay attention to the Start and Stop layers. Regardless of this setting: The script always removes M106 lines starting with the lowest layer number (when 'By Layer') or the starting layer number (when 'By Feature'). If you want to keep the M106 lines that Cura inserted up to the point where this post-processor will start making insertions, then un-check the box.",
"type": "bool",
"enabled": true,
"value": true,
"default_value": true
},
"feature_fan_start_layer":
{
"label": "Starting Layer",
"description": "Layer to start the insertion at. Use the Cura preview numbers. Changes will begin at the start of that layer.",
"type": "int",
"default_value": 5,
"minimum_value": 1,
"unit": "Lay# ",
"enabled": "fan_layer_or_feature == 'by_feature'"
},
"feature_fan_end_layer":
{
"label": "Ending Layer",
"description": "Layer to complete the insertion at. Enter '-1' for the entire file or enter a layer number. Insertions will stop at the END of this layer. If you set an End Layer then you should set the Final % that will finish the file",
"type": "int",
"default_value": -1,
"minimum_value": -1,
"unit": "Lay# ",
"enabled": "fan_layer_or_feature == 'by_feature'"
},
"layer_fan_1":
{
"label": "Layer/Percent #1",
"description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage. There are up to 8 changes. If you need more then add a second instance of this script and remember to turn off 'Remove M106 lines' in the second instance. The layer numbers in the second instance must start with a layer number higher than the last layer number in a previous script. You can't end the first script with a setting for layer 80 and then start the second script with a setting for layer 40 because 'Remove M106 lines' always starts with the lowest layer number when 'By Layer' is selected.",
"type": "str",
"default_value": "5/30",
"unit": "L#/% ",
"enabled": "fan_layer_or_feature == 'by_layer'"
},
"layer_fan_2":
{
"label": "Layer/Percent #2",
"description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage.",
"type": "str",
"default_value": "",
"unit": "L#/% ",
"enabled": "fan_layer_or_feature == 'by_layer'"
},
"layer_fan_3":
{
"label": "Layer/Percent #3",
"description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage.",
"type": "str",
"default_value": "",
"unit": "L#/% ",
"enabled": "fan_layer_or_feature == 'by_layer'"
},
"layer_fan_4":
{
"label": "Layer/Percent #4",
"description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage.",
"type": "str",
"default_value": "",
"unit": "L#/% ",
"enabled": "fan_layer_or_feature == 'by_layer'"
},
"layer_fan_5":
{
"label": "Layer/Percent #5",
"description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage.",
"type": "str",
"default_value": "",
"unit": "L#/% ",
"enabled": "fan_layer_or_feature == 'by_layer'"
},
"layer_fan_6":
{
"label": "Layer/Percent #6",
"description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage.",
"type": "str",
"default_value": "",
"unit": "L#/% ",
"enabled": "fan_layer_or_feature == 'by_layer'"
},
"layer_fan_7":
{
"label": "Layer/Percent #7",
"description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage.",
"type": "str",
"default_value": "",
"unit": "L#/% ",
"enabled": "fan_layer_or_feature == 'by_layer'"
},
"layer_fan_8":
{
"label": "Layer/Percent #8",
"description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage.",
"type": "str",
"default_value": "",
"unit": "L#/% ",
"enabled": "fan_layer_or_feature == 'by_layer'"
},
"feature_fan_skirt":
{
"label": "Skirt/Brim/Ooze Shield %",
"description": "Enter the fan percentage for skirt/brim. If you are starting at a layer above 1 then this setting only affects Ooze Shields and from the Start Layer up.",
"type": "int",
"default_value": 0,
"minimum_value": 0,
"maximum_value": 100,
"unit": "% ",
"enabled": "fan_layer_or_feature == 'by_feature'"
},
"feature_fan_wall_inner":
{
"label": "Inner Walls %",
"description": "Enter the fan percentage for the Wall-Inner.",
"type": "int",
"default_value": 35,
"minimum_value": 0,
"maximum_value": 100,
"unit": "% ",
"enabled": "fan_layer_or_feature == 'by_feature'"
},
"feature_fan_wall_outer":
{
"label": "Outer Walls %",
"description": "Enter the fan percentage for the Wall-Outer.",
"type": "int",
"default_value": 75,
"minimum_value": 0,
"maximum_value": 100,
"unit": "% ",
"enabled": "fan_layer_or_feature == 'by_feature'"
},
"feature_fan_fill":
{
"label": "Infill %",
"description": "Enter the fan percentage for the Infill.",
"type": "int",
"default_value": 35,
"minimum_value": 0,
"maximum_value": 100,
"unit": "% ",
"enabled": "fan_layer_or_feature == 'by_feature'"
},
"feature_fan_skin":
{
"label": "Top/Bottom (Skin) %",
"description": "Enter the fan percentage for the Skins.",
"type": "int",
"default_value": 100,
"minimum_value": 0,
"maximum_value": 100,
"unit": "% ",
"enabled": "fan_layer_or_feature == 'by_feature'"
},
"feature_fan_support":
{
"label": "Support %",
"description": "Enter the fan percentage for the Supports.",
"type": "int",
"default_value": 35,
"minimum_value": 0,
"maximum_value": 100,
"unit": "% ",
"enabled": "fan_layer_or_feature == 'by_feature'"
},
"feature_fan_support_interface":
{
"label": "Support Interface %",
"description": "Enter the fan percentage for the Support Interface.",
"type": "int",
"default_value": 100,
"minimum_value": 0,
"maximum_value": 100,
"unit": "% ",
"enabled": "fan_layer_or_feature == 'by_feature'"
},
"feature_fan_prime_tower":
{
"label": "Prime Tower %",
"description": "Enter the fan percentage for the Prime Tower (whether it's used or not).",
"type": "int",
"default_value": 35,
"minimum_value": 0,
"maximum_value": 100,
"unit": "% ",
"enabled": "fan_layer_or_feature == 'by_feature'"
},
"feature_fan_bridge":
{
"label": "Bridge %",
"description": "Enter the fan percentage for any Bridging (whether it's used on not).",
"type": "int",
"default_value": 100,
"minimum_value": 0,
"maximum_value": 100,
"unit": "% ",
"enabled": "fan_layer_or_feature == 'by_feature'"
},
"feature_fan_combing":
{
"label": "Fan 'OFF' during Combing:",
"description": "When checked will set the fan to 0% for combing moves over 5 lines long in the gcode. When un-checked the fan speed during combing is whatever the previous speed is set to.",
"type": "bool",
"enabled": "fan_layer_or_feature == 'by_feature'",
"default_value": true
},
"feature_fan_feature_final":
{
"label": "Final %",
"description": "If you choose an 'End Layer' then this is the fan speed that will carry through to the end of the gcode file. It will go into effect at the 'END' of your End layer.",
"type": "int",
"default_value": 35,
"minimum_value": 0,
"maximum_value": 100,
"unit": "% ",
"enabled": "(int(feature_fan_end_layer) != -1) and (fan_layer_or_feature == 'by_feature')"
},
"fan_enable_raft":
{
"label": "Enable Raft Cooling",
"description": "Enable the fan for the raft layers. When enabled the Raft Fan Speed will continue until another Layer or Feature setting over-rides it.",
"type": "bool",
"default_value": false,
"enabled": true
},
"fan_raft_percent":
{
"label": "Raft Fan %:",
"description": "Enter the percentage for the Raft.",
"type": "int",
"default_value": 35,
"minimum_value": 0,
"maximum_value": 100,
"unit": "% ",
"enabled": "fan_enable_raft"
}
}
}"""
def initialize(self) -> None:
super().initialize()
scripts = Application.getInstance().getGlobalContainerStack().getMetaDataEntry("post_processing_scripts")
if scripts != None:
script_count = scripts.count("AddCoolingProfile")
if script_count > 0:
## Set 'Remove M106 lines' to "false" if there is already an instance of this script running.
self._instance.setProperty("delete_existing_m106", "value", False)
def execute(self, data):
#Initialize variables that are buried in if statements.
mycura = Application.getInstance().getGlobalContainerStack()
t0_fan = " P0"; t1_fan = " P0"; t2_fan = " P0"; t3_fan = " P0"; is_multi_extr_print = True
#Get some information from Cura-----------------------------------
extruder = mycura.extruderList
#This will be true when fan scale is 0-255pwm and false when it's RepRap 0-1 (Cura 5.x)
fan_mode = True
##For 4.x versions that don't have the 0-1 option
try:
fan_mode = not bool(extruder[0].getProperty("machine_scale_fan_speed_zero_to_one", "value"))
except:
pass
bed_adhesion = (extruder[0].getProperty("adhesion_type", "value"))
extruder_count = mycura.getProperty("machine_extruder_count", "value")
print_sequence = str(mycura.getProperty("print_sequence", "value"))
#Assign the fan numbers to the tools------------------------------
if extruder_count == 1:
is_multi_fan = False
is_multi_extr_print = False
if int((extruder[0].getProperty("machine_extruder_cooling_fan_number", "value"))) > 0:
t0_fan = " P" + str((extruder[0].getProperty("machine_extruder_cooling_fan_number", "value")))
else:
#No P parameter if there is a single fan circuit------------------
t0_fan = ""
#Get the cooling fan numbers for each extruder if the printer has multiple extruders
elif extruder_count > 1:
is_multi_fan = True
t0_fan = " P" + str((extruder[0].getProperty("machine_extruder_cooling_fan_number", "value")))
if is_multi_fan:
if extruder_count > 1: t1_fan = " P" + str((extruder[1].getProperty("machine_extruder_cooling_fan_number", "value")))
if extruder_count > 2: t2_fan = " P" + str((extruder[2].getProperty("machine_extruder_cooling_fan_number", "value")))
if extruder_count > 3: t3_fan = " P" + str((extruder[3].getProperty("machine_extruder_cooling_fan_number", "value")))
#Initialize the fan_list with defaults----------------------------
fan_list = ["z"] * 16
for num in range(0,15,2):
fan_list[num] = len(data)
fan_list[num + 1] = "M106 S0"
#Assign the variable values if "By Layer"-------------------------
by_layer_or_feature = self.getSettingValueByKey("fan_layer_or_feature")
if by_layer_or_feature == "by_layer":
## By layer doesn't do any feature search so there is no need to look for combing moves
feature_fan_combing = False
fan_list[0] = self.getSettingValueByKey("layer_fan_1")
fan_list[2] = self.getSettingValueByKey("layer_fan_2")
fan_list[4] = self.getSettingValueByKey("layer_fan_3")
fan_list[6] = self.getSettingValueByKey("layer_fan_4")
fan_list[8] = self.getSettingValueByKey("layer_fan_5")
fan_list[10] = self.getSettingValueByKey("layer_fan_6")
fan_list[12] = self.getSettingValueByKey("layer_fan_7")
fan_list[14] = self.getSettingValueByKey("layer_fan_8")
## If there is no '/' delimiter then ignore the line else put the settings in a list
for num in range(0,15,2):
if "/" in fan_list[num]:
fan_list[num + 1] = self._layer_checker(fan_list[num], "p", fan_mode)
fan_list[num] = self._layer_checker(fan_list[num], "l", fan_mode)
## Assign the variable values if "By Feature"
elif by_layer_or_feature == "by_feature":
the_start_layer = self.getSettingValueByKey("feature_fan_start_layer") - 1
the_end_layer = self.getSettingValueByKey("feature_fan_end_layer")
try:
if int(the_end_layer) != -1:
## Catch a possible input error.
if the_end_layer < the_start_layer:
the_end_layer = the_start_layer
except:
the_end_layer = -1 ## If there is an input error default to the entire gcode file.
## Get the speed for each feature
feature_name_list = []
feature_speed_list = []
feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_skirt"), fan_mode)); feature_name_list.append(";TYPE:SKIRT")
feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_wall_inner"), fan_mode)); feature_name_list.append(";TYPE:WALL-INNER")
feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_wall_outer"), fan_mode)); feature_name_list.append(";TYPE:WALL-OUTER")
feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_fill"), fan_mode)); feature_name_list.append(";TYPE:FILL")
feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_skin"), fan_mode)); feature_name_list.append(";TYPE:SKIN")
feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_support"), fan_mode)); feature_name_list.append(";TYPE:SUPPORT")
feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_support_interface"), fan_mode)); feature_name_list.append(";TYPE:SUPPORT-INTERFACE")
feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_prime_tower"), fan_mode)); feature_name_list.append(";TYPE:PRIME-TOWER")
feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_bridge"), fan_mode)); feature_name_list.append(";BRIDGE")
feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_feature_final"), fan_mode)); feature_name_list.append("FINAL_FAN")
feature_fan_combing = self.getSettingValueByKey("feature_fan_combing")
if the_end_layer > -1 and by_layer_or_feature == "by_feature":
## Required so the final speed input can be determined
the_end_is_enabled = True
else:
## There is no ending layer so do the whole file
the_end_is_enabled = False
if the_end_layer == -1 or the_end_is_enabled == False:
the_end_layer = len(data) + 2
## Find the Layer0Index and the RaftIndex
raft_start_index = 0
number_of_raft_layers = 0
layer_0_index = 0
## Catch the number of raft layers.
for l_num in range(1,10,1):
layer = data[l_num]
if ";LAYER:-" in layer:
number_of_raft_layers += 1
if raft_start_index == 0:
raft_start_index = l_num
if ";LAYER:0" in layer:
layer_0_index = l_num
break
## Is this a single extruder print on a multi-extruder printer? - get the correct fan number for the extruder being used.
if is_multi_fan:
T0_used = False
T1_used = False
T2_used = False
T3_used = False
## Bypass the file header and ending gcode.
for num in range(1,len(data)-1,1):
lines = data[num]
if "T0" in lines:
T0_used = True
if "T1" in lines:
T1_used = True
if "T2" in lines:
T2_used = True
if "T3" in lines:
T3_used = True
is_multi_extr_print = True if sum([T0_used, T1_used, T2_used, T3_used]) > 1 else False
## On a multi-extruder printer and single extruder print find out which extruder starts the file.
init_fan = t0_fan
if not is_multi_extr_print:
startup = data[1]
lines = startup.split("\n")
for line in lines:
if line == "T1":
t0_fan = t1_fan
elif line == "T2":
t0_fan = t2_fan
elif line == "T3":
t0_fan = t3_fan
elif is_multi_extr_print:
## On a multi-extruder printer and multi extruder print find out which extruder starts the file.
startup = data[1]
lines = startup.split("\n")
for line in lines:
if line == "T0":
init_fan = t0_fan
elif line == "T1":
init_fan = t1_fan
elif line == "T2":
init_fan = t2_fan
elif line == "T3":
init_fan = t3_fan
else:
init_fan = ""
## Assign the variable values if "Raft Enabled"
raft_enabled = self.getSettingValueByKey("fan_enable_raft")
if raft_enabled and bed_adhesion == "raft":
fan_sp_raft = self._feature_checker(self.getSettingValueByKey("fan_raft_percent"), fan_mode)
else:
fan_sp_raft = "M106 S0"
# Start to alter the data-----------------------------------------
## Strip the existing M106 lines from the file up to the end of the last layer. If a user wants to use more than one instance of this plugin then they won't want to erase the M106 lines that the preceding plugins inserted so 'delete_existing_m106' is an option.
delete_existing_m106 = self.getSettingValueByKey("delete_existing_m106")
if delete_existing_m106:
## Start deleting from the beginning
start_from = int(raft_start_index)
else:
if by_layer_or_feature == "by_layer":
altered_start_layer = str(len(data))
## The fan list layers don't need to be in ascending order. Get the lowest.
for num in range(0,15,2):
try:
if int(fan_list[num]) < int(altered_start_layer):
altered_start_layer = int(fan_list[num])
except:
pass
elif by_layer_or_feature == "by_feature":
altered_start_layer = int(the_start_layer) - 1
start_from = int(layer_0_index) + int(altered_start_layer)
## Strip the M106 and M107 lines from the file
for l_index in range(int(start_from), len(data) - 1, 1):
data[l_index] = re.sub(re.compile("M106(.*)\n"), "", data[l_index])
data[l_index] = re.sub(re.compile("M107(.*)\n"), "", data[l_index])
## Deal with a raft and with One-At-A-Time print sequence
if raft_enabled and bed_adhesion == "raft":
if print_sequence == "one_at_a_time":
for r_index in range(2,len(data)-2,1):
lines = data[r_index].split("\n")
if not raft_enabled or bed_adhesion != "raft":
if ";LAYER:0" in data[r_index] or ";LAYER:-" in data[r_index]:
lines.insert(1, "M106 S0" + str(t0_fan))
if raft_enabled and bed_adhesion == "raft":
if ";LAYER:-" in data[r_index]:
## Turn the raft fan on
lines.insert(1, fan_sp_raft + str(t0_fan))
## Shut the raft fan off at layer 0
if ";LAYER:0" in data[r_index]:
lines.insert(1,"M106 S0" + str(t0_fan))
data[r_index] = "\n".join(lines)
elif print_sequence == "all_at_once":
layer = data[raft_start_index]
lines = layer.split("\n")
if ";LAYER:-" in layer:
## Turn the raft fan on
lines.insert(1, fan_sp_raft + str(init_fan))
layer = "\n".join(lines)
data[raft_start_index] = layer
layer = data[layer_0_index]
lines = layer.split("\n")
## Shut the raft fan off
lines.insert(1, "M106 S0" + str(init_fan))
data[layer_0_index] = "\n".join(lines)
else:
for r_index in range(2,len(data)-2,1):
lines = data[r_index].split("\n")
if ";LAYER:0" in data[r_index] or ";LAYER:-" in data[r_index]:
if not "0" in fan_list:
lines.insert(1, "M106 S0" + str(t0_fan))
data[r_index] = "\n".join(lines)
## Turn off all fans at the end of data[1]. If more than one instance of this script is running then this will result in multiple M106 lines.
temp_startup = data[1].split("\n")
temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t0_fan))
## If there are multiple cooling fans shut them all off
if is_multi_fan:
if extruder_count > 1 and t1_fan != t0_fan: temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t1_fan))
if extruder_count > 2 and t2_fan != t1_fan and t2_fan != t0_fan: temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t2_fan))
if extruder_count > 3 and t3_fan != t2_fan and t3_fan != t1_fan and t3_fan != t0_fan: temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t3_fan))
data[1] = "\n".join(temp_startup)
## If 'feature_fan_combing' is True then add additional 'MESH:NONMESH' lines for travel moves over 5 lines long
## For compatibility with 5.3.0 change any MESH:NOMESH to MESH:NONMESH.
if feature_fan_combing:
for layer_num in range(2,len(data)):
layer = data[layer_num]
data[layer_num] = re.sub(";MESH:NOMESH", ";MESH:NONMESH", layer)
data = self._add_travel_comment(data, layer_0_index)
# Single Fan "By Layer"--------------------------------------------
if by_layer_or_feature == "by_layer" and not is_multi_fan:
return self._single_fan_by_layer(data, layer_0_index, fan_list, t0_fan)
# Multi-Fan "By Layer"---------------------------------------------
if by_layer_or_feature == "by_layer" and is_multi_fan:
return self._multi_fan_by_layer(data, layer_0_index, fan_list, t0_fan, t1_fan, t2_fan, t3_fan)
#Single Fan "By Feature"------------------------------------------
if by_layer_or_feature == "by_feature" and (not is_multi_fan or not is_multi_extr_print):
return self._single_fan_by_feature(data, layer_0_index, the_start_layer, the_end_layer, the_end_is_enabled, fan_list, t0_fan, feature_speed_list, feature_name_list, feature_fan_combing)
#Multi Fan "By Feature"-------------------------------------------
if by_layer_or_feature == "by_feature" and is_multi_fan:
return self._multi_fan_by_feature(data, layer_0_index, the_start_layer, the_end_layer, the_end_is_enabled, fan_list, t0_fan, t1_fan, t2_fan, t3_fan, feature_speed_list, feature_name_list, feature_fan_combing)
# The Single Fan "By Layer"----------------------------------------
def _single_fan_by_layer(self, data: str, layer_0_index: int, fan_list: str, t0_fan: str)->str:
layer_number = "0"
single_fan_data = data
for l_index in range(layer_0_index,len(single_fan_data)-1,1):
layer = single_fan_data[l_index]
fan_lines = layer.split("\n")
for fan_line in fan_lines:
if ";LAYER:" in fan_line:
layer_number = str(fan_line.split(":")[1])
## If there is a match for the current layer number make the insertion
for num in range(0,15,2):
if layer_number == str(fan_list[num]):
layer = layer.replace(fan_lines[0],fan_lines[0] + "\n" + fan_list[num + 1] + str(t0_fan))
single_fan_data[l_index] = layer
return single_fan_data
# Multi-Fan "By Layer"-----------------------------------------
def _multi_fan_by_layer(self, data: str, layer_0_index: int, fan_list: str, t0_fan: str, t1_fan: str, t2_fan: str, t3_fan: str)->str:
multi_fan_data = data
layer_number = "0"
current_fan_speed = "0"
prev_fan = str(t0_fan)
this_fan = str(t0_fan)
start_index = str(len(multi_fan_data))
for num in range(0,15,2):
## The fan_list may not be in ascending order. Get the lowest layer number
try:
if int(fan_list[num]) < int(start_index):
start_index = str(fan_list[num])
except:
pass
## Move the start point if delete_existing_m106 is false
start_index = int(start_index) + int(layer_0_index)
## Track the tool number
for num in range(1,int(start_index),1):
layer = multi_fan_data[num]
lines = layer.split("\n")
for line in lines:
if line == "T0":
prev_fan = this_fan
this_fan = t0_fan
elif line == "T1":
prev_fan = this_fan
this_fan = t1_fan
elif line == "T2":
prev_fan = this_fan
this_fan = t2_fan
elif line == "T3":
prev_fan = this_fan
this_fan = t3_fan
for l_index in range(int(start_index),len(multi_fan_data)-1,1):
modified_data = ""
layer = multi_fan_data[l_index]
fan_lines = layer.split("\n")
for fan_line in fan_lines:
## Prepare to shut down the previous fan and start the next one.
if fan_line.startswith("T"):
if fan_line == "T0": this_fan = str(t0_fan)
if fan_line == "T1": this_fan = str(t1_fan)
if fan_line == "T2": this_fan = str(t2_fan)
if fan_line == "T3": this_fan = str(t3_fan)
modified_data += "M106 S0" + prev_fan + "\n"
modified_data += fan_line + "\n"
modified_data += "M106 S" + str(current_fan_speed) + this_fan + "\n"
prev_fan = this_fan
elif ";LAYER:" in fan_line:
modified_data += fan_line + "\n"
layer_number = str(fan_line.split(":")[1])
for num in range(0,15,2):
if layer_number == str(fan_list[num]):
modified_data += fan_list[num + 1] + this_fan + "\n"
current_fan_speed = str(fan_list[num + 1].split("S")[1])
current_fan_speed = str(current_fan_speed.split(" ")[0]) ## Just in case
else:
modified_data += fan_line + "\n"
if modified_data.endswith("\n"): modified_data = modified_data[0:-1]
multi_fan_data[l_index] = modified_data
return multi_fan_data
# Single fan by feature-----------------------------------------------
def _single_fan_by_feature(self, data: str, layer_0_index: int, the_start_layer: str, the_end_layer: str, the_end_is_enabled: str, fan_list: str, t0_fan: str, feature_speed_list: str, feature_name_list: str, feature_fan_combing: bool)->str:
single_fan_data = data
layer_number = "0"
index = 1
## Start with layer:0
for l_index in range(layer_0_index,len(single_fan_data)-1,1):
modified_data = ""
layer = single_fan_data[l_index]
lines = layer.split("\n")
for line in lines:
if ";LAYER:" in line:
layer_number = str(line.split(":")[1])
if int(layer_number) >= int(the_start_layer) and int(layer_number) < int(the_end_layer)-1:
temp = line.split(" ")[0]
try:
name_index = feature_name_list.index(temp)
except:
name_index = -1
if name_index != -1:
modified_data += feature_speed_list[name_index] + t0_fan + "\n"
elif ";MESH:NONMESH" in line:
if feature_fan_combing == True:
modified_data += "M106 S0" + t0_fan + "\n"
modified_data += line + "\n"
## If an End Layer is defined and is less than the last layer then insert the Final Speed
if line == ";LAYER:" + str(the_end_layer) and the_end_is_enabled == True:
modified_data += feature_speed_list[len(feature_speed_list) - 1] + t0_fan + "\n"
if modified_data.endswith("\n"): modified_data = modified_data[0: - 1]
single_fan_data[l_index] = modified_data
return single_fan_data
# Multi-fan by feature------------------------------------------------
def _multi_fan_by_feature(self, data: str, layer_0_index: int, the_start_layer: str, the_end_layer: str, the_end_is_enabled: str, fan_list: str, t0_fan: str, t1_fan: str, t2_fan: str, t3_fan: str, feature_speed_list: str, feature_name_list: str, feature_fan_combing: bool)->str:
multi_fan_data = data
layer_number = "0"
start_index = 1
prev_fan = t0_fan
this_fan = t0_fan
modified_data = ""
current_fan_speed = "0"
for my_index in range(1, len(multi_fan_data) - 1, 1):
layer = multi_fan_data[my_index]
if ";LAYER:" + str(the_start_layer) + "\n" in layer:
start_index = int(my_index) - 1
break
## Track the previous tool changes
for num in range(1,start_index,1):
layer = multi_fan_data[num]
lines = layer.split("\n")
for line in lines:
if line == "T0":
prev_fan = this_fan
this_fan = t0_fan
elif line == "T1":
prev_fan = this_fan
this_fan = t1_fan
elif line == "T2":
prev_fan = this_fan
this_fan = t2_fan
elif line == "T3":
prev_fan = this_fan
this_fan = t3_fan
## Get the current tool.
for l_index in range(start_index,start_index + 1,1):
layer = multi_fan_data[l_index]
lines = layer.split("\n")
for line in lines:
if line.startswith("T"):
if line == "T0": this_fan = t0_fan
if line == "T1": this_fan = t1_fan
if line == "T2": this_fan = t2_fan
if line == "T3": this_fan = t3_fan
prev_fan = this_fan
## Start to make insertions-------------------------------------
for l_index in range(start_index+1,len(multi_fan_data)-1,1):
layer = multi_fan_data[l_index]
lines = layer.split("\n")
for line in lines:
if line.startswith("T"):
if line == "T0": this_fan = t0_fan
if line == "T1": this_fan = t1_fan
if line == "T2": this_fan = t2_fan
if line == "T3": this_fan = t3_fan
## Turn off the prev fan
modified_data += "M106 S0" + prev_fan + "\n"
modified_data += line + "\n"
## Turn on the current fan
modified_data += "M106 S" + str(current_fan_speed) + this_fan + "\n"
prev_fan = this_fan
if ";LAYER:" in line:
layer_number = str(line.split(":")[1])
modified_data += line + "\n"
if int(layer_number) >= int(the_start_layer):
temp = line.split(" ")[0]
try:
name_index = feature_name_list.index(temp)
except:
name_index = -1
if name_index != -1:
modified_data += line + "\n" + feature_speed_list[name_index] + this_fan + "\n"
#modified_data += feature_speed_list[name_index] + this_fan + "\n"
current_fan_speed = str(feature_speed_list[name_index].split("S")[1])
elif ";MESH:NONMESH" in line:
if feature_fan_combing == True:
modified_data += line + "\n"
modified_data += "M106 S0" + this_fan + "\n"
current_fan_speed = "0"
else:
modified_data += line + "\n"
## If an end layer is defined - Insert the final speed and set the other variables to Final Speed to finish the file
## There cannot be a break here because if there are multiple fan numbers they still need to be shut off and turned on.
elif line == ";LAYER:" + str(the_end_layer):
modified_data += feature_speed_list[len(feature_speed_list) - 1] + this_fan + "\n"
for set_speed in range(0, len(feature_speed_list) - 2):
feature_speed_list[set_speed] = feature_speed_list[len(feature_speed_list) - 1]
else:
## Layer and Tool get inserted into modified_data above. All other lines go into modified_data here
if not line.startswith("T") and not line.startswith(";LAYER:"): modified_data += line + "\n"
if modified_data.endswith("\n"): modified_data = modified_data[0: - 1]
multi_fan_data[l_index] = modified_data
modified_data = ""
return multi_fan_data
#Try to catch layer input errors, set the minimum speed to 12%, and put the strings together
def _layer_checker(self, fan_string: str, ty_pe: str, fan_mode: bool) -> str:
fan_string_l = str(fan_string.split("/")[0])
try:
if int(fan_string_l) <= 1: fan_string_l = "1"
if fan_string_l == "": fan_string_l = str(len(data))
except ValueError:
fan_string_l = str(len(data))
fan_string_l = str(int(fan_string_l) - 1)
fan_string_p = str(fan_string.split("/")[1])
if fan_string_p == "": fan_string_p = "0"
try:
if int(fan_string_p) < 0: fan_string_p = "0"
if int(fan_string_p) > 100: fan_string_p = "100"
except ValueError:
fan_string_p = "0"
## Set the minimum fan speed to 12%
if int(fan_string_p) < 12 and int(fan_string_p) != 0:
fan_string_p = "12"
fan_layer_line = str(fan_string_l)
if fan_mode:
fan_percent_line = "M106 S" + str(round(int(fan_string_p) * 2.55))
else:
fan_percent_line = "M106 S" + str(round(int(fan_string_p) / 100, 1))
if ty_pe == "l":
return str(fan_layer_line)
elif ty_pe == "p":
return fan_percent_line
#Try to catch feature input errors, set the minimum speed to 12%, and put the strings together when 'By Feature'
def _feature_checker(self, fan_feat_string: int, fan_mode: bool) -> str:
if fan_feat_string < 0: fan_feat_string = 0
## Set the minimum fan speed to 12%
if fan_feat_string > 0 and fan_feat_string < 12: fan_feat_string = 12
if fan_feat_string > 100: fan_feat_string = 100
if fan_mode:
fan_sp_feat = "M106 S" + str(round(fan_feat_string * 2.55))
else:
fan_sp_feat = "M106 S" + str(round(fan_feat_string / 100, 1))
return fan_sp_feat
# Add additional travel comments to turn the fan off during combing.
def _add_travel_comment(self, comment_data: str, lay_0_index: str) -> str:
for lay_num in range(int(lay_0_index), len(comment_data)-1,1):
layer = comment_data[lay_num]
lines = layer.split("\n")
## Copy the data to new_data and make the insertions there
new_data = lines
g0_count = 0
g0_index = -1
feature_type = ";TYPE:SUPPORT"
is_travel = False
for index, line in enumerate(lines):
insert_index = 0
if ";TYPE:" in line:
feature_type = line
is_travel = False
g0_count = 0
if ";MESH:NONMESH" in line:
is_travel = True
g0_count = 0
if line.startswith("G0 ") and not is_travel:
g0_count += 1
if g0_index == -1:
g0_index = lines.index(line)
elif not line.startswith("G0 ") and not is_travel:
## Add additional 'NONMESH' lines to shut the fan off during long combing moves--------
if g0_count > 5:
if not is_travel:
new_data.insert(g0_index + insert_index, ";MESH:NONMESH")
insert_index += 1
## Add the feature_type at the end of the combing move to turn the fan back on
new_data.insert(g0_index + g0_count + 1, feature_type)
insert_index += 1
g0_count = 0
g0_index = -1
is_travel = False
elif g0_count <= 5:
g0_count = 0
g0_index = -1
is_travel = False
comment_data[lay_num] = "\n".join(new_data)
return comment_data

View file

@ -3,21 +3,16 @@
# Date: August 28, 2018
# Modified: November 16, 2018 by Joshua Pope-Lewis
# Description: This plugin shows custom messages about your print on the Status bar...
# Please look at the 5 options
# - Scrolling (SCROLL_LONG_FILENAMES) if enabled in Marlin and you aren't printing a small item select this option.
# - Name: By default it will use the name generated by Cura (EG: TT_Test_Cube) - Type a custom name in here
# - Start Num: Choose which number you prefer for the initial layer, 0 or 1
# - Max Layer: Enabling this will show how many layers are in the entire print (EG: Layer 1 of 265!)
# - Add prefix 'Printing': Enabling this will add the prefix 'Printing'
# Description: This plugin is now an option in 'Display Info on LCD'
from ..Script import Script
from UM.Application import Application
from UM.Message import Message
class DisplayFilenameAndLayerOnLCD(Script):
def __init__(self):
super().__init__()
def initialize(self) -> None:
Message(title = "[Display Filename and Layer on LCD]", text = "This script is now an option in 'Display Info on LCD'. This post processor no longer works.").show()
def getSettingDataString(self):
return """{
"name": "Display Filename And Layer On LCD",
@ -26,40 +21,10 @@ class DisplayFilenameAndLayerOnLCD(Script):
"version": 2,
"settings":
{
"scroll":
"enable_script":
{
"label": "Scroll enabled/Small layers?",
"description": "If SCROLL_LONG_FILENAMES is enabled select this setting however, if the model is small disable this setting!",
"type": "bool",
"default_value": false
},
"name":
{
"label": "Text to display:",
"description": "By default the current filename will be displayed on the LCD. Enter text here to override the filename and display something else.",
"type": "str",
"default_value": ""
},
"startNum":
{
"label": "Initial layer number:",
"description": "Choose which number you prefer for the initial layer, 0 or 1",
"type": "int",
"default_value": 0,
"minimum_value": 0,
"maximum_value": 1
},
"maxlayer":
{
"label": "Display max layer?:",
"description": "Display how many layers are in the entire print on status bar?",
"type": "bool",
"default_value": true
},
"addPrefixPrinting":
{
"label": "Add prefix 'Printing'?",
"description": "This will add the prefix 'Printing'",
"label": "Deprecated/Obsolete",
"description": "This script is now included in 'Display Info on LCD'.",
"type": "bool",
"default_value": true
}
@ -67,43 +32,6 @@ class DisplayFilenameAndLayerOnLCD(Script):
}"""
def execute(self, data):
max_layer = 0
lcd_text = "M117 "
if self.getSettingValueByKey("name") != "":
name = self.getSettingValueByKey("name")
else:
name = Application.getInstance().getPrintInformation().jobName
if self.getSettingValueByKey("addPrefixPrinting"):
lcd_text += "Printing "
if not self.getSettingValueByKey("scroll"):
lcd_text += "Layer "
else:
lcd_text += name + " - Layer "
i = self.getSettingValueByKey("startNum")
for layer in data:
display_text = lcd_text + str(i)
layer_index = data.index(layer)
lines = layer.split("\n")
for line in lines:
if line.startswith(";LAYER_COUNT:"):
max_layer = line
max_layer = max_layer.split(":")[1]
if self.getSettingValueByKey("startNum") == 0:
max_layer = str(int(max_layer) - 1)
if line.startswith(";LAYER:"):
if self.getSettingValueByKey("maxlayer"):
display_text = display_text + " of " + max_layer
if not self.getSettingValueByKey("scroll"):
display_text = display_text + " " + name
else:
if not self.getSettingValueByKey("scroll"):
display_text = display_text + " " + name + "!"
else:
display_text = display_text + "!"
line_index = lines.index(line)
lines.insert(line_index + 1, display_text)
i += 1
final_lines = "\n".join(lines)
data[layer_index] = final_lines
Message(title = "[Display Filename and Layer on LCD]", text = "This post is now included in 'Display Info on LCD'. This script will exit.").show()
data[0] += "; [Display Filename and Layer on LCD] Did not run. It is now included in 'Display Info on LCD'.\n"
return data

View file

@ -0,0 +1,486 @@
# Display Filename and Layer on the LCD by Amanda de Castilho on August 28, 2018
# Modified: Joshua Pope-Lewis on November 16, 2018
# Display Progress on LCD by Mathias Lyngklip Kjeldgaard, Alexander Gee, Kimmo Toivanen, Inigo Martinez on July 31, 2019
# Show Progress was adapted from Display Progress by Louis Wooters on January 6, 2020. His changes are included here.
#---------------------------------------------------------------
# DisplayNameOrProgressOnLCD.py
# Cura Post-Process plugin
# Combines 'Display Filename and Layer on the LCD' with 'Display Progress'
# Combined and with additions by: GregValiant (Greg Foresi)
# Date: September 8, 2023
# NOTE: This combined post processor will make 'Display Filename and Layer on the LCD' and 'Display Progress' obsolete
# Description: Display Filename and Layer options:
# Status messages sent to the printer...
# - Scrolling (SCROLL_LONG_FILENAMES) if enabled in Marlin and you aren't printing a small item select this option.
# - Name: By default it will use the name generated by Cura (EG: TT_Test_Cube) - You may enter a custom name here
# - Start Num: Choose which number you prefer for the initial layer, 0 or 1
# - Max Layer: Enabling this will show how many layers are in the entire print (EG: Layer 1 of 265!)
# - Add prefix 'Printing': Enabling this will add the prefix 'Printing'
# - Example Line on LCD: Printing Layer 0 of 395 3DBenchy
# Display Progress options:
# - Display Total Layer Count
# - Disply Time Remaining for the print
# - Time Fudge Factor % - Divide the Actual Print Time by the Cura Estimate. Enter as a percentage and the displayed time will be adjusted. This allows you to bring the displayed time closer to reality (Ex: Entering 87.5 would indicate an adjustment to 87.5% of the Cura estimate).
# - Example line on LCD: 1/479 | ET 2h13m
# - Time to Pauses changes the M117/M118 lines to countdown to the next pause as 1/479 | TP 2h36m
# - 'Add M118 Line' is available with either option. M118 will bounce the message back to a remote print server through the USB connection.
# - 'Add M73 Line' is used by 'Display Progress' only. There are options to incluse M73 P(percent) and M73 R(time remaining)
# - Enable 'Finish-Time' Message - when enabled, takes the Print Time and calculates when the print will end. It takes into account the Time Fudge Factor. The user may enter a print start time. This is also available for Display Filename.
from ..Script import Script
from UM.Application import Application
from UM.Qt.Duration import DurationFormat
import UM.Util
import configparser
from UM.Preferences import Preferences
import time
import datetime
import math
from UM.Message import Message
class DisplayInfoOnLCD(Script):
def getSettingDataString(self):
return """{
"name": "Display Info on LCD",
"key": "DisplayInfoOnLCD",
"metadata": {},
"version": 2,
"settings":
{
"display_option":
{
"label": "LCD display option...",
"description": "Display Filename and Layer was formerly 'Display Filename and Layer on LCD' post-processor. The message format on the LCD is 'Printing Layer 0 of 15 3D Benchy'. Display Progress is similar to the former 'Display Progress on LCD' post-processor. The display format is '1/16 | ET 2hr28m'. Display Progress includes a fudge factor for the print time estimate.",
"type": "enum",
"options": {
"display_progress": "Display Progress",
"filename_layer": "Filename and Layer"
},
"default_value": "display_progress"
},
"format_option":
{
"label": "Scroll enabled/Small layers?",
"description": "If SCROLL_LONG_FILENAMES is enabled in your firmware select this setting.",
"type": "bool",
"default_value": false,
"enabled": "display_option == 'filename_layer'"
},
"file_name":
{
"label": "Text to display:",
"description": "By default the current filename will be displayed on the LCD. Enter text here to override the filename and display something else.",
"type": "str",
"default_value": "",
"enabled": "display_option == 'filename_layer'"
},
"startNum":
{
"label": "Initial layer number:",
"description": "Choose which number you prefer for the initial layer, 0 or 1",
"type": "int",
"default_value": 0,
"minimum_value": 0,
"maximum_value": 1,
"enabled": "display_option == 'filename_layer'"
},
"maxlayer":
{
"label": "Display max layer?:",
"description": "Display how many layers are in the entire print on status bar?",
"type": "bool",
"default_value": true,
"enabled": "display_option == 'filename_layer'"
},
"addPrefixPrinting":
{
"label": "Add prefix 'Printing'?",
"description": "This will add the prefix 'Printing'",
"type": "bool",
"default_value": true,
"enabled": "display_option == 'filename_layer'"
},
"display_total_layers":
{
"label": "Display total layers",
"description": "This setting adds the 'Total Layers' to the LCD message as '17/234'.",
"type": "bool",
"default_value": true,
"enabled": "display_option == 'display_progress'"
},
"display_remaining_time":
{
"label": "Display remaining time",
"description": "This will add the remaining printing time to the LCD message.",
"type": "bool",
"default_value": true,
"enabled": "display_option == 'display_progress'"
},
"add_m118_line":
{
"label": "Add M118 Line",
"description": "Adds M118 in addition to the M117. It will bounce the message back through the USB port to a computer print server (if a printer server like Octoprint or Pronterface is in use).",
"type": "bool",
"default_value": false
},
"add_m73_line":
{
"label": "Add M73 Line(s)",
"description": "Adds M73 in addition to the M117. For some firmware this will set the printers time and or percentage.",
"type": "bool",
"default_value": false,
"enabled": "display_option == 'display_progress'"
},
"add_m73_percent":
{
"label": " Add M73 Percentage",
"description": "Adds M73 with the P parameter. For some firmware this will set the printers 'percentage' of layers completed and it will count upward.",
"type": "bool",
"default_value": false,
"enabled": "add_m73_line and display_option == 'display_progress'"
},
"add_m73_time":
{
"label": " Add M73 Time",
"description": "Adds M73 with the R parameter. For some firmware this will set the printers 'print time' and it will count downward.",
"type": "bool",
"default_value": false,
"enabled": "add_m73_line and display_option == 'display_progress'"
},
"speed_factor":
{
"label": "Time Fudge Factor %",
"description": "When using 'Display Progress' tweak this value to get better estimates. ([Actual Print Time]/[Cura Estimate]) x 100 = Time Fudge Factor. If Cura estimated 9hr and the print actually took 10hr30min then enter 117 here to adjust any estimate closer to reality. This Fudge Factor is also used to calculate the print finish time.",
"type": "float",
"unit": "%",
"default_value": 100,
"enabled": "enable_end_message or display_option == 'display_progress'"
},
"countdown_to_pause":
{
"label": "Countdown to Pauses",
"description": "Instead of the remaining print time the LCD will show the estimated time to pause (TP).",
"type": "bool",
"default_value": false,
"enabled": "display_option == 'display_progress'"
},
"enable_end_message":
{
"label": "Enable 'Finish-Time' Message",
"description": "Get a message when you save a fresh slice. It will show the estimated date and time that the print would finish.",
"type": "bool",
"default_value": true,
"enabled": true
},
"print_start_time":
{
"label": "Print Start Time (Ex 16:45)",
"description": "Use 'Military' time. 16:45 would be 4:45PM. 09:30 would be 9:30AM. If you leave this blank it will be assumed that the print will start Now. If you enter a guesstimate of your printer start time and that time is before 'Now' the guesstimate will consider that the print will start tomorrow at the entered time. ",
"type": "str",
"default_value": "",
"unit": "hrs ",
"enabled": "enable_end_message"
}
}
}"""
def execute(self, data):
display_option = self.getSettingValueByKey("display_option")
add_m118_line = self.getSettingValueByKey("add_m118_line")
add_m73_line = self.getSettingValueByKey("add_m73_line")
add_m73_time = self.getSettingValueByKey("add_m73_time")
add_m73_percent = self.getSettingValueByKey("add_m73_percent")
# This is Display Filename and Layer on LCD---------------------------------------------------------
if display_option == "filename_layer":
max_layer = 0
lcd_text = "M117 "
if self.getSettingValueByKey("file_name") != "":
file_name = self.getSettingValueByKey("file_name")
else:
file_name = Application.getInstance().getPrintInformation().jobName
if self.getSettingValueByKey("addPrefixPrinting"):
lcd_text += "Printing "
if not self.getSettingValueByKey("scroll"):
lcd_text += "Layer "
else:
lcd_text += file_name + " - Layer "
i = self.getSettingValueByKey("startNum")
for layer in data:
display_text = lcd_text + str(i)
layer_index = data.index(layer)
lines = layer.split("\n")
for line in lines:
if line.startswith(";LAYER_COUNT:"):
max_layer = line
max_layer = max_layer.split(":")[1]
if self.getSettingValueByKey("startNum") == 0:
max_layer = str(int(max_layer) - 1)
if line.startswith(";LAYER:"):
if self.getSettingValueByKey("maxlayer"):
display_text = display_text + " of " + max_layer
if not self.getSettingValueByKey("scroll"):
display_text = display_text + " " + file_name
else:
if not self.getSettingValueByKey("scroll"):
display_text = display_text + " " + file_name + "!"
else:
display_text = display_text + "!"
line_index = lines.index(line)
lines.insert(line_index + 1, display_text)
if add_m118_line:
lines.insert(line_index + 2, str(display_text.replace("M117", "M118", 1)))
i += 1
final_lines = "\n".join(lines)
data[layer_index] = final_lines
if bool(self.getSettingValueByKey("enable_end_message")):
message_str = self.message_to_user(self.getSettingValueByKey("speed_factor") / 100)
Message(title = "Display Info on LCD - Estimated Finish Time", text = message_str[0] + "\n\n" + message_str[1] + "\n" + message_str[2] + "\n" + message_str[3]).show()
return data
# Display Progress (from 'Show Progress' and 'Display Progress on LCD')---------------------------------------
elif display_option == "display_progress":
# get settings
display_total_layers = self.getSettingValueByKey("display_total_layers")
display_remaining_time = self.getSettingValueByKey("display_remaining_time")
speed_factor = self.getSettingValueByKey("speed_factor") / 100
m73_time = False
m73_percent = False
if add_m73_line and add_m73_time:
m73_time = True
if add_m73_line and add_m73_percent:
m73_percent = True
# initialize global variables
first_layer_index = 0
time_total = 0
number_of_layers = 0
time_elapsed = 0
# if at least one of the settings is disabled, there is enough room on the display to display "layer"
first_section = data[0]
lines = first_section.split("\n")
for line in lines:
if line.startswith(";TIME:"):
tindex = lines.index(line)
cura_time = int(line.split(":")[1])
print_time = cura_time * speed_factor
hhh = print_time/3600
hr = round(hhh // 1)
mmm = round((hhh % 1) * 60)
orig_hhh = cura_time/3600
orig_hr = round(orig_hhh // 1)
orig_mmm = math.floor((orig_hhh % 1) * 60)
orig_sec = round((((orig_hhh % 1) * 60) % 1) * 60)
if add_m118_line: lines.insert(tindex + 3,"M118 Adjusted Print Time " + str(hr) + "hr " + str(mmm) + "min")
lines.insert(tindex + 3,"M117 ET " + str(hr) + "hr " + str(mmm) + "min")
# add M73 line at beginning
mins = int(60 * hr + mmm)
if m73_time:
lines.insert(tindex + 3, "M73 R{}".format(mins))
if m73_percent:
lines.insert(tindex + 3, "M73 P0")
# If Countdonw to pause is enabled then count the pauses
pause_str = ""
if bool(self.getSettingValueByKey("countdown_to_pause")):
pause_count = 0
for num in range(2,len(data) - 1, 1):
if "PauseAtHeight.py" in data[num]:
pause_count += 1
pause_str = f" with {pause_count} pause(s)"
# This line goes in to convert seconds to hours and minutes
lines.insert(tindex + 3, f";Cura Time Estimate: {cura_time}sec = {orig_hr}hr {orig_mmm}min {orig_sec}sec {pause_str}")
data[0] = "\n".join(lines)
data[len(data)-1] += "M117 Orig Cura Est " + str(orig_hr) + "hr " + str(orig_mmm) + "min\n"
if add_m118_line: data[len(data)-1] += "M118 Est w/FudgeFactor " + str(speed_factor * 100) + "% was " + str(hr) + "hr " + str(mmm) + "min\n"
if not display_total_layers or not display_remaining_time:
base_display_text = "layer "
else:
base_display_text = ""
layer = data[len(data)-1]
data[len(data)-1] = layer.replace(";End of Gcode" + "\n", "")
data[len(data)-1] += ";End of Gcode" + "\n"
# Search for the number of layers and the total time from the start code
for index in range(len(data)):
data_section = data[index]
# We have everything we need, save the index of the first layer and exit the loop
if ";LAYER:" in data_section:
first_layer_index = index
break
else:
for line in data_section.split("\n"):
if line.startswith(";LAYER_COUNT:"):
number_of_layers = int(line.split(":")[1])
elif line.startswith(";TIME:"):
time_total = int(line.split(":")[1])
# for all layers...
current_layer = 0
for layer_counter in range(len(data)-2):
current_layer += 1
layer_index = first_layer_index + layer_counter
display_text = base_display_text
display_text += str(current_layer)
# create a list where each element is a single line of code within the layer
lines = data[layer_index].split("\n")
if not ";LAYER:" in data[layer_index]:
current_layer -= 1
continue
# add the total number of layers if this option is checked
if display_total_layers:
display_text += "/" + str(number_of_layers)
# if display_remaining_time is checked, it is calculated in this loop
if display_remaining_time:
time_remaining_display = " | ET " # initialize the time display
m = (time_total - time_elapsed) // 60 # estimated time in minutes
m *= speed_factor # correct for printing time
m = int(m)
h, m = divmod(m, 60) # convert to hours and minutes
# add the time remaining to the display_text
if h > 0: # if it's more than 1 hour left, display format = xhxxm
time_remaining_display += str(h) + "h"
if m < 10: # add trailing zero if necessary
time_remaining_display += "0"
time_remaining_display += str(m) + "m"
else:
time_remaining_display += str(m) + "m"
display_text += time_remaining_display
# find time_elapsed at the end of the layer (used to calculate the remaining time of the next layer)
if not current_layer == number_of_layers:
for line_index in range(len(lines) - 1, -1, -1):
line = lines[line_index]
if line.startswith(";TIME_ELAPSED:"):
# update time_elapsed for the NEXT layer and exit the loop
time_elapsed = int(float(line.split(":")[1]))
break
# insert the text AFTER the first line of the layer (in case other scripts use ";LAYER:")
for l_index, line in enumerate(lines):
if line.startswith(";LAYER:"):
lines[l_index] += "\nM117 " + display_text
# add M73 line
mins = int(60 * h + m)
if m73_time:
lines[l_index] += "\nM73 R{}".format(mins)
if m73_percent:
lines[l_index] += "\nM73 P" + str(round(int(current_layer) / int(number_of_layers) * 100))
if add_m118_line:
lines[l_index] += "\nM118 " + display_text
break
# overwrite the layer with the modified layer
data[layer_index] = "\n".join(lines)
# If enabled then change the ET to TP for 'Time To Pause'
if bool(self.getSettingValueByKey("countdown_to_pause")):
time_list = []
time_list.append("0")
time_list.append("0")
this_time = 0
pause_index = 1
# Get the layer times
for num in range(2,len(data) - 1):
layer = data[num]
lines = layer.split("\n")
for line in lines:
if line.startswith(";TIME_ELAPSED:"):
this_time = (float(line.split(":")[1]))*speed_factor
time_list.append(str(this_time))
if "PauseAtHeight.py" in layer:
for qnum in range(num - 1, pause_index, -1):
time_list[qnum] = str(float(this_time) - float(time_list[qnum])) + "P"
pause_index = num-1
# Make the adjustments to the M117 (and M118) lines that are prior to a pause
for num in range (2, len(data) - 1,1):
layer = data[num]
lines = layer.split("\n")
for line in lines:
if line.startswith("M117") and "|" in line and "P" in time_list[num]:
M117_line = line.split("|")[0] + "| TP "
alt_time = time_list[num][:-1]
hhh = int(float(alt_time) / 3600)
if hhh > 0:
hhr = str(hhh) + "h"
else:
hhr = ""
mmm = ((float(alt_time) / 3600) - (int(float(alt_time) / 3600))) * 60
sss = int((mmm - int(mmm)) * 60)
mmm = str(round(mmm)) + "m"
time_to_go = str(hhr) + str(mmm)
if hhr == "": time_to_go = time_to_go + str(sss) + "s"
M117_line = M117_line + time_to_go
layer = layer.replace(line, M117_line)
if line.startswith("M118") and "|" in line and "P" in time_list[num]:
M118_line = line.split("|")[0] + "| TP " + time_to_go
layer = layer.replace(line, M118_line)
data[num] = layer
setting_data = ""
if bool(self.getSettingValueByKey("enable_end_message")):
message_str = self.message_to_user(speed_factor)
Message(title = "[Display Info on LCD] - Estimated Finish Time", text = message_str[0] + "\n\n" + message_str[1] + "\n" + message_str[2] + "\n" + message_str[3]).show()
return data
def message_to_user(self, speed_factor: float):
# Message the user of the projected finish time of the print
print_time = Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.ISO8601)
print_start_time = self.getSettingValueByKey("print_start_time")
# If the user entered a print start time make sure it is in the correct format or ignore it.
if print_start_time == "" or print_start_time == "0" or len(print_start_time) != 5 or not ":" in print_start_time:
print_start_time = ""
# Change the print start time to proper time format, or, use the current time
if print_start_time != "":
hr = int(print_start_time.split(":")[0])
min = int(print_start_time.split(":")[1])
sec = 0
else:
hr = int(time.strftime("%H"))
min = int(time.strftime("%M"))
sec = int(time.strftime("%S"))
#Get the current data/time info
yr = int(time.strftime("%Y"))
day = int(time.strftime("%d"))
mo = int(time.strftime("%m"))
date_and_time = datetime.datetime(yr, mo, day, hr, min, sec)
#Split the Cura print time
pr_hr = int(print_time.split(":")[0])
pr_min = int(print_time.split(":")[1])
pr_sec = int(print_time.split(":")[2])
#Adjust the print time if none was entered
print_seconds = pr_hr*3600 + pr_min*60 + pr_sec
#Adjust the total seconds by the Fudge Factor
adjusted_print_time = print_seconds * speed_factor
#Break down the adjusted seconds back into hh:mm:ss
adj_hr = int(adjusted_print_time/3600)
print_seconds = adjusted_print_time - (adj_hr * 3600)
adj_min = int(print_seconds) / 60
adj_sec = int(print_seconds - (adj_min * 60))
#Get the print time to add to the start time
time_change = datetime.timedelta(hours=adj_hr, minutes=adj_min, seconds=adj_sec)
new_time = date_and_time + time_change
#Get the day of the week that the print will end on
week_day = str(["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][int(new_time.strftime("%w"))])
#Get the month that the print will end in
mo_str = str(["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][int(new_time.strftime("%m"))-1])
#Make adjustments from 24hr time to 12hr time
if int(new_time.strftime("%H")) > 12:
show_hr = str(int(new_time.strftime("%H")) - 12) + ":"
show_ampm = " PM"
elif int(new_time.strftime("%H")) == 0:
show_hr = "12:"
show_ampm = " AM"
else:
show_hr = str(new_time.strftime("%H")) + ":"
show_ampm = " AM"
if print_start_time == "":
start_str = "Now"
else:
start_str = "and your entered 'print start time' of " + print_start_time + "hrs."
if print_start_time != "":
print_start_str = "Print Start Time................." + str(print_start_time) + "hrs"
else:
print_start_str = "Print Start Time.................Now."
estimate_str = "Cura Time Estimate.........." + str(print_time)
adjusted_str = "Adjusted Time Estimate..." + str(time_change)
finish_str = week_day + " " + str(mo_str) + " " + str(new_time.strftime("%d")) + ", " + str(new_time.strftime("%Y")) + " at " + str(show_hr) + str(new_time.strftime("%M")) + str(show_ampm)
return finish_str, estimate_str, adjusted_str, print_start_str

View file

@ -9,12 +9,13 @@ from ..Script import Script
import re
import datetime
from UM.Message import Message
class DisplayProgressOnLCD(Script):
def __init__(self):
super().__init__()
def initialize(self) -> None:
Message(title = "[Display Progress on LCD]", text = "This script is now an option in 'Display Info on LCD'. This post processor no longer works.").show()
def getSettingDataString(self):
return """{
"name": "Display Progress On LCD",
@ -23,176 +24,17 @@ class DisplayProgressOnLCD(Script):
"version": 2,
"settings":
{
"time_remaining":
"enable_script":
{
"label": "Time Remaining",
"description": "Select to write remaining time to the display.Select to write remaining time on the display using M117 status line message (almost all printers) or using M73 command (Prusa and Marlin 2 if enabled).",
"label": "Deprecated/Obsolete",
"description": "This script is now included in 'Display Info on LCD'.",
"type": "bool",
"default_value": false
},
"time_remaining_method":
{
"label": "Time Reporting Method",
"description": "How should remaining time be shown on the display? It could use a generic message command (M117, almost all printers), or a specialised time remaining command (M73, Prusa and Marlin 2).",
"type": "enum",
"options": {
"m117":"M117 - All printers",
"m73":"M73 - Prusa, Marlin 2",
"m118":"M118 - Octoprint"
},
"enabled": "time_remaining",
"default_value": "m117"
},
"update_frequency":
{
"label": "Update frequency",
"description": "Update remaining time for every layer or periodically every minute or faster.",
"type": "enum",
"options": {"0":"Every layer","15":"Every 15 seconds","30":"Every 30 seconds","60":"Every minute"},
"default_value": "0",
"enabled": "time_remaining"
},
"percentage":
{
"label": "Percentage",
"description": "When enabled, set the completion bar percentage on the LCD using Marlin's M73 command.",
"type": "bool",
"default_value": false
"default_value": true
}
}
}"""
# Get the time value from a line as a float.
# Example line ;TIME_ELAPSED:1234.6789 or ;TIME:1337
def getTimeValue(self, line):
list_split = re.split(":", line) # Split at ":" so we can get the numerical value
return float(list_split[1]) # Convert the numerical portion to a float
def outputTime(self, lines, line_index, time_left, mode):
# Do some math to get the time left in seconds into the right format. (HH,MM,SS)
time_left = max(time_left, 0)
m, s = divmod(time_left, 60)
h, m = divmod(m, 60)
# Create the string
if mode == "m117":
current_time_string = "{:d}h{:02d}m{:02d}s".format(int(h), int(m), int(s))
# And now insert that into the GCODE
lines.insert(line_index, "M117 Time Left {}".format(current_time_string))
elif mode == "m118":
current_time_string = "{:d}h{:02d}m{:02d}s".format(int(h), int(m), int(s))
# And now insert that into the GCODE
lines.insert(line_index, "M118 A1 P0 action:notification Time Left {}".format(current_time_string))
else:
mins = int(60 * h + m + s / 30)
lines.insert(line_index, "M73 R{}".format(mins))
def execute(self, data):
output_time = self.getSettingValueByKey("time_remaining")
output_time_method = self.getSettingValueByKey("time_remaining_method")
output_frequency = int(self.getSettingValueByKey("update_frequency"))
output_percentage = self.getSettingValueByKey("percentage")
line_set = {}
if output_percentage or output_time:
total_time = -1
previous_layer_end_percentage = 0
previous_layer_end_time = 0
for layer in data:
layer_index = data.index(layer)
lines = layer.split("\n")
for line in lines:
if (line.startswith(";TIME:") or line.startswith(";PRINT.TIME:")) and total_time == -1:
# This line represents the total time required to print the gcode
total_time = self.getTimeValue(line)
line_index = lines.index(line)
# In the beginning we may have 2 M73 lines, but it makes logic less complicated
if output_time:
self.outputTime(lines, line_index, total_time, output_time_method)
if output_percentage:
# Emit 0 percent to sure Marlin knows we are overriding the completion percentage
if output_time_method == "m118":
lines.insert(line_index, "M118 A1 P0 action:notification Data Left 0/100")
else:
lines.insert(line_index, "M73 P0")
elif line.startswith(";TIME_ELAPSED:"):
# We've found one of the time elapsed values which are added at the end of layers
# If we have seen this line before then skip processing it. We can see lines multiple times because we are adding
# intermediate percentages before the line being processed. This can cause the current line to shift back and be
# encountered more than once
if line in line_set:
continue
line_set[line] = True
# If total_time was not already found then noop
if total_time == -1:
continue
current_time = self.getTimeValue(line)
line_index = lines.index(line)
if output_time:
if output_frequency == 0:
# Here we calculate remaining time
self.outputTime(lines, line_index, total_time - current_time, output_time_method)
else:
# Here we calculate remaining time and how many outputs are expected for the layer
layer_time_delta = int(current_time - previous_layer_end_time)
layer_step_delta = int((current_time - previous_layer_end_time) / output_frequency)
# If this layer represents less than 1 step then we don't need to emit anything, continue to the next layer
if layer_step_delta != 0:
# Grab the index of the current line and figure out how many lines represent one second
step = line_index / layer_time_delta
# Move new lines further as we add new lines above it
lines_added = 1
# Run through layer in seconds
for seconds in range(1, layer_time_delta + 1):
# Time from start to decide when to update
line_time = int(previous_layer_end_time + seconds)
# Output every X seconds and after last layer
if line_time % output_frequency == 0 or line_time == total_time:
# Line to add the output
time_line_index = int((seconds * step) + lines_added)
# Insert remaining time into the GCODE
self.outputTime(lines, time_line_index, total_time - line_time, output_time_method)
# Next line will be again lower
lines_added = lines_added + 1
previous_layer_end_time = int(current_time)
if output_percentage:
# Calculate percentage value this layer ends at
layer_end_percentage = int((current_time / total_time) * 100)
# Figure out how many percent of the total time is spent in this layer
layer_percentage_delta = layer_end_percentage - previous_layer_end_percentage
# If this layer represents less than 1 percent then we don't need to emit anything, continue to the next layer
if layer_percentage_delta != 0:
# Grab the index of the current line and figure out how many lines represent one percent
step = line_index / layer_percentage_delta
for percentage in range(1, layer_percentage_delta + 1):
# We add the percentage value here as while processing prior lines we will have inserted
# percentage lines before the current one. Failing to do this will upset the spacing
percentage_line_index = int((percentage * step) + percentage)
# Due to integer truncation of the total time value in the gcode the percentage we
# calculate may slightly exceed 100, as that is not valid we cap the value here
output = min(percentage + previous_layer_end_percentage, 100)
# Now insert the sanitized percentage into the GCODE
if output_time_method == "m118":
lines.insert(percentage_line_index, "M118 A1 P0 action:notification Data Left {}/100".format(output))
else:
lines.insert(percentage_line_index, "M73 P{}".format(output))
previous_layer_end_percentage = layer_end_percentage
# Join up the lines for this layer again and store them in the data array
data[layer_index] = "\n".join(lines)
Message(title = "[Display Progress on LCD]", text = "This post is now included in 'Display Info on LCD'. This script will exit.").show()
data[0] += "; [Display Progress on LCD] Did not run. It is now included in 'Display Info on LCD'.\n"
return data

View file

@ -218,13 +218,13 @@ class LimitXYAccelJerk(Script):
m201_limit_new = f"M201 X{x_accel} Y{y_accel}"
m201_limit_old = f"M201 X{round(accel_old)} Y{round(accel_old)}"
if x_jerk == 0:
m205_jerk_pattern = "Y(\d*)"
m205_jerk_pattern = r"Y(\d*)"
m205_jerk_new = f"Y{y_jerk}"
if y_jerk == 0:
m205_jerk_pattern = "X(\d*)"
m205_jerk_pattern = r"X(\d*)"
m205_jerk_new = f"X{x_jerk}"
if x_jerk != 0 and y_jerk != 0:
m205_jerk_pattern = jerk_cmd + " X(\d*) Y(\d*)"
m205_jerk_pattern = jerk_cmd + r" X(\d*) Y(\d*)"
m205_jerk_new = jerk_cmd + f" X{x_jerk} Y{y_jerk}"
m205_jerk_old = jerk_cmd + f" X{jerk_old} Y{jerk_old}"
type_of_change = self.getSettingValueByKey("type_of_change")

View file

@ -1,5 +1,6 @@
# Copyright (c) 2021 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import math
from UM.Math.Color import Color
from UM.Math.Vector import Vector
@ -35,7 +36,7 @@ class SimulationPass(RenderPass):
self._nozzle_shader = None
self._disabled_shader = None
self._old_current_layer = 0
self._old_current_path = 0
self._old_current_path: float = 0.0
self._switching_layers = True # Tracking whether the user is moving across layers (True) or across paths (False). If false, lower layers render as shadowy.
self._gl = OpenGL.getInstance().getBindingsObject()
self._scene = Application.getInstance().getController().getScene()
@ -139,7 +140,7 @@ class SimulationPass(RenderPass):
continue
# Render all layers below a certain number as line mesh instead of vertices.
if self._layer_view._current_layer_num > -1 and ((not self._layer_view._only_show_top_layers) or (not self._layer_view.getCompatibilityMode())):
if self._layer_view.getCurrentLayer() > -1 and ((not self._layer_view._only_show_top_layers) or (not self._layer_view.getCompatibilityMode())):
start = 0
end = 0
element_counts = layer_data.getElementCounts()
@ -147,33 +148,42 @@ class SimulationPass(RenderPass):
# In the current layer, we show just the indicated paths
if layer == self._layer_view._current_layer_num:
# We look for the position of the head, searching the point of the current path
index = self._layer_view._current_path_num
offset = 0
index = int(self._layer_view.getCurrentPath())
for polygon in layer_data.getLayer(layer).polygons:
# The size indicates all values in the two-dimension array, and the second dimension is
# always size 3 because we have 3D points.
if index >= polygon.data.size // 3 - offset:
index -= polygon.data.size // 3 - offset
offset = 1 # This is to avoid the first point when there is more than one polygon, since has the same value as the last point in the previous polygon
if index >= polygon.data.size // 3 :
index -= polygon.data.size // 3
continue
# The head position is calculated and translated
head_position = Vector(polygon.data[index+offset][0], polygon.data[index+offset][1], polygon.data[index+offset][2]) + node.getWorldPosition()
ratio = self._layer_view.getCurrentPath() - math.floor(self._layer_view.getCurrentPath())
pos_a = Vector(polygon.data[index][0], polygon.data[index][1],
polygon.data[index][2])
if ratio <= 0.0001 or index + 1 == len(polygon.data):
# in case there multiple polygons and polygon changes, the first point has the same value as the last point in the previous polygon
head_position = pos_a + node.getWorldPosition()
else:
pos_b = Vector(polygon.data[index + 1][0],
polygon.data[index + 1][1],
polygon.data[index + 1][2])
vec = pos_a * (1.0 - ratio) + pos_b * ratio
head_position = vec + node.getWorldPosition()
break
break
if self._layer_view._minimum_layer_num > layer:
if self._layer_view.getMinimumLayer() > layer:
start += element_counts[layer]
end += element_counts[layer]
# Calculate the range of paths in the last layer
current_layer_start = end
current_layer_end = end + self._layer_view._current_path_num * 2 # Because each point is used twice
current_layer_end = end + int( self._layer_view.getCurrentPath()) * 2 # Because each point is used twice
# This uses glDrawRangeElements internally to only draw a certain range of lines.
# All the layers but the current selected layer are rendered first
if self._old_current_path != self._layer_view._current_path_num:
if self._old_current_path != self._layer_view.getCurrentPath():
self._current_shader = self._layer_shadow_shader
self._switching_layers = False
if not self._layer_view.isSimulationRunning() and self._old_current_layer != self._layer_view._current_layer_num:
if not self._layer_view.isSimulationRunning() and self._old_current_layer != self._layer_view.getCurrentLayer():
self._current_shader = self._layer_shader
self._switching_layers = True
@ -193,8 +203,8 @@ class SimulationPass(RenderPass):
current_layer_batch.addItem(node.getWorldTransformation(), layer_data)
current_layer_batch.render(self._scene.getActiveCamera())
self._old_current_layer = self._layer_view._current_layer_num
self._old_current_path = self._layer_view._current_path_num
self._old_current_layer = self._layer_view.getCurrentLayer()
self._old_current_path = self._layer_view.getCurrentPath()
# Create a new batch that is not range-limited
batch = RenderBatch(self._layer_shader, type = RenderBatch.RenderType.Solid)
@ -230,4 +240,4 @@ class SimulationPass(RenderPass):
if changed_object.callDecoration("getLayerData"): # Any layer data has changed.
self._switching_layers = True
self._old_current_layer = 0
self._old_current_path = 0
self._old_current_path = 0.0

View file

@ -1,6 +1,5 @@
# Copyright (c) 2021 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import sys
from PyQt6.QtCore import Qt
@ -58,6 +57,7 @@ class SimulationView(CuraView):
LAYER_VIEW_TYPE_LINE_TYPE = 1
LAYER_VIEW_TYPE_FEEDRATE = 2
LAYER_VIEW_TYPE_THICKNESS = 3
SIMULATION_FACTOR = 2
_no_layers_warning_preference = "view/no_layers_warning"
@ -74,19 +74,20 @@ class SimulationView(CuraView):
self._old_max_layers = 0
self._max_paths = 0
self._current_path_num = 0
self._current_path_num: float = 0.0
self._current_time = 0.0
self._minimum_path_num = 0
self.currentLayerNumChanged.connect(self._onCurrentLayerNumChanged)
self._busy = False
self._simulation_running = False
self._ghost_shader = None # type: Optional["ShaderProgram"]
self._layer_pass = None # type: Optional[SimulationPass]
self._composite_pass = None # type: Optional[CompositePass]
self._old_layer_bindings = None # type: Optional[List[str]]
self._simulationview_composite_shader = None # type: Optional["ShaderProgram"]
self._old_composite_shader = None # type: Optional["ShaderProgram"]
self._ghost_shader: Optional["ShaderProgram"] = None
self._layer_pass: Optional[SimulationPass] = None
self._composite_pass: Optional[CompositePass] = None
self._old_layer_bindings: Optional[List[str]] = None
self._simulationview_composite_shader: Optional["ShaderProgram"] = None
self._old_composite_shader: Optional["ShaderProgram"] = None
self._max_feedrate = sys.float_info.min
self._min_feedrate = sys.float_info.max
@ -96,14 +97,16 @@ class SimulationView(CuraView):
self._min_line_width = sys.float_info.max
self._min_flow_rate = sys.float_info.max
self._max_flow_rate = sys.float_info.min
self._cumulative_line_duration_layer: Optional[int] = None
self._cumulative_line_duration: List[float] = []
self._global_container_stack = None # type: Optional[ContainerStack]
self._global_container_stack: Optional[ContainerStack] = None
self._proxy = None
self._resetSettings()
self._legend_items = None
self._show_travel_moves = False
self._nozzle_node = None # type: Optional[NozzleNode]
self._nozzle_node: Optional[NozzleNode] = None
Application.getInstance().getPreferences().addPreference("view/top_layer_count", 5)
Application.getInstance().getPreferences().addPreference("view/only_show_top_layers", False)
@ -125,13 +128,12 @@ class SimulationView(CuraView):
self._only_show_top_layers = bool(Application.getInstance().getPreferences().getValue("view/only_show_top_layers"))
self._compatibility_mode = self._evaluateCompatibilityMode()
self._slice_first_warning_message = Message(catalog.i18nc("@info:status",
"Nothing is shown because you need to slice first."),
title = catalog.i18nc("@info:title", "No layers to show"),
option_text = catalog.i18nc("@info:option_text",
"Do not show this message again"),
option_state = False,
message_type = Message.MessageType.WARNING)
self._slice_first_warning_message = Message(catalog.i18nc("@info:status", "Nothing is shown because you need to slice first."),
title=catalog.i18nc("@info:title", "No layers to show"),
option_text=catalog.i18nc("@info:option_text",
"Do not show this message again"),
option_state=False,
message_type=Message.MessageType.WARNING)
self._slice_first_warning_message.optionToggled.connect(self._onDontAskMeAgain)
CuraApplication.getInstance().getPreferences().addPreference(self._no_layers_warning_preference, True)
@ -187,9 +189,90 @@ class SimulationView(CuraView):
def getMaxLayers(self) -> int:
return self._max_layers
def getCurrentPath(self) -> int:
def getCurrentPath(self) -> float:
return self._current_path_num
def setTime(self, time: float) -> None:
cumulative_line_duration = self.cumulativeLineDuration()
if len(cumulative_line_duration) > 0:
self._current_time = time
left_i = 0
right_i = len(cumulative_line_duration) - 1
total_duration = cumulative_line_duration[-1]
# make an educated guess about where to start
i = int(right_i * max(0.0, min(1.0, self._current_time / total_duration)))
# binary search for the correct path
while left_i < right_i:
if cumulative_line_duration[i] <= self._current_time:
left_i = i + 1
else:
right_i = i
i = int((left_i + right_i) / 2)
left_value = cumulative_line_duration[i - 1] if i > 0 else 0.0
right_value = cumulative_line_duration[i]
if not (left_value <= self._current_time <= right_value):
Logger.warn(
f"Binary search error (out of bounds): index {i}: left value {left_value} right value {right_value} and current time is {self._current_time}")
fractional_value = (self._current_time - left_value) / (right_value - left_value)
self.setPath(i + fractional_value)
def advanceTime(self, time_increase: float) -> bool:
"""
Advance the time by the given amount.
:param time_increase: The amount of time to advance (in seconds).
:return: True if the time was advanced, False if the end of the simulation was reached.
"""
total_duration = 0.0
if len(self.cumulativeLineDuration()) > 0:
total_duration = self.cumulativeLineDuration()[-1]
if self._current_time + time_increase > total_duration:
# If we have reached the end of the simulation, go to the next layer.
if self.getCurrentLayer() == self.getMaxLayers():
# If we are already at the last layer, go to the first layer.
self.setTime(total_duration)
return False
# advance to the next layer, and reset the time
self.setLayer(self.getCurrentLayer() + 1)
self.setTime(0.0)
else:
self.setTime(self._current_time + time_increase)
return True
def cumulativeLineDuration(self) -> List[float]:
# Make sure _cumulative_line_duration is initialized properly
if self.getCurrentLayer() != self._cumulative_line_duration_layer:
#clear cache
self._cumulative_line_duration = []
total_duration = 0.0
polylines = self.getLayerData()
if polylines is not None:
for polyline in polylines.polygons:
for line_duration in list((polyline.lineLengths / polyline.lineFeedrates)[0]):
total_duration += line_duration / SimulationView.SIMULATION_FACTOR
self._cumulative_line_duration.append(total_duration)
# for tool change we add an extra tool path
self._cumulative_line_duration.append(total_duration)
# set current cached layer
self._cumulative_line_duration_layer = self.getCurrentLayer()
return self._cumulative_line_duration
def getLayerData(self) -> Optional["LayerData"]:
scene = self.getController().getScene()
for node in DepthFirstIterator(scene.getRoot()): # type: ignore
layer_data = node.callDecoration("getLayerData")
if not layer_data:
continue
return layer_data.getLayer(self.getCurrentLayer())
return None
def getMinimumPath(self) -> int:
return self._minimum_path_num
@ -277,7 +360,7 @@ class SimulationView(CuraView):
self._startUpdateTopLayers()
self.currentLayerNumChanged.emit()
def setPath(self, value: int) -> None:
def setPath(self, value: float) -> None:
"""
Set the upper end of the range of visible paths on the current layer.
@ -287,6 +370,9 @@ class SimulationView(CuraView):
if self._current_path_num != value:
self._current_path_num = min(max(value, 0), self._max_paths)
self._minimum_path_num = min(self._minimum_path_num, self._current_path_num)
# update _current time when the path is changed by user
if self._current_path_num < self._max_paths and round(self._current_path_num)== self._current_path_num:
self._current_time = self.cumulativeLineDuration()[int(self._current_path_num)]
self._startUpdateTopLayers()
self.currentPathNumChanged.emit()
@ -492,6 +578,7 @@ class SimulationView(CuraView):
self._max_thickness = sys.float_info.min
self._min_flow_rate = sys.float_info.max
self._max_flow_rate = sys.float_info.min
self._cumulative_line_duration = {}
# The colour scheme is only influenced by the visible lines, so filter the lines by if they should be visible.
visible_line_types = []

View file

@ -127,6 +127,7 @@ Item
function resumeSimulation()
{
UM.SimulationView.setSimulationRunning(true)
UM.SimulationView.setCurrentPath(UM.SimulationView.currentPath)
simulationTimer.start()
layerSlider.manuallyChanged = false
pathSlider.manuallyChanged = false
@ -136,54 +137,19 @@ Item
Timer
{
id: simulationTimer
interval: 100
interval: 1000 / 15
running: false
repeat: true
onTriggered:
{
var currentPath = UM.SimulationView.currentPath
var numPaths = UM.SimulationView.numPaths
var currentLayer = UM.SimulationView.currentLayer
var numLayers = UM.SimulationView.numLayers
// When the user plays the simulation, if the path slider is at the end of this layer, we start
// the simulation at the beginning of the current layer.
if (!isSimulationPlaying)
{
if (currentPath >= numPaths)
{
UM.SimulationView.setCurrentPath(0)
}
else
{
UM.SimulationView.setCurrentPath(currentPath + 1)
}
}
// If the simulation is already playing and we reach the end of a layer, then it automatically
// starts at the beginning of the next layer.
else
{
if (currentPath >= numPaths)
{
// At the end of the model, the simulation stops
if (currentLayer >= numLayers)
{
playButton.pauseSimulation()
}
else
{
UM.SimulationView.setCurrentLayer(currentLayer + 1)
UM.SimulationView.setCurrentPath(0)
}
}
else
{
UM.SimulationView.setCurrentPath(currentPath + 1)
}
// divide by 1000 to account for ms to s conversion
const advance_time = simulationTimer.interval / 1000.0;
if (!UM.SimulationView.advanceTime(advance_time)) {
playButton.pauseSimulation();
}
// The status must be set here instead of in the resumeSimulation function otherwise it won't work
// correctly, because part of the logic is in this trigger function.
isSimulationPlaying = true
isSimulationPlaying = true;
}
}

View file

@ -50,10 +50,14 @@ class SimulationViewProxy(QObject):
def numPaths(self):
return self._simulation_view.getMaxPaths()
@pyqtProperty(int, notify=currentPathChanged)
@pyqtProperty(float, notify=currentPathChanged)
def currentPath(self):
return self._simulation_view.getCurrentPath()
@pyqtSlot(float, result=bool)
def advanceTime(self, duration: float) -> bool:
return self._simulation_view.advanceTime(duration)
@pyqtProperty(int, notify=currentPathChanged)
def minimumPath(self):
return self._simulation_view.getMinimumPath()
@ -78,8 +82,8 @@ class SimulationViewProxy(QObject):
def setMinimumLayer(self, layer_num):
self._simulation_view.setMinimumLayer(layer_num)
@pyqtSlot(int)
def setCurrentPath(self, path_num):
@pyqtSlot(float)
def setCurrentPath(self, path_num: float):
self._simulation_view.setPath(path_num)
@pyqtSlot(int)
@ -215,4 +219,3 @@ class SimulationViewProxy(QObject):
self._simulation_view.activityChanged.disconnect(self._onActivityChanged)
self._simulation_view.globalStackChanged.disconnect(self._onGlobalStackChanged)
self._simulation_view.preferencesChanged.disconnect(self._onPreferencesChanged)

View file

@ -58,7 +58,6 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
# The minimum version of firmware that support print job actions over cloud.
PRINT_JOB_ACTIONS_MIN_VERSION = Version("5.2.12")
PRINT_JOB_ACTIONS_MIN_VERSION_METHOD = Version("2.700")
# Notify can only use signals that are defined by the class that they are in, not inherited ones.
# Therefore, we create a private signal used to trigger the printersChanged signal.
@ -214,7 +213,12 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
return
# Export the scene to the correct file type.
job = ExportFileJob(file_handler=file_handler, nodes=nodes, firmware_version=self.firmwareVersion)
job = ExportFileJob(
file_handler=file_handler,
nodes=nodes,
firmware_version=self.firmwareVersion,
print_type=self.printerType,
)
job.finished.connect(self._onPrintJobCreated)
job.start()
@ -319,19 +323,29 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
PrintJobUploadErrorMessage(message).show()
self.writeError.emit()
@pyqtProperty(bool, notify=_cloudClusterPrintersChanged)
def isMethod(self) -> bool:
"""Whether the printer that this output device represents is a Method series printer."""
if not self._printers:
return False
[printer, *_] = self._printers
return printer.type in ("MakerBot Method X", "MakerBot Method XL")
@pyqtProperty(bool, notify=_cloudClusterPrintersChanged)
def supportsPrintJobActions(self) -> bool:
"""Whether the printer that this output device represents supports print job actions via the cloud."""
if not self._printers:
return False
if self.isMethod:
return True
version_number = self.printers[0].firmwareVersion.split(".")
if len(version_number)> 2:
firmware_version = Version([version_number[0], version_number[1], version_number[2]])
return firmware_version >= self.PRINT_JOB_ACTIONS_MIN_VERSION
else:
firmware_version = Version([version_number[0], version_number[1]])
return firmware_version >= self.PRINT_JOB_ACTIONS_MIN_VERSION_METHOD
firmware_version = Version([version_number[0], version_number[1], version_number[2]])
return firmware_version >= self.PRINT_JOB_ACTIONS_MIN_VERSION
@pyqtProperty(bool, constant = True)

View file

@ -16,9 +16,9 @@ from .MeshFormatHandler import MeshFormatHandler
class ExportFileJob(WriteFileJob):
"""Job that exports the build plate to the correct file format for the target cluster."""
def __init__(self, file_handler: Optional[FileHandler], nodes: List[SceneNode], firmware_version: str) -> None:
self._mesh_format_handler = MeshFormatHandler(file_handler, firmware_version)
def __init__(self, file_handler: Optional[FileHandler], nodes: List[SceneNode], firmware_version: str,
print_type: str) -> None:
self._mesh_format_handler = MeshFormatHandler(file_handler, firmware_version, print_type)
if not self._mesh_format_handler.is_valid:
Logger.log("e", "Missing file or mesh writer!")
return

View file

@ -19,10 +19,9 @@ I18N_CATALOG = i18nCatalog("cura")
class MeshFormatHandler:
"""This class is responsible for choosing the formats used by the connected clusters."""
def __init__(self, file_handler: Optional[FileHandler], firmware_version: str) -> None:
def __init__(self, file_handler: Optional[FileHandler], firmware_version: str, printer_type: str) -> None:
self._file_handler = file_handler or CuraApplication.getInstance().getMeshFileHandler()
self._preferred_format = self._getPreferredFormat(firmware_version)
self._preferred_format = self._getPreferredFormat(firmware_version, printer_type)
self._writer = self._getWriter(self.mime_type) if self._preferred_format else None
@property
@ -82,7 +81,7 @@ class MeshFormatHandler:
value = value.encode()
return value
def _getPreferredFormat(self, firmware_version: str) -> Dict[str, Union[str, int, bool]]:
def _getPreferredFormat(self, firmware_version: str, printer_type: str) -> Dict[str, Union[str, int, bool]]:
"""Chooses the preferred file format for the given file handler.
:param firmware_version: The version of the firmware.
@ -103,13 +102,11 @@ class MeshFormatHandler:
machine_file_formats = [file_type.strip() for file_type in machine_file_formats]
# Exception for UM3 firmware version >=4.4: UFP is now supported and should be the preferred file format.
if "application/x-ufp" not in machine_file_formats and Version(firmware_version) >= Version("4.4"):
if printer_type in (
"ultimaker3", "ultimaker3_extended") and "application/x-ufp" not in machine_file_formats and Version(
firmware_version) >= Version("4.4"):
machine_file_formats = ["application/x-ufp"] + machine_file_formats
# Exception for makerbot firmware version >=2.700: makerbot is supported
elif "application/x-makerbot" not in machine_file_formats and Version(firmware_version >= Version("2.700")):
machine_file_formats = ["application/x-makerbot"] + machine_file_formats
# Take the intersection between file_formats and machine_file_formats.
format_by_mimetype = {f["mime_type"]: f for f in file_formats}

View file

@ -146,7 +146,12 @@ class LocalClusterOutputDevice(UltimakerNetworkedPrinterOutputDevice):
self.writeStarted.emit(self)
# Export the scene to the correct file type.
job = ExportFileJob(file_handler=file_handler, nodes=nodes, firmware_version=self.firmwareVersion)
job = ExportFileJob(
file_handler=file_handler,
nodes=nodes,
firmware_version=self.firmwareVersion,
print_type=self.printerType,
)
job.finished.connect(self._onPrintJobCreated)
job.start()

View file

@ -13,5 +13,10 @@
"DUAL600": "strateo3d",
"IDEX420": "strateo3d_IDEX420",
"IDEX420 Duplicate": "strateo3d_IDEX420_duplicate",
"IDEX420 Mirror": "strateo3d_IDEX420_mirror"
}
"IDEX420 Mirror": "strateo3d_IDEX420_mirror",
"UltiMaker Method": "ultimaker_method",
"UltiMaker Method X": "ultimaker_methodx",
"UltiMaker Method XL": "ultimaker_methodxl",
"UltiMaker Sketch": "ultimaker_sketch",
"UltiMaker Sketch Large": "ultimaker_sketch_large"
}

View file

@ -1,41 +1,47 @@
### Direct requirements for Uranium and libCharon ###
PyQt6-sip==13.4.1 \
--hash=sha256:0df998f2b6ceeacfd10de773441572e215be0c9cae566cc7dd36e231bf714a12 \
--hash=sha256:224575e84805c4317bacd5d1b8e93e0ad5c48685dadbbe1e902d4ebe16f22828 \
--hash=sha256:36ae29cdc223cacc1257d0f5075cf81474550c6d26b728f922487a2aa935f130 \
--hash=sha256:3a674c591d4274d4ea8127205290e927a7dab0eb87a0038d4f4ea1d430782649 \
--hash=sha256:3ef9392e4ae29d393b79237d85840cdc6b8831f36eed5d56c7d9b329b380cc8d \
--hash=sha256:43935873d60f57719632840d517afee04ef8f30e92cfe0dadc7e6326691920fc \
--hash=sha256:5731f22618435654352ef07684549a17be82b75254227fc80b4b5b0b59fc6656 \
--hash=sha256:5bc4beb6fb1de4c9ba8beee7b1a4a813fa888c3b095206dafcd25d7e6e4ed2a7 \
--hash=sha256:5c36ab984402e96792eebf4b031abfaa589aa20af3190a79c54502c16964d97e \
--hash=sha256:a2a0461992c6657f343308b150c4d6b57e9e7a0e5c2f79538434e7fb869ea827 \
--hash=sha256:a81490ee84d7a41a126b116081bd97d758f41bf706aee0a8cec24d6e4c660184 \
--hash=sha256:e00e287ea05bbc293fc6e2198301962af9b7b622bd2daf4288f925a88ae35dc9 \
--hash=sha256:e670a7b2fb7e32204ce67d274017bfff3e21139d217d60cebbfcb75b019c91ee \
--hash=sha256:ee06f255787a0b4957f357f93b78d2a11ca3761916833e3afa83f1381d4d1a46 \
--hash=sha256:fbee0d554e0e98f56dbf6d94b00a28cc32425938ad7ae98fd91f8822c5b24d45 \
--hash=sha256:fcc6d78314783f4a193f02353f431b7ea4d357f47c3c7a7d0740e723f69c64dc
PyQt6==6.4.2 \
--hash=sha256:18d1daf98d9236d55102cdadafd1056f5802f3c9288fcf7238569937b71a89f0 \
--hash=sha256:25bd399b4a95dce65d5f937c1aa85d3c7e14a21745ae2a4ca14c0116cd104290 \
--hash=sha256:740244f608fe15ee1d89695c43f31a14caeca41c4f02ac36c86dfba4a5d5813d \
--hash=sha256:c128bc0f17833e324593e3db83e99470d451a197dd17ff0333927b946c935bd9
PyQt6-Qt6==6.4.2 \
--hash=sha256:9f07c3c100cb46cca4074965e7494d4df4f0fc016497d5303c1fe135822876e1 \
--hash=sha256:a29b8c858babd523e80c8db5f8fd19792641588ec04eab49af18b7a4423eb99f \
--hash=sha256:c0e91d0275d428496cacff717a9b719c52bfa52b21f124d638b79cc2217bc81e \
--hash=sha256:d19c4e72615762cd6f0b043f23fa5f0b02656091427ce6de1efccd58e10e6a53
PyQt6-NetworkAuth==6.4.0 \
--hash=sha256:ab6178b3b2902ae9939a148555cfcee8c7803d6b0d5924cd1bd8f3407b8b9210 \
--hash=sha256:c16ec80232d88024b60d04386a23cc93067e5644a65f47f26ffb13d84dcd4a6d \
--hash=sha256:c302cd0d838c7229eda5e26e0b1b3d3ec4f8720f8d9379472bce5a89ff0735c2 \
--hash=sha256:d948fc0cf43b64afbda2acb5bf2392f785a1e7a2950d79ea850c1a3f4ae12f1a
PyQt6-NetworkAuth-Qt6==6.4.2 \
--hash=sha256:179094bcb4d4d056316c22d3d067cd94d4591da23f804461bfb025ccfa29b2b4 \
--hash=sha256:1de6abbb5fa6585b97ae49d3f64b0dfad40bd56b1a31744d9775ff26247241c8 \
--hash=sha256:79ec4b0fc9450bbedbff03541b93b10d1c7e761cd2cc16ce70d2b09dcdf8c720 \
--hash=sha256:d96d557fe61edb9b68d189f270f0393d6579c8d308e6b0d41bc0699371d7cb4e
PyQt6-sip==13.6.0 \
--hash=sha256:0dfd22cfedd87e96f9d51e0778ca2ba3dc0be83e424e9e0f98f6994d8d9c90f0 \
--hash=sha256:13885361ca2cb2f5085d50359ba61b3fabd41b139fb58f37332acbe631ef2357 \
--hash=sha256:24441032a29791e82beb7dfd76878339058def0e97fdb7c1cea517f3a0e6e96b \
--hash=sha256:2486e1588071943d4f6657ba09096dc9fffd2322ad2c30041e78ea3f037b5778 \
--hash=sha256:3075d8b325382750829e6cde6971c943352309d35768a4d4da0587459606d562 \
--hash=sha256:33ea771fe777eb0d1a2c3ef35bcc3f7a286eb3ff09cd5b2fdd3d87d1f392d7e8 \
--hash=sha256:39854dba35f8e5a4288da26ecb5f40b4c5ec1932efffb3f49d5ea435a7f37fb3 \
--hash=sha256:3bf03e130fbfd75c9c06e687b86ba375410c7a9e835e4e03285889e61dd4b0c4 \
--hash=sha256:43fb8551796030aae3d66d6e35e277494071ec6172cd182c9569ab7db268a2f5 \
--hash=sha256:58f68a48400e0b3d1ccb18090090299bad26e3aed7ccb7057c65887b79b8aeea \
--hash=sha256:5b9c6b6f9cfccb48cbb78a59603145a698fb4ffd176764d7083e5bf47631d8df \
--hash=sha256:747f6ca44af81777a2c696bd501bc4815a53ec6fc94d4e25830e10bc1391f8ab \
--hash=sha256:86a7b67c64436e32bffa9c28c9f21bf14a9faa54991520b12c3f6f435f24df7f \
--hash=sha256:8c282062125eea5baf830c6998587d98c50be7c3a817a057fb95fef647184012 \
--hash=sha256:8f9df9f7ccd8a9f0f1d36948c686f03ce1a1281543a3e636b7b7d5e086e1a436 \
--hash=sha256:98bf954103b087162fa63b3a78f30b0b63da22fd6450b610ec1b851dbb798228 \
--hash=sha256:9adf672f9114687533a74d5c2d4c03a9a929ad5ad9c3e88098a7da1a440ab916 \
--hash=sha256:a6ce80bc24618d8a41be8ca51ad9f10e8bc4296dd90ab2809573df30a23ae0e5 \
--hash=sha256:d6b5f699aaed0ac1fcd23e8fbca70d8a77965831b7c1ce474b81b1678817a49d \
--hash=sha256:fa759b6339ff7e25f9afe2a6b651b775f0a36bcb3f5fa85e81a90d3b033c83f4 \
--hash=sha256:fa7b10af7488efc5e53b41dd42c0f421bde6c2865a107af7ae259aff9d841da9
PyQt6==6.6.0 \
--hash=sha256:33655db05ac2de699320f035250c21434c77144a6a2943aca3f4c579dabc3f7b \
--hash=sha256:3ef68830a9b32050c30f7962c56a5927802c9193b68eaf405faecb8ce9ae10a8 \
--hash=sha256:d41512d66044c2df9c5f515a56a922170d68a37b3406ffddc8b4adc57181b576 \
--hash=sha256:fc7185d65755f26d7a6842492ec5398c92544dc4eafbbcbef1b1922aca585c96
PyQt6-Qt6==6.6.0 \
--hash=sha256:1b079a33088d32ff47872cdb37fd15aa42101f0be46c3340244483849b781438 \
--hash=sha256:8cb30d64a4d32465ea1686bc827cbe452225fb387c4873356b0fa7b9ae63534f \
--hash=sha256:a151f34712cd645111e89cb30b02e5fb69c9dcc3603ab3c03a561e874bd7cbcf \
--hash=sha256:e5483ae04bf107411c7469f1be9f9e2eb9840303e788b3ac524fe30af90d45f4
PyQt6-NetworkAuth==6.6.0 \
--hash=sha256:7b90b81792fe53105287c8cbb5e4b22bc44a482268ffb7d3e33f852807f86182 \
--hash=sha256:c7e2335159aa795e2fe6fb069ccce6308672ab80f26c50fab57caf957371cbb5 \
--hash=sha256:cdfc0bfaea16a9e09f075bdafefb996aa9fdec392052ba4fb3cbac233c1958fb \
--hash=sha256:f60ff9a62f5129dc2a9d4c495fb47f9a03e4dfb666b50fb7d61f46e89bf7b6a2
PyQt6-NetworkAuth-Qt6==6.6.0 \
--hash=sha256:481d9093e1fb1ac6843d8beabcd359cc34b74b9a2cbb3e2b68d96bd3f178d4e0 \
--hash=sha256:4cc48fd375730a0ba5fbed9d64abb2914f587377560a78a63aff893f9e276a45 \
--hash=sha256:5006deabf55304d4a3e0b3c954f93e5835546b11e789d14653a2493d12d3a063 \
--hash=sha256:bcd56bfc892fec961c51eba3c0bf32ba8317a762d9e254d3830569611ed569d6
certifi==2023.5.7; \
--hash=sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716
cryptography==41.0.1 \

View file

@ -6,7 +6,7 @@
"display_name": "3MF Reader",
"description": "Provides support for reading 3MF files.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -23,7 +23,7 @@
"display_name": "3MF Writer",
"description": "Provides support for writing 3MF files.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -40,7 +40,7 @@
"display_name": "AMF Reader",
"description": "Provides support for reading AMF files.",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "fieldOfView",
@ -57,7 +57,7 @@
"display_name": "Cura Backups",
"description": "Backup and restore your configuration.",
"package_version": "1.2.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -74,7 +74,7 @@
"display_name": "CuraEngine Backend",
"description": "Provides the link to the CuraEngine slicing backend.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -91,7 +91,7 @@
"display_name": "Cura Profile Reader",
"description": "Provides support for importing Cura profiles.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -108,7 +108,7 @@
"display_name": "Cura Profile Writer",
"description": "Provides support for exporting Cura profiles.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -125,7 +125,7 @@
"display_name": "Ultimaker Digital Library",
"description": "Connects to the Digital Library, allowing Cura to open files from and save files to the Digital Library.",
"package_version": "1.1.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -142,7 +142,7 @@
"display_name": "Firmware Update Checker",
"description": "Checks for firmware updates.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -159,7 +159,7 @@
"display_name": "Firmware Updater",
"description": "Provides a machine actions for updating firmware.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -176,7 +176,7 @@
"display_name": "Compressed G-code Reader",
"description": "Reads g-code from a compressed archive.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -193,7 +193,7 @@
"display_name": "Compressed G-code Writer",
"description": "Writes g-code to a compressed archive.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -210,7 +210,7 @@
"display_name": "G-Code Profile Reader",
"description": "Provides support for importing profiles from g-code files.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -227,7 +227,7 @@
"display_name": "G-Code Reader",
"description": "Allows loading and displaying G-code files.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "VictorLarchenko",
@ -244,7 +244,7 @@
"display_name": "G-Code Writer",
"description": "Writes g-code to a file.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -261,7 +261,7 @@
"display_name": "Image Reader",
"description": "Enables ability to generate printable geometry from 2D image files.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -278,7 +278,7 @@
"display_name": "Legacy Cura Profile Reader",
"description": "Provides support for importing profiles from legacy Cura versions.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -295,7 +295,7 @@
"display_name": "Machine Settings Action",
"description": "Provides a way to change machine settings (such as build volume, nozzle size, etc.).",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "fieldOfView",
@ -312,7 +312,7 @@
"display_name": "Makerbot Printfile Writer",
"description": "Provides support for writing MakerBot Format Packages.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -329,7 +329,7 @@
"display_name": "Model Checker",
"description": "Checks models and print configuration for possible printing issues and give suggestions.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -346,7 +346,7 @@
"display_name": "Monitor Stage",
"description": "Provides a monitor stage in Cura.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -363,7 +363,7 @@
"display_name": "Per-Object Settings Tool",
"description": "Provides the per-model settings.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -380,7 +380,7 @@
"display_name": "Post Processing",
"description": "Extension that allows for user created scripts for post processing.",
"package_version": "2.2.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -397,7 +397,7 @@
"display_name": "Prepare Stage",
"description": "Provides a prepare stage in Cura.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -414,7 +414,7 @@
"display_name": "Preview Stage",
"description": "Provides a preview stage in Cura.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -431,7 +431,7 @@
"display_name": "Removable Drive Output Device",
"description": "Provides removable drive hotplugging and writing support.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -448,7 +448,7 @@
"display_name": "Sentry Logger",
"description": "Logs certain events so that they can be used by the crash reporter",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -465,7 +465,7 @@
"display_name": "Simulation View",
"description": "Provides the Simulation view.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -482,7 +482,7 @@
"display_name": "Slice Info",
"description": "Submits anonymous slice info. Can be disabled through preferences.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -499,7 +499,7 @@
"display_name": "Solid View",
"description": "Provides a normal solid mesh view.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -516,7 +516,7 @@
"display_name": "Support Eraser Tool",
"description": "Creates an eraser mesh to block the printing of support in certain places.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -533,7 +533,7 @@
"display_name": "Trimesh Reader",
"description": "Provides support for reading model files.",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -550,7 +550,7 @@
"display_name": "Marketplace",
"description": "Find, manage and install new Cura packages.",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -567,7 +567,7 @@
"display_name": "UFP Reader",
"description": "Provides support for reading Ultimaker Format Packages.",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -584,7 +584,7 @@
"display_name": "UFP Writer",
"description": "Provides support for writing Ultimaker Format Packages.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -601,7 +601,7 @@
"display_name": "Ultimaker Machine Actions",
"description": "Provides machine actions for Ultimaker machines (such as bed leveling wizard, selecting upgrades, etc.).",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -618,7 +618,7 @@
"display_name": "UM3 Network Printing",
"description": "Manages network connections to Ultimaker 3 printers.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -635,7 +635,7 @@
"display_name": "USB Printing",
"description": "Accepts G-Code and sends them to a printer. Plugin can also update firmware.",
"package_version": "1.0.2",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -652,7 +652,7 @@
"display_name": "Version Upgrade 2.1 to 2.2",
"description": "Upgrades configurations from Cura 2.1 to Cura 2.2.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -669,7 +669,7 @@
"display_name": "Version Upgrade 2.2 to 2.4",
"description": "Upgrades configurations from Cura 2.2 to Cura 2.4.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -686,7 +686,7 @@
"display_name": "Version Upgrade 2.5 to 2.6",
"description": "Upgrades configurations from Cura 2.5 to Cura 2.6.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -703,7 +703,7 @@
"display_name": "Version Upgrade 2.6 to 2.7",
"description": "Upgrades configurations from Cura 2.6 to Cura 2.7.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -720,7 +720,7 @@
"display_name": "Version Upgrade 2.7 to 3.0",
"description": "Upgrades configurations from Cura 2.7 to Cura 3.0.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -737,7 +737,7 @@
"display_name": "Version Upgrade 3.0 to 3.1",
"description": "Upgrades configurations from Cura 3.0 to Cura 3.1.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -754,7 +754,7 @@
"display_name": "Version Upgrade 3.2 to 3.3",
"description": "Upgrades configurations from Cura 3.2 to Cura 3.3.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -771,7 +771,7 @@
"display_name": "Version Upgrade 3.3 to 3.4",
"description": "Upgrades configurations from Cura 3.3 to Cura 3.4.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -788,7 +788,7 @@
"display_name": "Version Upgrade 3.4 to 3.5",
"description": "Upgrades configurations from Cura 3.4 to Cura 3.5.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -805,7 +805,7 @@
"display_name": "Version Upgrade 3.5 to 4.0",
"description": "Upgrades configurations from Cura 3.5 to Cura 4.0.",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -822,7 +822,7 @@
"display_name": "Version Upgrade 4.0 to 4.1",
"description": "Upgrades configurations from Cura 4.0 to Cura 4.1.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -839,7 +839,7 @@
"display_name": "Version Upgrade 4.1 to 4.2",
"description": "Upgrades configurations from Cura 4.1 to Cura 4.2.",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -856,7 +856,7 @@
"display_name": "Version Upgrade 4.2 to 4.3",
"description": "Upgrades configurations from Cura 4.2 to Cura 4.3.",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -873,7 +873,7 @@
"display_name": "Version Upgrade 4.3 to 4.4",
"description": "Upgrades configurations from Cura 4.3 to Cura 4.4.",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -890,7 +890,7 @@
"display_name": "Version Upgrade 4.4 to 4.5",
"description": "Upgrades configurations from Cura 4.4 to Cura 4.5.",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -907,7 +907,7 @@
"display_name": "Version Upgrade 4.5 to 4.6",
"description": "Upgrades configurations from Cura 4.5 to Cura 4.6.",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -924,7 +924,7 @@
"display_name": "Version Upgrade 4.6.0 to 4.6.2",
"description": "Upgrades configurations from Cura 4.6.0 to Cura 4.6.2.",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -941,7 +941,7 @@
"display_name": "Version Upgrade 4.6.2 to 4.7",
"description": "Upgrades configurations from Cura 4.6.2 to Cura 4.7.",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -958,7 +958,7 @@
"display_name": "Version Upgrade 4.7.0 to 4.8.0",
"description": "Upgrades configurations from Cura 4.7.0 to Cura 4.8.0",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -975,7 +975,7 @@
"display_name": "Version Upgrade 4.8.0 to 4.9.0",
"description": "Upgrades configurations from Cura 4.8.0 to Cura 4.9.0",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -992,7 +992,7 @@
"display_name": "Version Upgrade 4.9 to 4.10",
"description": "Upgrades configurations from Cura 4.9 to Cura 4.10",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -1009,7 +1009,7 @@
"display_name": "Version Upgrade 4.11 to 4.12",
"description": "Upgrades configurations from Cura 4.11 to Cura 4.12",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"sdk_version_semver": "7.7.0",
"website": "https://ultimaker.com",
"author": {
@ -1027,7 +1027,7 @@
"display_name": "Version Upgrade 4.13 to 5.0",
"description": "Upgrades configurations from Cura 4.13 to Cura 5.0",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -1044,7 +1044,7 @@
"display_name": "Version Upgrade 5.2 to 5.3",
"description": "Upgrades configurations from Cura 5.2 to Cura 5.3",
"package_version": "1.0.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -1061,7 +1061,7 @@
"display_name": "X3D Reader",
"description": "Provides support for reading X3D files.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "SevaAlekseyev",
@ -1078,7 +1078,7 @@
"display_name": "XML Material Profiles",
"description": "Provides capabilities to read and write XML-based material profiles.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -1095,7 +1095,7 @@
"display_name": "X-Ray View",
"description": "Provides the X-Ray view.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
@ -1112,7 +1112,7 @@
"display_name": "Generic ABS",
"description": "The generic ABS profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1130,7 +1130,7 @@
"display_name": "Generic BAM",
"description": "The generic BAM profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1148,7 +1148,7 @@
"display_name": "Generic CFF CPE",
"description": "The generic CFF CPE profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1166,7 +1166,7 @@
"display_name": "Generic CFF PA",
"description": "The generic CFF PA profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1184,7 +1184,7 @@
"display_name": "Generic CPE",
"description": "The generic CPE profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1202,7 +1202,7 @@
"display_name": "Generic CPE+",
"description": "The generic CPE+ profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1220,7 +1220,7 @@
"display_name": "Generic GFF CPE",
"description": "The generic GFF CPE profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1238,7 +1238,7 @@
"display_name": "Generic GFF PA",
"description": "The generic GFF PA profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1256,7 +1256,7 @@
"display_name": "Generic HIPS",
"description": "The generic HIPS profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1274,7 +1274,7 @@
"display_name": "Generic Nylon",
"description": "The generic Nylon profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1292,7 +1292,7 @@
"display_name": "Generic PC",
"description": "The generic PC profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1310,7 +1310,7 @@
"display_name": "Generic PETG",
"description": "The generic PETG profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1328,7 +1328,7 @@
"display_name": "Generic PLA",
"description": "The generic PLA profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1346,7 +1346,7 @@
"display_name": "Generic PP",
"description": "The generic PP profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1364,7 +1364,7 @@
"display_name": "Generic PVA",
"description": "The generic PVA profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1382,7 +1382,7 @@
"display_name": "Generic Tough PLA",
"description": "The generic Tough PLA profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1400,7 +1400,7 @@
"display_name": "Generic TPU",
"description": "The generic TPU profile which other profiles can be based upon.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://github.com/Ultimaker/fdm_materials",
"author": {
"author_id": "Generic",
@ -1418,7 +1418,7 @@
"display_name": "Dagoma Chromatik PLA",
"description": "Filament testé et approuvé pour les imprimantes 3D Dagoma. Chromatik est l'idéal pour débuter et suivre les tutoriels premiers pas. Il vous offre qualité et résistance pour chacune de vos impressions.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://dagoma.fr/boutique/filaments.html",
"author": {
"author_id": "Dagoma",
@ -1435,7 +1435,7 @@
"display_name": "FABtotum ABS",
"description": "This material is easy to be extruded but it is not the simplest to use. It is one of the most used in 3D printing to get very well finished objects. It is not sustainable and its smoke can be dangerous if inhaled. The reason to prefer this filament to PLA is mainly because of its precision and mechanical specs. ABS (for plastic) stands for Acrylonitrile Butadiene Styrene and it is a thermoplastic which is widely used in everyday objects. It can be printed with any FFF 3D printer which can get to high temperatures as it must be extruded in a range between 220° and 245°, so its compatible with all versions of the FABtotum Personal fabricator.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://store.fabtotum.com/eu/products/filaments.html?filament_type=40",
"author": {
"author_id": "FABtotum",
@ -1452,7 +1452,7 @@
"display_name": "FABtotum Nylon",
"description": "When 3D printing started this material was not listed among the extrudable filaments. It is flexible as well as resistant to tractions. It is well known for its uses in textile but also in industries which require a strong and flexible material. There are different kinds of Nylon: 3D printing mostly uses Nylon 6 and Nylon 6.6, which are the most common. It requires higher temperatures to be printed, so a 3D printer must be able to reach them (around 240°C): the FABtotum, of course, can.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://store.fabtotum.com/eu/products/filaments.html?filament_type=53",
"author": {
"author_id": "FABtotum",
@ -1469,7 +1469,7 @@
"display_name": "FABtotum PLA",
"description": "It is the most common filament used for 3D printing. It is studied to be bio-degradable as it comes from corn starchs sugar mainly. It is completely made of renewable sources and has no footprint on polluting. PLA stands for PolyLactic Acid and it is a thermoplastic that today is still considered the easiest material to be 3D printed. It can be extruded at lower temperatures: the standard range of FABtotums one is between 185° and 195°.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://store.fabtotum.com/eu/products/filaments.html?filament_type=39",
"author": {
"author_id": "FABtotum",
@ -1486,7 +1486,7 @@
"display_name": "FABtotum TPU Shore 98A",
"description": "",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://store.fabtotum.com/eu/products/filaments.html?filament_type=66",
"author": {
"author_id": "FABtotum",
@ -1503,7 +1503,7 @@
"display_name": "Fiberlogy HD PLA",
"description": "With our HD PLA you have many more options. You can use this material in two ways. Choose the one you like best. You can use it as a normal PLA and get prints characterized by a very good adhesion between the layers and high precision. You can also make your prints acquire similar properties to that of ABS better impact resistance and high temperature resistance. All you need is an oven. Yes, an oven! By annealing our HD PLA in an oven, in accordance with the manual, you will avoid all the inconveniences of printing with ABS, such as unpleasant odour or hazardous fumes.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "http://fiberlogy.com/en/fiberlogy-filaments/filament-hd-pla/",
"author": {
"author_id": "Fiberlogy",
@ -1520,7 +1520,7 @@
"display_name": "Filo3D PLA",
"description": "Fast, safe and reliable printing. PLA is ideal for the fast and reliable printing of parts and prototypes with a great surface quality.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://dagoma.fr",
"author": {
"author_id": "Dagoma",
@ -1537,7 +1537,7 @@
"display_name": "IMADE3D JellyBOX PETG",
"description": "",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "http://shop.imade3d.com/filament.html",
"author": {
"author_id": "IMADE3D",
@ -1554,7 +1554,7 @@
"display_name": "IMADE3D JellyBOX PLA",
"description": "",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "http://shop.imade3d.com/filament.html",
"author": {
"author_id": "IMADE3D",
@ -1571,7 +1571,7 @@
"display_name": "Octofiber PLA",
"description": "PLA material from Octofiber.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://nl.octofiber.com/3d-printing-filament/pla.html",
"author": {
"author_id": "Octofiber",
@ -1588,7 +1588,7 @@
"display_name": "PolyFlex™ PLA",
"description": "PolyFlex™ is a highly flexible yet easy to print 3D printing material. Featuring good elasticity and a large strain-to- failure, PolyFlex™ opens up a completely new realm of applications.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "http://www.polymaker.com/shop/polyflex/",
"author": {
"author_id": "Polymaker",
@ -1605,7 +1605,7 @@
"display_name": "PolyMax™ PLA",
"description": "PolyMax™ PLA is a 3D printing material with excellent mechanical properties and printing quality. PolyMax™ PLA has an impact resistance of up to nine times that of regular PLA, and better overall mechanical properties than ABS.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "http://www.polymaker.com/shop/polymax/",
"author": {
"author_id": "Polymaker",
@ -1622,7 +1622,7 @@
"display_name": "PolyPlus™ PLA True Colour",
"description": "PolyPlus™ PLA is a premium PLA designed for all desktop FDM/FFF 3D printers. It is produced with our patented Jam-Free™ technology that ensures consistent extrusion and prevents jams.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "http://www.polymaker.com/shop/polyplus-true-colour/",
"author": {
"author_id": "Polymaker",
@ -1639,7 +1639,7 @@
"display_name": "PolyWood™ PLA",
"description": "PolyWood™ is a wood mimic printing material that contains no actual wood ensuring a clean Jam-Free™ printing experience.",
"package_version": "1.0.1",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "http://www.polymaker.com/shop/polywood/",
"author": {
"author_id": "Polymaker",
@ -1656,7 +1656,7 @@
"display_name": "Ultimaker ABS",
"description": "Example package for material and quality profiles for Ultimaker materials.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com/products/materials/abs",
"author": {
"author_id": "UltimakerPackages",
@ -1675,7 +1675,7 @@
"display_name": "Ultimaker Breakaway",
"description": "Example package for material and quality profiles for Ultimaker materials.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com/products/materials/breakaway",
"author": {
"author_id": "UltimakerPackages",
@ -1694,7 +1694,7 @@
"display_name": "Ultimaker CPE",
"description": "Example package for material and quality profiles for Ultimaker materials.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com/products/materials/abs",
"author": {
"author_id": "UltimakerPackages",
@ -1713,7 +1713,7 @@
"display_name": "Ultimaker CPE+",
"description": "Example package for material and quality profiles for Ultimaker materials.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com/products/materials/cpe",
"author": {
"author_id": "UltimakerPackages",
@ -1732,7 +1732,7 @@
"display_name": "Ultimaker Nylon",
"description": "Example package for material and quality profiles for Ultimaker materials.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com/products/materials/abs",
"author": {
"author_id": "UltimakerPackages",
@ -1751,7 +1751,7 @@
"display_name": "Ultimaker PC",
"description": "Example package for material and quality profiles for Ultimaker materials.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com/products/materials/pc",
"author": {
"author_id": "UltimakerPackages",
@ -1770,7 +1770,7 @@
"display_name": "Ultimaker PLA",
"description": "Example package for material and quality profiles for Ultimaker materials.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com/products/materials/abs",
"author": {
"author_id": "UltimakerPackages",
@ -1789,7 +1789,7 @@
"display_name": "Ultimaker PP",
"description": "Example package for material and quality profiles for Ultimaker materials.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com/products/materials/pp",
"author": {
"author_id": "UltimakerPackages",
@ -1808,7 +1808,7 @@
"display_name": "Ultimaker PVA",
"description": "Example package for material and quality profiles for Ultimaker materials.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com/products/materials/abs",
"author": {
"author_id": "UltimakerPackages",
@ -1827,7 +1827,7 @@
"display_name": "Ultimaker TPU 95A",
"description": "Example package for material and quality profiles for Ultimaker materials.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com/products/materials/tpu-95a",
"author": {
"author_id": "UltimakerPackages",
@ -1846,7 +1846,7 @@
"display_name": "Ultimaker Tough PLA",
"description": "Example package for material and quality profiles for Ultimaker materials.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://ultimaker.com/products/materials/tough-pla",
"author": {
"author_id": "UltimakerPackages",
@ -1865,7 +1865,7 @@
"display_name": "Vertex Delta ABS",
"description": "ABS material and quality files for the Delta Vertex K8800.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://vertex3dprinter.eu",
"author": {
"author_id": "Velleman",
@ -1882,7 +1882,7 @@
"display_name": "Vertex Delta PET",
"description": "ABS material and quality files for the Delta Vertex K8800.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://vertex3dprinter.eu",
"author": {
"author_id": "Velleman",
@ -1899,7 +1899,7 @@
"display_name": "Vertex Delta PLA",
"description": "ABS material and quality files for the Delta Vertex K8800.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://vertex3dprinter.eu",
"author": {
"author_id": "Velleman",
@ -1916,7 +1916,7 @@
"display_name": "Vertex Delta TPU",
"description": "ABS material and quality files for the Delta Vertex K8800.",
"package_version": "1.4.0",
"sdk_version": "8.5.0",
"sdk_version": "8.6.0",
"website": "https://vertex3dprinter.eu",
"author": {
"author_id": "Velleman",

View file

@ -130,8 +130,7 @@
"support_infill_rate": { "value": "0 if support_enable and support_structure == 'tree' else 20" },
"support_interface_density": { "value": 33.333 },
"support_interface_height": { "value": "layer_height * 3" },
"support_interface_pattern": { "value": "zigzag" },
"support_interface_skip_height": { "value": 0.2 },
"support_interface_pattern": { "value": "'zigzag'" },
"support_pattern": { "value": "'zigzag'" },
"support_wall_count": { "value": 0 },
"support_xy_distance": { "value": "wall_line_width_0 * 2" },

View file

@ -131,8 +131,7 @@
"support_infill_rate": { "value": "0 if support_enable and support_structure == 'tree' else 20" },
"support_interface_density": { "value": 33.333 },
"support_interface_height": { "value": "layer_height * 3" },
"support_interface_pattern": { "value": "zigzag" },
"support_interface_skip_height": { "value": 0.2 },
"support_interface_pattern": { "value": "'zigzag'" },
"support_pattern": { "value": "'zigzag'" },
"support_wall_count": { "value": 0 },
"support_xy_distance": { "value": "wall_line_width_0 * 2" },

View file

@ -118,8 +118,7 @@
"support_infill_rate": { "value": "0 if support_enable and support_structure == 'tree' else 20" },
"support_interface_density": { "value": 33.333 },
"support_interface_height": { "value": "layer_height * 3" },
"support_interface_pattern": { "value": "zigzag" },
"support_interface_skip_height": { "value": 0.2 },
"support_interface_pattern": { "value": "'zigzag'" },
"support_pattern": { "value": "'zigzag'" },
"support_wall_count": { "value": 0 },
"support_xy_distance": { "value": "wall_line_width_0 * 2" },

View file

@ -137,10 +137,9 @@
"machine_start_gcode": { "value": "\"\" if machine_gcode_flavor == \"UltiGCode\" else \"G21 ;metric values\\nG90 ;absolute positioning\\nM82 ;set extruder to absolute mode\\nM107 ;start with the fan off\\nM200 D0 T0 ;reset filament diameter\\nM200 D0 T1\\nG28 Z0; home all\\nG28 X0 Y0\\nG0 Z20 F2400 ;move the platform to 20mm\\nG92 E0\\nM190 S{material_bed_temperature_layer_0}\\nM109 T0 S{material_standby_temperature, 0}\\nM109 T1 S{material_print_temperature_layer_0, 1}\\nM104 T0 S{material_print_temperature_layer_0, 0}\\nT1 ; move to the 2th head\\nG0 Z20 F2400\\nG92 E-7.0 ;prime distance\\nG1 E0 F45 ;purge nozzle\\nG1 E-5.1 F1500 ; retract\\nG1 X90 Z0.01 F5000 ; move away from the prime poop\\nG1 X50 F9000\\nG0 Z20 F2400\\nT0 ; move to the first head\\nM104 T1 S{material_standby_temperature, 1}\\nG0 Z20 F2400\\nM104 T{initial_extruder_nr} S{material_print_temperature_layer_0, initial_extruder_nr}\\nG92 E-7.0\\nG1 E0 F45 ;purge nozzle\\nG1 X60 Z0.01 F5000 ; move away from the prime poop\\nG1 X20 F9000\\nM400 ;finish all moves\\nG92 E0\\n;end of startup sequence\\n\"" },
"machine_use_extruder_offset_to_offset_coords": { "default_value": false },
"machine_width": { "default_value": 223 },
"prime_tower_position_y": { "value": "170" },
"retraction_amount": { "default_value": 5.1 },
"retraction_speed": { "default_value": 25 },
"speed_support": { "value": "speed_wall_0" },
"speed_wall_x": { "value": "speed_wall" },
"switch_extruder_prime_speed":
{
"enabled": false,

View file

@ -59,7 +59,7 @@
"machine_width": { "default_value": 280 },
"material_diameter": { "default_value": 1.75 },
"material_initial_print_temperature": { "value": "material_print_temperature" },
"prime_tower_min_volume": { "value": "((resolveOrValue('layer_height'))/2" },
"prime_tower_min_volume": { "value": "resolveOrValue('layer_height')/2" },
"prime_tower_size": { "value": "30" },
"prime_tower_wipe_enabled": { "default_value": true },
"retraction_amount": { "default_value": 5 },

View file

@ -0,0 +1,90 @@
{
"version": 2,
"name": "Anycubic Kobra 2",
"inherits": "fdmprinter",
"metadata":
{
"visible": true,
"author": "ThatGuyZim",
"manufacturer": "Anycubic",
"file_formats": "text/x-gcode",
"platform": "anycubic_kobra2_platform.stl",
"machine_extruder_trains": { "0": "anycubic_kobra2_extruder_0" }
},
"overrides":
{
"acceleration_enabled": { "value": true },
"acceleration_print": { "value": 2500 },
"acceleration_travel": { "value": 3000 },
"acceleration_travel_layer_0": { "value": "acceleration_travel" },
"gantry_height": { "value": "0" },
"infill_before_walls": { "value": false },
"jerk_enabled": { "value": true },
"jerk_print": { "value": 8 },
"jerk_travel": { "value": 10 },
"jerk_travel_layer_0": { "value": "jerk_travel" },
"layer_height": { "default_value": 0.2 },
"machine_center_is_zero": { "default_value": false },
"machine_depth": { "default_value": 220 },
"machine_end_gcode": { "default_value": "M104 S0 ; turn off extruder\nM140 S0 ; turn off bed\nM107 ; fan off\nG91 ;relative positioning\nG1 E-2 F3000 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 F3000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 F3000 ;move X/Y to min endstops, so the head is out of the way\nG1 Y210 F3000\nM84 ;steppers off\nG90\nM300 S1318 P266" },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_heated_bed": { "default_value": true },
"machine_height": { "default_value": 250 },
"machine_max_acceleration_e": { "value": 2500 },
"machine_max_acceleration_x": { "value": 2500 },
"machine_max_acceleration_y": { "value": 2500 },
"machine_max_acceleration_z": { "value": 800 },
"machine_max_feedrate_e": { "default_value": 100 },
"machine_max_feedrate_x": { "default_value": 300 },
"machine_max_feedrate_y": { "default_value": 250 },
"machine_max_feedrate_z": { "default_value": 40 },
"machine_max_jerk_e": { "value": 10 },
"machine_max_jerk_xy": { "value": 10 },
"machine_max_jerk_z": { "value": 2 },
"machine_name": { "default_value": "Anycubic Kobra 2" },
"machine_start_gcode": { "default_value": "G21 ;metric values\nG90 ; use absolute coordinates\nM82 ; use absolute distances for extrusion\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 ; home all axes\nM300 S1318 P266\nG1 Z5 F5000 ; lift nozzle\nG1 X5 Y0 F3000\nG1 Z0.3 ; set nozzle height\nG92 E0\nG1 X50 Y0 E20 F500 ; Extrude 20mm of filament in a 5cm line \nG92 E0 ; zero the extruded length again \nG1 E-4.5 F4800 ; Retract a little \nG92 E0\nG1 X120 F4000 ; Quickly wipe away from the filament line\nM117 ; Printing\u2026\nG5" },
"machine_width": { "default_value": 220 },
"material_bed_temperature": { "maximum_value_warning": 110 },
"material_bed_temperature_layer_0": { "maximum_value_warning": 110 },
"material_diameter": { "default_value": 1.75 },
"material_final_print_temperature": { "value": "material_print_temperature" },
"material_initial_print_temperature":
{
"maximum_value_warning": 260,
"value": "material_print_temperature + 5"
},
"material_print_temperature": { "maximum_value_warning": 260 },
"material_print_temperature_layer_0":
{
"maximum_value_warning": 260,
"value": "material_print_temperature + 5"
},
"retraction_amount": { "value": 2 },
"retraction_combing": { "value": "'off'" },
"retraction_combing_max_distance": { "value": 30 },
"retraction_min_travel": { "value": 1 },
"retraction_prime_speed": { "maximum_value_warning": 100 },
"retraction_retract_speed": { "maximum_value_warning": 100 },
"retraction_speed":
{
"maximum_value_warning": 100,
"value": 80
},
"speed_print": { "value": 80 },
"speed_support": { "value": "speed_wall_0" },
"speed_support_interface": { "value": "speed_topbottom" },
"speed_travel":
{
"maximum_value": 200.0,
"maximum_value_warning": 175.0,
"value": 125
},
"speed_travel_layer_0": { "value": "speed_travel" },
"speed_wall_x": { "value": "speed_wall" },
"top_bottom_pattern": { "default_value": "zigzag" },
"travel_avoid_supports": { "value": true },
"travel_retract_before_outer_wall": { "value": true },
"wall_line_count": { "value": 3 },
"wall_thickness": { "value": 1.2 }
}
}

View file

@ -20,15 +20,18 @@
},
"overrides":
{
"gantry_height": { "value": 25 },
"gantry_height": { "value": 38 },
"machine_depth": { "default_value": 220 },
"machine_head_with_fans_polygon":
{
"default_value": [
[-20, 10],
[10, 10],
[10, -10],
[-20, -10]
[-36, -18],
[-20, -42],
[6, -42],
[30, -18],
[30, 52],
[-3, 56],
[-36, 52]
]
},
"machine_heated_bed": { "default_value": true },

View file

@ -55,6 +55,7 @@
[215, 160]
]
]
}
},
"prime_tower_position_x": { "value": "350" }
}
}

View file

@ -101,6 +101,8 @@
},
"machine_height": { "default_value": 250 },
"machine_name": { "default_value": "Deltacomb DC-20 DUAL" },
"machine_width": { "default_value": 190 }
"machine_width": { "default_value": 190 },
"prime_tower_position_x": { "value": "60" },
"prime_tower_position_y": { "value": "60" }
}
}

View file

@ -131,10 +131,9 @@
"machine_width": { "default_value": 238 },
"material_adhesion_tendency": { "enabled": true },
"material_diameter": { "default_value": 1.75 },
"prime_tower_position_x": { "value": "200" },
"retraction_amount": { "default_value": 6.5 },
"retraction_speed": { "default_value": 25 },
"speed_support": { "value": "speed_wall_0" },
"speed_wall_x": { "value": "speed_wall" },
"switch_extruder_prime_speed":
{
"enabled": false,

View file

@ -62,6 +62,18 @@
"settable_per_meshgroup": false,
"type": "str"
},
"machine_extruder_end_code_duration":
{
"default_value": 0,
"description": "The time it takes to execute the end g-code, when switching away from this extruder.",
"label": "Extruder End G-Code Duration",
"minimum_value": "0",
"settable_globally": false,
"settable_per_extruder": true,
"settable_per_mesh": false,
"settable_per_meshgroup": false,
"type": "float"
},
"machine_extruder_end_pos_abs":
{
"default_value": false,
@ -108,6 +120,18 @@
"settable_per_meshgroup": false,
"type": "str"
},
"machine_extruder_start_code_duration":
{
"default_value": 0,
"description": "The time it'll take to execute the start g-code, when switching to this extruder.",
"label": "Extruder Start G-Code Duration",
"minimum_value": "0",
"settable_globally": false,
"settable_per_extruder": true,
"settable_per_mesh": false,
"settable_per_meshgroup": false,
"type": "float"
},
"machine_extruder_start_pos_abs":
{
"default_value": false,

View file

@ -1159,7 +1159,7 @@
"label": "Optimize Wall Printing Order",
"description": "Optimize the order in which walls are printed so as to reduce the number of retractions and the distance travelled. Most parts will benefit from this being enabled but some may actually take longer so please compare the print time estimates with and without optimization. First layer is not optimized when choosing brim as build plate adhesion type.",
"type": "bool",
"default_value": false,
"default_value": true,
"settable_per_mesh": true
},
"inset_direction":
@ -1396,7 +1396,6 @@
{
"label": "Z Seam Relative",
"description": "When enabled, the z seam coordinates are relative to each part's centre. When disabled, the coordinates define an absolute position on the build plate.",
"unit": "mm",
"type": "bool",
"default_value": false,
"enabled": "z_seam_type == 'back'",
@ -1479,6 +1478,7 @@
"description": "Print top surface lines in an ordering that causes them to always overlap with adjacent lines in a single direction. This takes slightly more time to print, but makes flat surfaces look more consistent.",
"type": "bool",
"value": true,
"default_value": true,
"enabled": "roofing_layer_count > 0 and top_layers > 0 and roofing_pattern != 'concentric'",
"limit_to_extruder": "roofing_extruder_nr",
"settable_per_mesh": true
@ -2603,7 +2603,7 @@
"maximum_value_warning": "120",
"settable_per_mesh": false,
"settable_per_extruder": false,
"resolve": "sum(extruderValues(\"material_shrinkage_percentage\")) / len(extruderValues(\"material_shrinkage_percentage\"))",
"resolve": "max(extruderValues(\"material_shrinkage_percentage\")) if any(extruderValues('material_is_support_material')) else sum(extruderValues(\"material_shrinkage_percentage\")) / len(extruderValues(\"material_shrinkage_percentage\"))",
"children":
{
"material_shrinkage_percentage_xy":
@ -2619,7 +2619,7 @@
"maximum_value_warning": "120",
"settable_per_mesh": false,
"settable_per_extruder": false,
"resolve": "sum(extruderValues(\"material_shrinkage_percentage_xy\")) / len(extruderValues(\"material_shrinkage_percentage_xy\"))",
"resolve": "max(extruderValues(\"material_shrinkage_percentage\")) if any(extruderValues('material_is_support_material')) else sum(extruderValues(\"material_shrinkage_percentage_xy\")) / len(extruderValues(\"material_shrinkage_percentage_xy\"))",
"value": "material_shrinkage_percentage"
},
"material_shrinkage_percentage_z":
@ -2635,7 +2635,7 @@
"maximum_value_warning": "120",
"settable_per_mesh": false,
"settable_per_extruder": false,
"resolve": "sum(extruderValues(\"material_shrinkage_percentage_z\")) / len(extruderValues(\"material_shrinkage_percentage_z\"))",
"resolve": "max(extruderValues(\"material_shrinkage_percentage_z\")) if any(extruderValues('material_is_support_material')) else sum(extruderValues(\"material_shrinkage_percentage_z\")) / len(extruderValues(\"material_shrinkage_percentage_z\"))",
"value": "material_shrinkage_percentage"
}
}
@ -4579,6 +4579,7 @@
"unit": "\u00b0C",
"type": "float",
"value": "material_print_temperature",
"default_value": 0,
"enabled": "cool_min_layer_time > 0",
"minimum_value_warning": "max(material_final_print_temperature, material_initial_print_temperature)",
"maximum_value_warning": "material_print_temperature",
@ -6113,7 +6114,101 @@
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"limit_to_extruder": "adhesion_extruder_nr",
"settable_per_mesh": false,
"settable_per_extruder": true
"settable_per_extruder": true,
"children":
{
"raft_base_margin":
{
"label": "Raft Base Extra Margin",
"description": "If the raft base is enabled, this is the extra raft area around the model which is also given a raft. Increasing this margin will create a stronger raft while using more material and leaving less area for your print.",
"unit": "mm",
"type": "float",
"value": "raft_margin",
"default_value": 15,
"minimum_value_warning": "raft_interface_line_width",
"maximum_value_warning": "min(raft_interface_margin, 20)",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"limit_to_extruder": "raft_base_extruder_nr",
"settable_per_mesh": false,
"settable_per_extruder": true
},
"raft_interface_margin":
{
"label": "Raft Middle Extra Margin",
"description": "If the raft middle is enabled, this is the extra raft area around the model which is also given a raft. Increasing this margin will create a stronger raft while using more material and leaving less area for your print.",
"unit": "mm",
"type": "float",
"value": "raft_margin",
"default_value": 15,
"minimum_value_warning": "raft_interface_line_width",
"maximum_value_warning": "min(raft_surface_margin, 20)",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"limit_to_extruder": "raft_interface_extruder_nr",
"settable_per_mesh": false,
"settable_per_extruder": true
},
"raft_surface_margin":
{
"label": "Raft Top Extra Margin",
"description": "If the raft top is enabled, this is the extra raft area around the model which is also given a raft. Increasing this margin will create a stronger raft while using more material and leaving less area for your print.",
"unit": "mm",
"type": "float",
"value": "raft_margin",
"default_value": 15,
"minimum_value_warning": "raft_interface_line_width",
"maximum_value_warning": "20",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"limit_to_extruder": "raft_surface_extruder_nr",
"settable_per_mesh": false,
"settable_per_extruder": true
}
}
},
"raft_remove_inside_corners":
{
"label": "Remove Raft Inside Corners",
"description": "Remove inside corners from the raft, causing the raft to become convex.",
"type": "bool",
"default_value": false,
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": false,
"children":
{
"raft_base_remove_inside_corners":
{
"label": "Remove Raft Base Inside Corners",
"description": "Remove inside corners from the raft base, causing the raft to become convex.",
"type": "bool",
"value": "raft_remove_inside_corners",
"default_value": false,
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": false
},
"raft_interface_remove_inside_corners":
{
"label": "Remove Raft Middle Inside Corners",
"description": "Remove inside corners from the raft middle part, causing the raft to become convex.",
"type": "bool",
"value": "raft_remove_inside_corners",
"default_value": false,
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": false
},
"raft_surface_remove_inside_corners":
{
"label": "Remove Raft Top Inside Corners",
"description": "Remove inside corners from the raft top part, causing the raft to become convex.",
"type": "bool",
"value": "raft_remove_inside_corners",
"default_value": false,
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": false
}
}
},
"raft_smoothing":
{
@ -6125,9 +6220,53 @@
"minimum_value": "0",
"minimum_value_warning": "raft_interface_line_width",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_remove_inside_corners",
"limit_to_extruder": "adhesion_extruder_nr",
"settable_per_mesh": false,
"settable_per_extruder": true
"settable_per_extruder": false,
"children":
{
"raft_base_smoothing":
{
"label": "Raft Base Smoothing",
"description": "This setting controls how much inner corners in the raft base outline are rounded. Inward corners are rounded to a semi circle with a radius equal to the value given here. This setting also removes holes in the raft outline which are smaller than such a circle.",
"unit": "mm",
"type": "float",
"value": "raft_smoothing",
"default_value": 5,
"minimum_value": "0",
"minimum_value_warning": "raft_interface_line_width",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_base_remove_inside_corners",
"settable_per_mesh": false,
"settable_per_extruder": false
},
"raft_interface_smoothing":
{
"label": "Raft Middle Smoothing",
"description": "This setting controls how much inner corners in the raft middle outline are rounded. Inward corners are rounded to a semi circle with a radius equal to the value given here. This setting also removes holes in the raft outline which are smaller than such a circle.",
"unit": "mm",
"type": "float",
"value": "raft_smoothing",
"default_value": 5,
"minimum_value": "0",
"minimum_value_warning": "raft_interface_line_width",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_interface_remove_inside_corners",
"settable_per_mesh": false,
"settable_per_extruder": false
},
"raft_surface_smoothing":
{
"label": "Raft Top Smoothing",
"description": "This setting controls how much inner corners in the raft top outline are rounded. Inward corners are rounded to a semi circle with a radius equal to the value given here. This setting also removes holes in the raft outline which are smaller than such a circle.",
"unit": "mm",
"type": "float",
"value": "raft_smoothing",
"default_value": 5,
"minimum_value": "0",
"minimum_value_warning": "raft_interface_line_width",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_surface_remove_inside_corners",
"settable_per_mesh": false,
"settable_per_extruder": false
}
}
},
"raft_airgap":
{
@ -6146,7 +6285,7 @@
"layer_0_z_overlap":
{
"label": "Initial Layer Z Overlap",
"description": "Make the first and second layer of the model overlap in the Z direction to compensate for the filament lost in the airgap. All models above the first model layer will be shifted down by this amount.",
"description": "Make the first and second layer of the model overlap in the Z direction to compensate for the filament lost in the airgap. All models above the first model layer will be shifted down by this amount.\nIt may be noted that sometimes the second layer is printed below initial layer because of this setting. This is intended behavior",
"unit": "mm",
"type": "float",
"default_value": 0.22,
@ -6158,66 +6297,53 @@
"settable_per_extruder": true,
"limit_to_extruder": "raft_surface_extruder_nr"
},
"raft_surface_layers":
"raft_base_thickness":
{
"label": "Raft Top Layers",
"description": "The number of top layers on top of the 2nd raft layer. These are fully filled layers that the model sits on. 2 layers result in a smoother top surface than 1.",
"type": "int",
"default_value": 2,
"minimum_value": "0",
"maximum_value_warning": "20",
"label": "Raft Base Thickness",
"description": "Layer thickness of the base raft layer. This should be a thick layer which sticks firmly to the printer build plate.",
"unit": "mm",
"type": "float",
"default_value": 0.3,
"value": "resolveOrValue('layer_height_0') * 1.2",
"minimum_value": "0.001",
"minimum_value_warning": "0.04",
"maximum_value_warning": "0.75 * raft_base_line_width",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": true,
"limit_to_extruder": "raft_surface_extruder_nr"
"limit_to_extruder": "raft_base_extruder_nr"
},
"raft_surface_thickness":
"raft_base_line_width":
{
"label": "Raft Top Layer Thickness",
"description": "Layer thickness of the top raft layers.",
"label": "Raft Base Line Width",
"description": "Width of the lines in the base raft layer. These should be thick lines to assist in build plate adhesion.",
"unit": "mm",
"type": "float",
"default_value": 0.1,
"value": "resolveOrValue('layer_height')",
"default_value": 0.8,
"minimum_value": "0.001",
"minimum_value_warning": "0.04",
"maximum_value_warning": "0.75 * machine_nozzle_size",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0",
"value": "machine_nozzle_size * 2",
"minimum_value_warning": "machine_nozzle_size * 0.5",
"maximum_value_warning": "machine_nozzle_size * 3",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": true,
"limit_to_extruder": "raft_surface_extruder_nr"
"limit_to_extruder": "raft_base_extruder_nr"
},
"raft_surface_line_width":
"raft_base_line_spacing":
{
"label": "Raft Top Line Width",
"description": "Width of the lines in the top surface of the raft. These can be thin lines so that the top of the raft becomes smooth.",
"label": "Raft Base Line Spacing",
"description": "The distance between the raft lines for the base raft layer. Wide spacing makes for easy removal of the raft from the build plate.",
"unit": "mm",
"type": "float",
"default_value": 0.4,
"value": "line_width",
"minimum_value": "0.001",
"minimum_value_warning": "machine_nozzle_size * 0.1",
"maximum_value_warning": "machine_nozzle_size * 2",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0",
"settable_per_mesh": false,
"settable_per_extruder": true,
"limit_to_extruder": "raft_surface_extruder_nr"
},
"raft_surface_line_spacing":
{
"label": "Raft Top Spacing",
"description": "The distance between the raft lines for the top raft layers. The spacing should be equal to the line width, so that the surface is solid.",
"unit": "mm",
"type": "float",
"default_value": 0.4,
"default_value": 1.6,
"value": "raft_base_line_width * 2",
"minimum_value": "0",
"minimum_value_warning": "raft_surface_line_width",
"maximum_value_warning": "raft_surface_line_width * 3",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0",
"value": "raft_surface_line_width",
"minimum_value_warning": "raft_base_line_width",
"maximum_value_warning": "100",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": true,
"limit_to_extruder": "raft_surface_extruder_nr"
"limit_to_extruder": "raft_base_extruder_nr"
},
"raft_interface_layers":
{
@ -6280,53 +6406,114 @@
"settable_per_extruder": true,
"limit_to_extruder": "raft_interface_extruder_nr"
},
"raft_base_thickness":
"raft_surface_layers":
{
"label": "Raft Base Thickness",
"description": "Layer thickness of the base raft layer. This should be a thick layer which sticks firmly to the printer build plate.",
"label": "Raft Top Layers",
"description": "The number of top layers on top of the 2nd raft layer. These are fully filled layers that the model sits on. 2 layers result in a smoother top surface than 1.",
"type": "int",
"default_value": 2,
"minimum_value": "0",
"maximum_value_warning": "20",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": true,
"limit_to_extruder": "raft_surface_extruder_nr"
},
"raft_surface_thickness":
{
"label": "Raft Top Layer Thickness",
"description": "Layer thickness of the top raft layers.",
"unit": "mm",
"type": "float",
"default_value": 0.3,
"value": "resolveOrValue('layer_height_0') * 1.2",
"default_value": 0.1,
"value": "resolveOrValue('layer_height')",
"minimum_value": "0.001",
"minimum_value_warning": "0.04",
"maximum_value_warning": "0.75 * raft_base_line_width",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"maximum_value_warning": "0.75 * machine_nozzle_size",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0",
"settable_per_mesh": false,
"settable_per_extruder": true,
"limit_to_extruder": "raft_base_extruder_nr"
"limit_to_extruder": "raft_surface_extruder_nr"
},
"raft_base_line_width":
"raft_surface_line_width":
{
"label": "Raft Base Line Width",
"description": "Width of the lines in the base raft layer. These should be thick lines to assist in build plate adhesion.",
"label": "Raft Top Line Width",
"description": "Width of the lines in the top surface of the raft. These can be thin lines so that the top of the raft becomes smooth.",
"unit": "mm",
"type": "float",
"default_value": 0.8,
"default_value": 0.4,
"value": "line_width",
"minimum_value": "0.001",
"value": "machine_nozzle_size * 2",
"minimum_value_warning": "machine_nozzle_size * 0.5",
"maximum_value_warning": "machine_nozzle_size * 3",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"minimum_value_warning": "machine_nozzle_size * 0.1",
"maximum_value_warning": "machine_nozzle_size * 2",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0",
"settable_per_mesh": false,
"settable_per_extruder": true,
"limit_to_extruder": "raft_base_extruder_nr"
"limit_to_extruder": "raft_surface_extruder_nr"
},
"raft_base_line_spacing":
"raft_surface_line_spacing":
{
"label": "Raft Base Line Spacing",
"description": "The distance between the raft lines for the base raft layer. Wide spacing makes for easy removal of the raft from the build plate.",
"label": "Raft Top Spacing",
"description": "The distance between the raft lines for the top raft layers. The spacing should be equal to the line width, so that the surface is solid.",
"unit": "mm",
"type": "float",
"default_value": 1.6,
"value": "raft_base_line_width * 2",
"default_value": 0.4,
"minimum_value": "0",
"minimum_value_warning": "raft_base_line_width",
"maximum_value_warning": "100",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"minimum_value_warning": "raft_surface_line_width",
"maximum_value_warning": "raft_surface_line_width * 3",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0",
"value": "raft_surface_line_width",
"settable_per_mesh": false,
"settable_per_extruder": true,
"limit_to_extruder": "raft_base_extruder_nr"
"limit_to_extruder": "raft_surface_extruder_nr"
},
"raft_wall_count":
{
"label": "Raft Wall Count",
"description": "The number of contours to print around the linear pattern of the raft.",
"type": "int",
"default_value": 1,
"minimum_value": "0",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": false,
"children":
{
"raft_base_wall_count":
{
"label": "Raft Base Wall Count",
"description": "The number of contours to print around the linear pattern in the base layer of the raft.",
"type": "int",
"default_value": 1,
"value": "raft_wall_count",
"minimum_value": "0",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": false
},
"raft_interface_wall_count":
{
"label": "Raft Middle Wall Count",
"description": "The number of contours to print around the linear pattern in the middle layers of the raft.",
"type": "int",
"default_value": 0,
"minimum_value": "0",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": false
},
"raft_surface_wall_count":
{
"label": "Raft Top Wall Count",
"description": "The number of contours to print around the linear pattern in the top layers of the raft.",
"type": "int",
"default_value": 0,
"minimum_value": "0",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": false
}
}
},
"raft_speed":
{
@ -6345,21 +6532,21 @@
"limit_to_extruder": "adhesion_extruder_nr",
"children":
{
"raft_surface_speed":
"raft_base_speed":
{
"label": "Raft Top Print Speed",
"description": "The speed at which the top raft layers are printed. These should be printed a bit slower, so that the nozzle can slowly smooth out adjacent surface lines.",
"label": "Raft Base Print Speed",
"description": "The speed at which the base raft layer is printed. This should be printed quite slowly, as the volume of material coming out of the nozzle is quite high.",
"unit": "mm/s",
"type": "float",
"default_value": 20,
"default_value": 15,
"minimum_value": "0.1",
"maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "100",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0",
"value": "raft_speed",
"maximum_value_warning": "200",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"value": "0.75 * raft_speed",
"settable_per_mesh": false,
"settable_per_extruder": true,
"limit_to_extruder": "raft_surface_extruder_nr"
"limit_to_extruder": "raft_base_extruder_nr"
},
"raft_interface_speed":
{
@ -6377,21 +6564,21 @@
"settable_per_extruder": true,
"limit_to_extruder": "raft_interface_extruder_nr"
},
"raft_base_speed":
"raft_surface_speed":
{
"label": "Raft Base Print Speed",
"description": "The speed at which the base raft layer is printed. This should be printed quite slowly, as the volume of material coming out of the nozzle is quite high.",
"label": "Raft Top Print Speed",
"description": "The speed at which the top raft layers are printed. These should be printed a bit slower, so that the nozzle can slowly smooth out adjacent surface lines.",
"unit": "mm/s",
"type": "float",
"default_value": 15,
"default_value": 20,
"minimum_value": "0.1",
"maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "200",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"value": "0.75 * raft_speed",
"maximum_value_warning": "100",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0",
"value": "raft_speed",
"settable_per_mesh": false,
"settable_per_extruder": true,
"limit_to_extruder": "raft_base_extruder_nr"
"limit_to_extruder": "raft_surface_extruder_nr"
}
}
},
@ -6411,10 +6598,10 @@
"limit_to_extruder": "adhesion_extruder_nr",
"children":
{
"raft_surface_acceleration":
"raft_base_acceleration":
{
"label": "Raft Top Print Acceleration",
"description": "The acceleration with which the top raft layers are printed.",
"label": "Raft Base Print Acceleration",
"description": "The acceleration with which the base raft layer is printed.",
"unit": "mm/s\u00b2",
"type": "float",
"default_value": 3000,
@ -6422,9 +6609,9 @@
"minimum_value": "0.1",
"minimum_value_warning": "100",
"maximum_value_warning": "10000",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('acceleration_enabled') and raft_surface_layers > 0",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('acceleration_enabled')",
"settable_per_mesh": false,
"limit_to_extruder": "raft_surface_extruder_nr"
"limit_to_extruder": "raft_base_extruder_nr"
},
"raft_interface_acceleration":
{
@ -6441,10 +6628,10 @@
"settable_per_mesh": false,
"limit_to_extruder": "raft_interface_extruder_nr"
},
"raft_base_acceleration":
"raft_surface_acceleration":
{
"label": "Raft Base Print Acceleration",
"description": "The acceleration with which the base raft layer is printed.",
"label": "Raft Top Print Acceleration",
"description": "The acceleration with which the top raft layers are printed.",
"unit": "mm/s\u00b2",
"type": "float",
"default_value": 3000,
@ -6452,9 +6639,9 @@
"minimum_value": "0.1",
"minimum_value_warning": "100",
"maximum_value_warning": "10000",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('acceleration_enabled')",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('acceleration_enabled') and raft_surface_layers > 0",
"settable_per_mesh": false,
"limit_to_extruder": "raft_base_extruder_nr"
"limit_to_extruder": "raft_surface_extruder_nr"
}
}
},
@ -6474,20 +6661,20 @@
"limit_to_extruder": "adhesion_extruder_nr",
"children":
{
"raft_surface_jerk":
"raft_base_jerk":
{
"label": "Raft Top Print Jerk",
"description": "The jerk with which the top raft layers are printed.",
"label": "Raft Base Print Jerk",
"description": "The jerk with which the base raft layer is printed.",
"unit": "mm/s",
"type": "float",
"default_value": 20,
"value": "raft_jerk",
"minimum_value": "0",
"minimum_value_warning": "5",
"maximum_value_warning": "100",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('jerk_enabled') and raft_surface_layers > 0",
"maximum_value_warning": "50",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('jerk_enabled')",
"settable_per_mesh": false,
"limit_to_extruder": "raft_surface_extruder_nr"
"limit_to_extruder": "raft_base_extruder_nr"
},
"raft_interface_jerk":
{
@ -6504,20 +6691,20 @@
"settable_per_mesh": false,
"limit_to_extruder": "raft_interface_extruder_nr"
},
"raft_base_jerk":
"raft_surface_jerk":
{
"label": "Raft Base Print Jerk",
"description": "The jerk with which the base raft layer is printed.",
"label": "Raft Top Print Jerk",
"description": "The jerk with which the top raft layers are printed.",
"unit": "mm/s",
"type": "float",
"default_value": 20,
"value": "raft_jerk",
"minimum_value": "0",
"minimum_value_warning": "5",
"maximum_value_warning": "50",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('jerk_enabled')",
"maximum_value_warning": "100",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('jerk_enabled') and raft_surface_layers > 0",
"settable_per_mesh": false,
"limit_to_extruder": "raft_base_extruder_nr"
"limit_to_extruder": "raft_surface_extruder_nr"
}
}
},
@ -6536,20 +6723,20 @@
"limit_to_extruder": "adhesion_extruder_nr",
"children":
{
"raft_surface_fan_speed":
"raft_base_fan_speed":
{
"label": "Raft Top Fan Speed",
"description": "The fan speed for the top raft layers.",
"label": "Raft Base Fan Speed",
"description": "The fan speed for the base raft layer.",
"unit": "%",
"type": "float",
"minimum_value": "0",
"maximum_value": "100",
"default_value": 0,
"value": "raft_fan_speed",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": true,
"limit_to_extruder": "raft_surface_extruder_nr"
"limit_to_extruder": "raft_base_extruder_nr"
},
"raft_interface_fan_speed":
{
@ -6566,20 +6753,20 @@
"settable_per_extruder": true,
"limit_to_extruder": "raft_interface_extruder_nr"
},
"raft_base_fan_speed":
"raft_surface_fan_speed":
{
"label": "Raft Base Fan Speed",
"description": "The fan speed for the base raft layer.",
"label": "Raft Top Fan Speed",
"description": "The fan speed for the top raft layers.",
"unit": "%",
"type": "float",
"minimum_value": "0",
"maximum_value": "100",
"default_value": 0,
"value": "raft_fan_speed",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0",
"settable_per_mesh": false,
"settable_per_extruder": true,
"limit_to_extruder": "raft_base_extruder_nr"
"limit_to_extruder": "raft_surface_extruder_nr"
}
}
}
@ -6660,7 +6847,7 @@
"unit": "mm",
"enabled": "resolveOrValue('prime_tower_mode') != 'none'",
"default_value": 200,
"value": "(resolveOrValue('machine_width') / 2 + resolveOrValue('prime_tower_size') / 2) if resolveOrValue('machine_shape') == 'elliptic' else (resolveOrValue('machine_width') - (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0) - max(max(extruderValues('travel_avoid_distance')) + max(extruderValues('support_offset')) + (extruderValue(skirt_brim_extruder_nr, 'skirt_brim_line_width') * extruderValue(skirt_brim_extruder_nr, 'skirt_line_count') * extruderValue(skirt_brim_extruder_nr, 'initial_layer_line_width_factor') / 100 + extruderValue(skirt_brim_extruder_nr, 'skirt_gap') if resolveOrValue('adhesion_type') == 'skirt' else 0) + (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0), max(map(abs, extruderValues('machine_nozzle_offset_x'))), 1)) - (resolveOrValue('machine_width') / 2 if resolveOrValue('machine_center_is_zero') else 0)",
"value": "(resolveOrValue('machine_width') / 2 + resolveOrValue('prime_tower_size') / 2) if resolveOrValue('machine_shape') == 'elliptic' else (resolveOrValue('machine_width') - (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0) - max(max(extruderValues('travel_avoid_distance')) + max(extruderValues('machine_nozzle_offset_x')) + max(extruderValues('support_offset')) + (extruderValue(skirt_brim_extruder_nr, 'skirt_brim_line_width') * extruderValue(skirt_brim_extruder_nr, 'skirt_line_count') * extruderValue(skirt_brim_extruder_nr, 'initial_layer_line_width_factor') / 100 + extruderValue(skirt_brim_extruder_nr, 'skirt_gap') if resolveOrValue('adhesion_type') == 'skirt' else 0) + (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0), max(map(abs, extruderValues('machine_nozzle_offset_x'))), 1)) - (resolveOrValue('machine_width') / 2 if resolveOrValue('machine_center_is_zero') else 0)",
"maximum_value": "(machine_width / 2 if machine_center_is_zero else machine_width) - (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0)",
"minimum_value": "resolveOrValue('prime_tower_size') + (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0) - (machine_width / 2 if machine_center_is_zero else 0)",
"settable_per_mesh": false,
@ -6674,7 +6861,7 @@
"unit": "mm",
"enabled": "resolveOrValue('prime_tower_mode') != 'none'",
"default_value": 200,
"value": "machine_depth - prime_tower_size - (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0) - max(max(extruderValues('travel_avoid_distance')) + max(extruderValues('support_offset')) + (extruderValue(skirt_brim_extruder_nr, 'skirt_brim_line_width') * extruderValue(skirt_brim_extruder_nr, 'skirt_line_count') * extruderValue(skirt_brim_extruder_nr, 'initial_layer_line_width_factor') / 100 + extruderValue(skirt_brim_extruder_nr, 'skirt_gap') if resolveOrValue('adhesion_type') == 'skirt' else 0) + (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0), max(map(abs, extruderValues('machine_nozzle_offset_y'))), 1) - (resolveOrValue('machine_depth') / 2 if resolveOrValue('machine_center_is_zero') else 0)",
"value": "machine_depth - prime_tower_size - (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0) - max(max(extruderValues('travel_avoid_distance')) + max(extruderValues('machine_nozzle_offset_y')) + max(extruderValues('support_offset')) + (extruderValue(skirt_brim_extruder_nr, 'skirt_brim_line_width') * extruderValue(skirt_brim_extruder_nr, 'skirt_line_count') * extruderValue(skirt_brim_extruder_nr, 'initial_layer_line_width_factor') / 100 + extruderValue(skirt_brim_extruder_nr, 'skirt_gap') if resolveOrValue('adhesion_type') == 'skirt' else 0) + (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0), max(map(abs, extruderValues('machine_nozzle_offset_y'))), 1) - (resolveOrValue('machine_depth') / 2 if resolveOrValue('machine_center_is_zero') else 0)",
"maximum_value": "(machine_depth / 2 - resolveOrValue('prime_tower_size') if machine_center_is_zero else machine_depth - resolveOrValue('prime_tower_size')) - (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0)",
"minimum_value": "(machine_depth / -2 if machine_center_is_zero else 0) + (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0)",
"settable_per_mesh": false,
@ -6694,7 +6881,7 @@
{
"value": "resolveOrValue('adhesion_type') in ['raft', 'brim']",
"label": "Prime Tower Base",
"description": "Prime-towers might need the extra adhesion afforded by a brim or raft, even if the model doesn't.",
"description": "By enabling this setting, your prime-tower will get a brim, even if the model doesn't. If you want a sturdier base for a high tower, you can increase the base height.",
"type": "bool",
"enabled": "resolveOrValue('prime_tower_mode') != 'none' and resolveOrValue('adhesion_type') != 'raft'",
"default_value": false,
@ -6705,21 +6892,21 @@
{
"value": "resolveOrValue('raft_margin') if resolveOrValue('adhesion_type') == 'raft' else resolveOrValue('brim_width')",
"label": "Prime Tower Base Size",
"description": "The width of the prime tower base.",
"description": "The width of the prime tower brim/base. A larger base enhances adhesion to the build plate, but also reduces the effective print area.",
"type": "float",
"unit": "mm",
"enabled": "resolveOrValue('prime_tower_mode') != 'none' and (resolveOrValue('prime_tower_brim_enable') or resolveOrValue('adhesion_type') == 'raft')",
"default_value": "resolveOrValue('brim_width')",
"default_value": 1.2,
"minimum_value": "0",
"maximum_value": "min(0.5 * machine_width, 0.5 * machine_depth)",
"settable_per_mesh": false,
"settable_per_extruder": false
"settable_per_extruder": false
},
"prime_tower_base_height":
{
"value": "resolveOrValue('layer_height')",
"label": "Prime Tower Base Height",
"description": "The height of the prime tower base.",
"description": "The height of the prime tower base. Increasing this value will result in a more sturdy prime tower because the base will be wider. If this setting is too low, the prime tower will not have a sturdy base.",
"type": "float",
"unit": "mm",
"enabled": "resolveOrValue('prime_tower_mode') != 'none' and (resolveOrValue('prime_tower_brim_enable') or resolveOrValue('adhesion_type') == 'raft')",
@ -6731,8 +6918,8 @@
},
"prime_tower_base_curve_magnitude":
{
"label": "Prime Tower Base Curve Magnitude",
"description": "The magnitude factor used for the curve of the prime tower foot.",
"label": "Prime Tower Base Slope",
"description": "The magnitude factor used for the slope of the prime tower base. If you increase this value, the base will become slimmer. If you decrease it, the base will become thicker.",
"type": "float",
"enabled": "resolveOrValue('prime_tower_mode') != 'none' and (resolveOrValue('prime_tower_brim_enable') or resolveOrValue('adhesion_type') == 'raft')",
"default_value": 4,
@ -7858,7 +8045,7 @@
"type": "float",
"minimum_value": "5",
"minimum_value_warning": "50",
"maximum_value_warning": "150",
"maximum_value_warning": "250",
"enabled": "bridge_settings_enabled",
"settable_per_mesh": true
},
@ -7885,7 +8072,7 @@
"type": "float",
"minimum_value": "5",
"minimum_value_warning": "50",
"maximum_value_warning": "150",
"maximum_value_warning": "250",
"enabled": "bridge_settings_enabled",
"settable_per_mesh": true
},
@ -8293,28 +8480,6 @@
"settable_per_mesh": true,
"settable_per_extruder": true
},
"raft_remove_inside_corners":
{
"label": "Remove Raft Inside Corners",
"description": "Remove inside corners from the raft, causing the raft to become convex.",
"type": "bool",
"default_value": false,
"resolve": "any(extruderValues('raft_remove_inside_corners'))",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": false
},
"raft_base_wall_count":
{
"label": "Raft Base Wall Count",
"description": "The number of contours to print around the linear pattern in the base layer of the raft.",
"type": "int",
"default_value": 1,
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"resolve": "max(extruderValues('raft_base_wall_count'))",
"settable_per_mesh": false,
"settable_per_extruder": false
},
"group_outer_walls":
{
"label": "Group Outer Walls",
@ -8325,6 +8490,88 @@
}
}
},
"ppr":
{
"label": "Print Process Reporting",
"type": "category",
"icon": "DocumentFilled",
"description": "Reporting events that go out of set thresholds",
"enabled": false,
"children":
{
"ppr_enable":
{
"label": "Enable Print Process Reporting",
"description": "Enable print process reporting for setting threshold values for possible fault detection.",
"type": "bool",
"enabled": false,
"default_value": false,
"value": false,
"settable_per_mesh": false,
"settable_per_extruder": false
},
"flow_warn_limit":
{
"label": "Flow Warning",
"description": "Limit on the flow warning for detection.",
"default_value": 15.0,
"enabled": "ppr_enable",
"unit": "%",
"type": "float",
"settable_per_extruder": true
},
"flow_anomaly_limit":
{
"label": "Flow Limit",
"description": "Limit on flow anomaly for detection.",
"default_value": 25.0,
"enabled": "ppr_enable",
"unit": "%",
"type": "float",
"settable_per_extruder": true
},
"print_temp_warn_limit":
{
"label": "Print temperature Warning",
"description": "Limit on Print temperature warning for detection.",
"unit": "\u00b0C",
"type": "float",
"default_value": 3.0,
"enabled": "ppr_enable",
"settable_per_extruder": true
},
"print_temp_anomaly_limit":
{
"label": "Print temperature Limit",
"description": "Limit on Print Temperature anomaly for detection.",
"unit": "\u00b0C",
"type": "float",
"default_value": 7.0,
"enabled": "ppr_enable",
"settable_per_extruder": true
},
"bv_temp_warn_limit":
{
"label": "Build Volume temperature Warning",
"description": "Limit on Build Volume Temperature warning for detection.",
"unit": "\u00b0C",
"type": "float",
"default_value": 7.5,
"enabled": "ppr_enable",
"settable_per_extruder": false
},
"bv_temp_anomaly_limit":
{
"label": "Build Volume temperature Limit",
"description": "Limit on Build Volume temperature Anomaly for detection.",
"unit": "\u00b0C",
"type": "float",
"default_value": 10.0,
"enabled": "ppr_enable",
"settable_per_extruder": false
}
}
},
"command_line_settings":
{
"label": "Command Line Settings",

View file

@ -41,10 +41,9 @@
"infill_line_width": { "value": "line_width + 0.1" },
"infill_overlap": { "value": 30 },
"infill_pattern": { "value": "'lines' if infill_sparse_density > 50 else 'cubic'" },
"infill_sparse_density": { "value": 20 },
"infill_wipe_dist": { "value": 0.0 },
"layer_height_0": { "value": 0.2 },
"machine_buildplate_type": { "value": "glass" },
"machine_buildplate_type": { "value": "'glass'" },
"machine_center_is_zero": { "default_value": false },
"machine_end_gcode": { "default_value": "G91 ;use relative coordinates\nG1 E-4 F1500 ;retract the filament\nG1 X5 Y5 Z0.2 F5000 ;wipe\nG1 Z5 F1500 ;raise z\nG90 ;use absolute coordinates\nG1 X10 Y{machine_depth} F5000 ;park print head\n\nM107 ;turn off fan\nM104 S0 ;turn off hotend\nM140 S0 ;turn off heatbed\nM84 ;disable motors" },
"machine_heated_bed": { "default_value": true },

View file

@ -0,0 +1,48 @@
{
"version": 2,
"name": "Flying Bear Ghost 6",
"inherits": "flyingbear_base",
"metadata":
{
"visible": true,
"author": "barrnet",
"platform": "flyingbear_platform.obj",
"platform_texture": "flyingbear_platform.png",
"quality_definition": "flyingbear_base"
},
"overrides":
{
"acceleration_enabled": { "value": false },
"acceleration_print": { "value": 1500 },
"acceleration_roofing": { "enabled": "acceleration_enabled and roofing_layer_count > 0 and top_layers > 0" },
"acceleration_travel": { "value": 3000 },
"acceleration_travel_layer_0": { "value": "acceleration_travel" },
"jerk_enabled": { "value": false },
"jerk_print": { "value": 20 },
"jerk_travel": { "value": "jerk_print" },
"jerk_travel_layer_0": { "value": "jerk_travel" },
"machine_acceleration": { "value": 1500 },
"machine_depth": { "default_value": 210 },
"machine_height": { "default_value": 210 },
"machine_max_acceleration_e": { "value": 80000 },
"machine_max_acceleration_x": { "value": 1000 },
"machine_max_acceleration_y": { "value": 1000 },
"machine_max_acceleration_z": { "value": 200 },
"machine_max_feedrate_e": { "value": 70 },
"machine_max_feedrate_x": { "value": 200 },
"machine_max_feedrate_y": { "value": 200 },
"machine_max_feedrate_z": { "value": 20 },
"machine_max_jerk_e": { "value": 5.0 },
"machine_max_jerk_xy": { "value": 15 },
"machine_max_jerk_z": { "value": 0.4 },
"machine_name": { "default_value": "Flying Bear Ghost 6" },
"machine_steps_per_mm_e": { "default_value": 405 },
"machine_steps_per_mm_x": { "default_value": 160 },
"machine_steps_per_mm_y": { "default_value": 160 },
"machine_steps_per_mm_z": { "default_value": 800 },
"machine_width": { "default_value": 255 },
"retraction_amount": { "value": 0.8 },
"retraction_extrusion_window": { "value": 1.5 },
"retraction_speed": { "default_value": 35 }
}
}

View file

@ -20,10 +20,9 @@
"cool_fan_full_at_height": { "value": "layer_height_0 + 2 * layer_height" },
"cool_min_layer_time": { "value": 10 },
"gantry_height": { "value": 40 },
"jerk_enabled": { "value": false },
"jerk_print": { "value": 8 },
"jerk_travel": { "value": "jerk_print" },
"jerk_travel_layer_0": { "value": " jerk_travel" },
"jerk_travel_layer_0": { "value": "jerk_travel" },
"machine_depth": { "default_value": 235 },
"machine_end_gcode": { "default_value": "; SC-10 Custom End G-code\nG4 ; Wait\nM220 S100 ; Reset Speed factor override percentage to default (100%)\nM221 S100 ; Reset Extrude factor override percentage to default (100%)\nG91 ; Set coordinates to relative\nG1 F1800 E-3 ; Retract filament 3 mm to prevent oozing\nG1 F3000 Z20 ; Move Z Axis up 20 mm to allow filament ooze freely\nG90 ; Set coordinates to absolute\nG1 X0 Y{machine_depth} F1000 ; Move Heat Bed to the front for easy print removal\nM84 ; Disable stepper motors\n; End of custom end GCode" },
"machine_head_with_fans_polygon":

View file

@ -78,7 +78,7 @@
"minimum_value_warning": "0.01"
},
"retraction_amount": { "default_value": 2 },
"retraction_combing": { "value": "off" },
"retraction_combing": { "value": "'off'" },
"retraction_combing_max_distance": { "default_value": 0.5 },
"retraction_count_max": { "default_value": 100 },
"retraction_extrusion_window":

View file

@ -82,6 +82,6 @@
"travel_avoid_supports": { "value": true },
"travel_retract_before_outer_wall": { "value": true },
"wall_thickness": { "value": "line_width * 2" },
"z_seam_corner": { "value": "z_seam_corner_weighted" }
"z_seam_corner": { "value": "'z_seam_corner_weighted'" }
}
}

View file

@ -82,6 +82,6 @@
"travel_avoid_supports": { "value": true },
"travel_retract_before_outer_wall": { "value": true },
"wall_thickness": { "value": "line_width * 2" },
"z_seam_corner": { "value": "z_seam_corner_weighted" }
"z_seam_corner": { "value": "'z_seam_corner_weighted'" }
}
}

View file

@ -0,0 +1,18 @@
{
"version": 2,
"name": "Multicomp Pro MCPI-200",
"inherits": "goofoo_near",
"metadata":
{
"visible": true,
"author": "Woosh",
"manufacturer": "Multicomp Pro"
},
"overrides":
{
"machine_depth": { "default_value": 200 },
"machine_height": { "default_value": 200 },
"machine_name": { "default_value": "Multicomp Pro MCPI-200" },
"machine_width": { "default_value": 200 }
}
}

View file

@ -0,0 +1,18 @@
{
"version": 2,
"name": "Renkforce Pro 10+",
"inherits": "goofoo_near",
"metadata":
{
"visible": true,
"author": "Woosh (based on RF100.ini by Conrad Electronic SE)",
"manufacturer": "Renkforce"
},
"overrides":
{
"machine_depth": { "default_value": 360 },
"machine_height": { "default_value": 400 },
"machine_name": { "default_value": "Renkforce Pro 10+" },
"machine_width": { "default_value": 360 }
}
}

View file

@ -13,8 +13,6 @@
"machine_acceleration": { "value": 1000 },
"machine_max_feedrate_e": { "value": 40 },
"machine_max_jerk_xy": { "value": 5 },
"material_print_temperature": { "value": 195 },
"retraction_speed": { "default_value": 30 },
"z_seam_corner": { "value": "'z_seam_corner_weighted'" }
}
}

View file

@ -150,6 +150,7 @@
"value": "resolveOrValue('print_sequence') != 'one_at_a_time'"
},
"prime_tower_enable": { "default_value": true },
"prime_tower_position_x": { "value": "185" },
"prime_tower_wipe_enabled": { "default_value": false },
"retraction_amount": { "value": "6.5" },
"retraction_hop": { "value": "2" },

View file

@ -1,11 +1,11 @@
{
"version": 2,
"name": "Makerbot Method Base Profile",
"name": "UltiMaker Method Base Profile",
"inherits": "ultimaker",
"metadata":
{
"visible": false,
"author": "Ultimaker",
"author": "UltiMaker",
"manufacturer": "Ultimaker B.V.",
"file_formats": "application/x-makerbot",
"platform": "ultimaker_method_platform.stl",
@ -69,7 +69,6 @@
"preferred_material": "generic_pla_175",
"preferred_quality_type": "fast",
"preferred_variant_name": "1A",
"supports_material_export": true,
"supports_network_connection": true,
"supports_usb_connection": false,
"variants_name": "Extruder",
@ -321,19 +320,17 @@
"layer_start_y": { "value": "sum(extruderValues('machine_extruder_start_pos_y')) / len(extruderValues('machine_extruder_start_pos_y'))" },
"machine_acceleration": { "default_value": 3000 },
"machine_center_is_zero": { "value": true },
"machine_depth": { "default_value": 190 },
"machine_end_gcode": { "default_value": "" },
"machine_extruder_count": { "default_value": 2 },
"machine_gcode_flavor": { "default_value": "Griffin" },
"machine_heated_bed": { "default_value": false },
"machine_heated_build_volume": { "default_value": true },
"machine_height": { "default_value": 196 },
"machine_min_cool_heat_time_window": { "value": 15 },
"machine_name": { "default_value": "Makerbot Method" },
"machine_name": { "default_value": "UltiMaker Method" },
"machine_nozzle_cool_down_speed": { "value": 0.8 },
"machine_nozzle_heat_up_speed": { "value": 3.5 },
"machine_scale_fan_speed_zero_to_one": { "value": true },
"machine_start_gcode": { "default_value": "" },
"machine_width": { "default_value": 150 },
"material_bed_temperature": { "enabled": "machine_heated_bed" },
"material_bed_temperature_layer_0": { "enabled": "machine_heated_bed" },
"material_final_print_temperature": { "value": "material_print_temperature-10" },
@ -341,7 +338,6 @@
"material_initial_print_temperature": { "value": "material_print_temperature-10" },
"material_print_temperature": { "value": "default_material_print_temperature" },
"material_shrinkage_percentage": { "enabled": true },
"material_shrinkage_percentage_z": { "resolve": "0.9852*sum(extruderValues(\"material_shrinkage_percentage_z\")) / len(extruderValues(\"material_shrinkage_percentage_z\"))" },
"min_wall_line_width": { "value": 0.4 },
"minimum_support_area": { "value": 0.1 },
"multiple_mesh_overlap": { "value": 0 },
@ -349,27 +345,24 @@
"prime_blob_enable": { "enabled": false },
"prime_tower_base_curve_magnitude": { "value": 2 },
"prime_tower_base_height": { "value": 6 },
"prime_tower_base_size": { "value": 6 },
"prime_tower_base_size": { "value": 10 },
"prime_tower_enable": { "value": false },
"prime_tower_flow": { "value": "material_flow" },
"prime_tower_line_width": { "value": 1 },
"prime_tower_raft_base_line_spacing": { "value": "raft_base_line_width" },
"prime_tower_wipe_enabled": { "value": true },
"print_sequence":
{
"enabled": false,
"value": "all_at_once"
},
"print_sequence": { "enabled": false },
"raft_base_line_spacing": { "value": "2*raft_base_line_width" },
"raft_base_line_width": { "value": 1.4 },
"raft_base_speed": { "value": 5 },
"raft_base_speed": { "value": 10 },
"raft_base_thickness": { "value": 0.8 },
"raft_interface_extruder_nr": { "value": "raft_surface_extruder_nr" },
"raft_interface_layers": { "value": 2 },
"raft_interface_line_width": { "value": 1.2 },
"raft_interface_line_width": { "value": 0.7 },
"raft_interface_speed": { "value": 90 },
"raft_interface_thickness": { "value": 0.3 },
"raft_margin": { "value": 3 },
"raft_surface_extruder_nr": { "value": "int(anyExtruderWithMaterial('material_is_support_material'))" },
"raft_surface_extruder_nr": { "value": "int(anyExtruderWithMaterial('material_is_support_material')) if support_enable and extruderValue(support_extruder_nr,'material_is_support_material') else raft_base_extruder_nr" },
"retraction_amount": { "value": 0.75 },
"retraction_combing": { "value": "'off'" },
"retraction_combing_max_distance": { "value": "speed_travel / 10" },
@ -428,7 +421,7 @@
"switch_extruder_retraction_speeds": { "value": "retraction_speed" },
"top_bottom_thickness": { "value": "5*layer_height" },
"travel_avoid_distance": { "value": "3 if extruders_enabled_count > 1 else machine_nozzle_tip_outer_diameter / 2 * 1.5" },
"travel_avoid_supports": { "value": true },
"travel_avoid_other_parts": { "value": false },
"wall_0_inset": { "value": 0 },
"wall_0_material_flow": { "value": "material_flow" },
"wall_0_wipe_dist": { "value": 0 },

View file

@ -1,11 +1,11 @@
{
"version": 2,
"name": "Makerbot Method X",
"name": "UltiMaker Method X",
"inherits": "ultimaker_method_base",
"metadata":
{
"visible": true,
"author": "Ultimaker",
"author": "UltiMaker",
"manufacturer": "Ultimaker B.V.",
"file_formats": "application/x-makerbot",
"platform": "ultimaker_method_platform.stl",
@ -69,12 +69,13 @@
"platform_offset": [
0,
0,
0
16
],
"platform_texture": "MakerbotMethod.png",
"preferred_material": "ultimaker_absr_175",
"preferred_quality_type": "draft",
"preferred_variant_name": "1XA",
"reference_machine_id": "lava_f",
"supports_network_connection": true,
"supports_usb_connection": false,
"variant_definition": "ultimaker_methodx",
@ -83,6 +84,40 @@
},
"overrides":
{
"machine_name": { "default_value": "Makerbot Method X" }
"machine_depth": { "default_value": 236.48 },
"machine_disallowed_areas":
{
"default_value": [
[
[-141.65, -118.11],
[141.65, -118.11],
[141.65, -94],
[-141.65, -94]
],
[
[-141.65, 118.37],
[141.65, 118.37],
[141.65, 94],
[-141.65, 94]
],
[
[-141.65, -118.11],
[-75, -118.11],
[-75, 118.37],
[-141.65, 118.37]
],
[
[75, -118.11],
[141.65, -118.11],
[141.65, 118.37],
[75, 118.37]
]
]
},
"machine_height": { "default_value": 196 },
"machine_name": { "default_value": "UltiMaker Method X" },
"machine_width": { "default_value": 283.3 },
"prime_tower_position_x": { "value": "(150 / 2 + resolveOrValue('prime_tower_size') / 2) if resolveOrValue('machine_shape') == 'elliptic' else (150 - (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0) - max(max(extruderValues('travel_avoid_distance')) + max(extruderValues('support_offset')) + (extruderValue(skirt_brim_extruder_nr, 'skirt_brim_line_width') * extruderValue(skirt_brim_extruder_nr, 'skirt_line_count') * extruderValue(skirt_brim_extruder_nr, 'initial_layer_line_width_factor') / 100 + extruderValue(skirt_brim_extruder_nr, 'skirt_gap') if resolveOrValue('adhesion_type') == 'skirt' else 0) + (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0), max(map(abs, extruderValues('machine_nozzle_offset_x'))), 1)) - (150 / 2 if resolveOrValue('machine_center_is_zero') else 0)" },
"prime_tower_position_y": { "value": "190 - prime_tower_size - (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0) - max(max(extruderValues('travel_avoid_distance')) + max(extruderValues('support_offset')) + (extruderValue(skirt_brim_extruder_nr, 'skirt_brim_line_width') * extruderValue(skirt_brim_extruder_nr, 'skirt_line_count') * extruderValue(skirt_brim_extruder_nr, 'initial_layer_line_width_factor') / 100 + extruderValue(skirt_brim_extruder_nr, 'skirt_gap') if resolveOrValue('adhesion_type') == 'skirt' else 0) + (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0), max(map(abs, extruderValues('machine_nozzle_offset_y'))), 1) - (190 / 2 if resolveOrValue('machine_center_is_zero') else 0)" }
}
}

View file

@ -1,11 +1,11 @@
{
"version": 2,
"name": "Makerbot Method XL",
"name": "UltiMaker Method XL",
"inherits": "ultimaker_methodx",
"metadata":
{
"visible": true,
"author": "Ultimaker",
"author": "UltiMaker",
"manufacturer": "Ultimaker B.V.",
"file_formats": "application/x-makerbot",
"platform": "ultimaker_method_xl_platform.stl",
@ -25,6 +25,7 @@
],
"platform_texture": "MakerbotMethod.png",
"preferred_quality_type": "draft",
"reference_machine_id": "magma_10",
"supports_network_connection": true,
"supports_usb_connection": false,
"variants_name": "Extruder",
@ -32,12 +33,42 @@
},
"overrides":
{
"machine_depth": { "default_value": 305 },
"machine_depth": { "default_value": 320 },
"machine_disallowed_areas":
{
"default_value": [
[
[-204, -160],
[204, -160],
[204, -154.5],
[-204, -154.5]
],
[
[-204, 160],
[204, 160],
[204, 154.5],
[-204, 154.5]
],
[
[-205, -160],
[-154.5, -160],
[-154.5, 160],
[-205, 160]
],
[
[154.5, -160],
[205, -160],
[205, 160],
[154.5, 160]
]
]
},
"machine_heated_bed": { "default_value": true },
"machine_height": { "default_value": 317 },
"machine_name": { "default_value": "Makerbot Method XL" },
"machine_width": { "default_value": 305 },
"material_shrinkage_percentage_z": { "resolve": "sum(extruderValues(\"material_shrinkage_percentage_z\")) / len(extruderValues(\"material_shrinkage_percentage_z\"))" },
"machine_height": { "default_value": 320 },
"machine_name": { "default_value": "UltiMaker Method XL" },
"machine_width": { "default_value": 410 },
"prime_tower_position_x": { "value": "(305 - (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0) - max(max(extruderValues('travel_avoid_distance')) + max(extruderValues('support_offset')) + (extruderValue(skirt_brim_extruder_nr, 'skirt_brim_line_width') * extruderValue(skirt_brim_extruder_nr, 'skirt_line_count') * extruderValue(skirt_brim_extruder_nr, 'initial_layer_line_width_factor') / 100 + extruderValue(skirt_brim_extruder_nr, 'skirt_gap') if resolveOrValue('adhesion_type') == 'skirt' else 0) + (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0), max(map(abs, extruderValues('machine_nozzle_offset_x'))), 1)) - (305 / 2)" },
"prime_tower_position_y": { "value": "305 - prime_tower_size - (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0) - max(max(extruderValues('travel_avoid_distance')) + max(extruderValues('support_offset')) + (extruderValue(skirt_brim_extruder_nr, 'skirt_brim_line_width') * extruderValue(skirt_brim_extruder_nr, 'skirt_line_count') * extruderValue(skirt_brim_extruder_nr, 'initial_layer_line_width_factor') / 100 + extruderValue(skirt_brim_extruder_nr, 'skirt_gap') if resolveOrValue('adhesion_type') == 'skirt' else 0) + (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0), max(map(abs, extruderValues('machine_nozzle_offset_y'))), 1) - (305 / 2)" },
"speed_travel": { "value": 500 }
}
}

View file

@ -1,11 +1,11 @@
{
"version": 2,
"name": "Ultimaker S3",
"name": "UltiMaker S3",
"inherits": "ultimaker",
"metadata":
{
"visible": true,
"author": "Ultimaker",
"author": "UltiMaker",
"manufacturer": "Ultimaker B.V.",
"file_formats": "application/x-ufp;text/x-gcode",
"platform": "ultimaker_s3_platform.obj",

View file

@ -1,11 +1,11 @@
{
"version": 2,
"name": "Ultimaker S5",
"name": "UltiMaker S5",
"inherits": "ultimaker",
"metadata":
{
"visible": true,
"author": "Ultimaker",
"author": "UltiMaker",
"manufacturer": "Ultimaker B.V.",
"file_formats": "application/x-ufp;text/x-gcode",
"platform": "ultimaker_s5_platform.obj",

View file

@ -1,11 +1,11 @@
{
"version": 2,
"name": "Ultimaker S7",
"name": "UltiMaker S7",
"inherits": "ultimaker_s5",
"metadata":
{
"visible": true,
"author": "Ultimaker",
"author": "UltiMaker",
"manufacturer": "Ultimaker B.V.",
"file_formats": "application/x-ufp;text/x-gcode",
"platform": "ultimaker_s7_platform.obj",

View file

@ -47,10 +47,8 @@
"infill_enable_travel_optimization": { "value": "True" },
"infill_line_width": { "value": "round(line_width * 1.1, 2)" },
"infill_pattern": { "value": "'gyroid'" },
"initial_layer_line_width_factor": { "value": "100" },
"layer_height_0": { "value": "layer_height" },
"line_width": { "value": "machine_nozzle_size" },
"machine_buildplate_type": { "value": "glass" },
"machine_buildplate_type": { "value": "'glass'" },
"machine_center_is_zero": { "default_value": false },
"machine_depth": { "default_value": 220 },
"machine_end_gcode": { "default_value": "G91\nG1 E-1 F600\nG1 Z+1 E-3 X-20 Y-20 F4800\nM104 S0\nM106 S0\nM140 S0\nM220 S100\nM221 S100\nG28\nG90\nM84\n;\n" },

View file

@ -222,7 +222,7 @@
"raft_surface_speed": { "value": 40.0 },
"raft_surface_thickness": { "value": 0.25 },
"retraction_amount": { "default_value": 3 },
"retraction_combing": { "value": "off" },
"retraction_combing": { "value": "'off'" },
"retraction_extrusion_window": { "value": 1.0 },
"retraction_hop_after_extruder_switch": { "default_value": false },
"retraction_min_travel": { "value": 0.8 },

View file

@ -46,10 +46,8 @@
"infill_enable_travel_optimization": { "value": "True" },
"infill_line_width": { "value": "round(line_width * 1.1, 2)" },
"infill_pattern": { "value": "'gyroid'" },
"initial_layer_line_width_factor": { "value": "100" },
"layer_height_0": { "value": "layer_height" },
"line_width": { "value": "machine_nozzle_size" },
"machine_buildplate_type": { "value": "glass" },
"machine_buildplate_type": { "value": "'glass'" },
"machine_center_is_zero": { "default_value": false },
"machine_depth": { "default_value": 200 },
"machine_end_gcode": { "default_value": ";---- Ending Script Start ----\nM104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-4 F300 ;retract the filament a bit before lifting the nozzle to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F5000 ;move Z up a bit and retract filament even more\nG28 Z0 ;move bed down\nG28 X0 Y0 ;move X/Y to min endstops so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning\nM107 ;switch off cooling fan\nM355 S0 P0 ;switch off case light\n;---- Ending Script End ----\n" },

View file

@ -0,0 +1,16 @@
{
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata":
{
"machine": "anycubic_kobra2",
"position": "0"
},
"overrides":
{
"extruder_nr": { "default_value": 0 },
"machine_nozzle_size": { "default_value": 0.4 },
"material_diameter": { "default_value": 1.75 }
}
}

View file

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Cura 5.1\n"
"Report-Msgid-Bugs-To: plugins@ultimaker.com\n"
"POT-Creation-Date: 2023-10-31 19:13+0000\n"
"POT-Creation-Date: 2023-11-24 12:51+0000\n"
"PO-Revision-Date: 2023-02-16 20:35+0100\n"
"Last-Translator: Miroslav Šustek <sustmidown@centrum.cz>\n"
"Language-Team: DenyCZ <www.github.com/DenyCZ>\n"
@ -461,6 +461,10 @@ msgctxt "build_volume_temperature label"
msgid "Build Volume Temperature"
msgstr "Teplota sestavení"
msgctxt "prime_tower_brim_enable description"
msgid "By enabling this setting, your prime-tower will get a brim, even if the model doesn't. If you want a sturdier base for a high tower, you can increase the base height."
msgstr ""
msgctxt "center_object label"
msgid "Center Object"
msgstr "Centrovat objekt"
@ -2519,10 +2523,6 @@ msgctxt "prime_tower_brim_enable label"
msgid "Prime Tower Base"
msgstr ""
msgctxt "prime_tower_base_curve_magnitude label"
msgid "Prime Tower Base Curve Magnitude"
msgstr ""
msgctxt "prime_tower_base_height label"
msgid "Prime Tower Base Height"
msgstr ""
@ -2531,6 +2531,10 @@ msgctxt "prime_tower_base_size label"
msgid "Prime Tower Base Size"
msgstr ""
msgctxt "prime_tower_base_curve_magnitude label"
msgid "Prime Tower Base Slope"
msgstr ""
msgctxt "prime_tower_flow label"
msgid "Prime Tower Flow"
msgstr "Průtok u hlavní věžě"
@ -2567,10 +2571,6 @@ msgctxt "prime_tower_position_y label"
msgid "Prime Tower Y Position"
msgstr "Pozice Y hlavní věže"
msgctxt "prime_tower_brim_enable description"
msgid "Prime-towers might need the extra adhesion afforded by a brim or raft, even if the model doesn't."
msgstr ""
msgctxt "acceleration_print label"
msgid "Print Acceleration"
msgstr "Akcelerace tisku"
@ -3988,7 +3988,7 @@ msgid "The height of the initial layer in mm. A thicker initial layer makes adhe
msgstr "Výška počáteční vrstvy v mm. Silnější počáteční vrstva usnadňuje přilnavost k montážní desce."
msgctxt "prime_tower_base_height description"
msgid "The height of the prime tower base."
msgid "The height of the prime tower base. Increasing this value will result in a more sturdy prime tower because the base will be wider. If this setting is too low, the prime tower will not have a sturdy base."
msgstr ""
msgctxt "support_bottom_stair_step_height description"
@ -4064,7 +4064,7 @@ msgid "The length of material retracted during a retraction move."
msgstr "Délka materiálu zasunutého během pohybu zasunutí."
msgctxt "prime_tower_base_curve_magnitude description"
msgid "The magnitude factor used for the curve of the prime tower foot."
msgid "The magnitude factor used for the slope of the prime tower base. If you increase this value, the base will become slimmer. If you decrease it, the base will become thicker."
msgstr ""
msgctxt "machine_buildplate_type description"
@ -4700,7 +4700,7 @@ msgid "The width of the interlocking structure beams."
msgstr "Šířka paprsků vzájemného propletení."
msgctxt "prime_tower_base_size description"
msgid "The width of the prime tower base."
msgid "The width of the prime tower brim/base. A larger base enhances adhesion to the build plate, but also reduces the effective print area."
msgstr ""
msgctxt "prime_tower_size description"
@ -5491,655 +5491,42 @@ msgctxt "travel description"
msgid "travel"
msgstr "cestování"
#~ msgctxt "machine_head_with_fans_polygon description"
#~ msgid "A 2D silhouette of the print head (fan caps included)."
#~ msgstr "2D silueta tiskové hlavy (včetně krytů ventilátoru)."
msgctxt "gradual_flow_discretisation_step_size description"
msgid "Duration of each step in the gradual flow change"
msgstr "Doba trvání každého kroku v postupné změně průtoku"
#~ msgctxt "spaghetti_infill_extra_volume description"
#~ msgid "A correction term to adjust the total volume being extruded each time when filling spaghetti."
#~ msgstr "Korekční termín pro úpravu celkového objemu, který se vytlačuje pokaždé, když se plní špagety."
msgctxt "gradual_flow_enabled description"
msgid "Enable gradual flow changes. When enabled, the flow is gradually increased/decreased to the target flow. This is useful for printers with a bowden tube where the flow is not immediately changed when the extruder motor starts/stops."
msgstr "Povolit postupné změny průtoku. Když je povoleno, průtok se postupně zvyšuje / snižuje na cílový průtok. Toto je užitečné pro tiskárny s Bowdenovou trubicí, kde se průtok okamžitě nezmění, když se spustí / zastaví extrudér."
#~ msgctxt "wall_add_middle_threshold label"
#~ msgid "Add Middle Line Threshold"
#~ msgstr "Mez pro přidání prostřední čáry"
msgctxt "reset_flow_duration description"
msgid "For any travel move longer than this value, the material flow is reset to the paths target flow"
msgstr "Pro jakýkoli pohyb delší než tato hodnota se materiálový průtok resetuje na cílový průtok dráhy"
#~ msgctxt "spaghetti_flow description"
#~ msgid "Adjusts the density of the spaghetti infill. Note that the Infill Density only controls the line spacing of the filling pattern, not the amount of extrusion for spaghetti infill."
#~ msgstr "Upravuje hustotu výplně špaget. Mějte na paměti, že hustota výplně řídí pouze rozteč linií výplňového vzoru, nikoli velikost výtluku pro výplň špaget."
msgctxt "gradual_flow_discretisation_step_size label"
msgid "Gradual flow discretisation step size"
msgstr "Velikost kroku diskretizace postupné změny průtoku"
#~ msgctxt "hole_xy_offset description"
#~ msgid "Amount of offset applied to all holes in each layer. Positive values increase the size of the holes, negative values reduce the size of the holes."
#~ msgstr "Množství ofsetu aplikovaného na všechny díry v každé vrstvě. Pozitivní hodnoty zvětšují velikost děr, záporné hodnoty snižují velikost děr."
msgctxt "gradual_flow_enabled label"
msgid "Gradual flow enabled"
msgstr "Postupné změny průtoku povoleny"
#~ msgctxt "machine_use_extruder_offset_to_offset_coords description"
#~ msgid "Apply the extruder offset to the coordinate system."
#~ msgstr "Naneste odsazení extrudéru na souřadnicový systém."
msgctxt "max_flow_acceleration label"
msgid "Gradual flow max acceleration"
msgstr "Maximální zrychlení postupných změn průtoku"
#~ msgctxt "material_flow_dependent_temperature label"
#~ msgid "Auto Temperature"
#~ msgstr "Automatická teplota"
msgctxt "layer_0_max_flow_acceleration label"
msgid "Initial layer max flow acceleration"
msgstr "Maximální zrychlení průtoku pro první vrstvu"
#~ msgctxt "material_flow_dependent_temperature description"
#~ msgid "Change the temperature for each layer automatically with the average flow speed of that layer."
#~ msgstr "Změňte teplotu pro každou vrstvu automaticky s průměrnou rychlostí průtoku této vrstvy."
msgctxt "max_flow_acceleration description"
msgid "Maximum acceleration for gradual flow changes"
msgstr "Maximální zrychlení pro postupné změny průtoku"
#~ msgctxt "wireframe_strategy option compensate"
#~ msgid "Compensate"
#~ msgstr "Kompenzovat"
msgctxt "layer_0_max_flow_acceleration description"
msgid "Minimum speed for gradual flow changes for the first layer"
msgstr "Minimální rychlost pro postupné změny průtoku pro první vrstvu"
#~ msgctxt "travel_compensate_overlapping_walls_x_enabled label"
#~ msgid "Compensate Inner Wall Overlaps"
#~ msgstr "Kompenzujte překrytí vnitřní stěny"
#~ msgctxt "travel_compensate_overlapping_walls_0_enabled label"
#~ msgid "Compensate Outer Wall Overlaps"
#~ msgstr "Kompenzujte překrytí vnější stěny"
#~ msgctxt "travel_compensate_overlapping_walls_enabled label"
#~ msgid "Compensate Wall Overlaps"
#~ msgstr "Kompenzujte překrytí stěn"
#~ msgctxt "travel_compensate_overlapping_walls_enabled description"
#~ msgid "Compensate the flow for parts of a wall being printed where there is already a wall in place."
#~ msgstr "Vykompenzujte tok částí tisku, které se tisknou tam, kde je již zeď na místě."
#~ msgctxt "travel_compensate_overlapping_walls_x_enabled description"
#~ msgid "Compensate the flow for parts of an inner wall being printed where there is already a wall in place."
#~ msgstr "Kompenzujte tok částí tisknuté vnitřní stěny, kde již je zeď na místě."
#~ msgctxt "travel_compensate_overlapping_walls_0_enabled description"
#~ msgid "Compensate the flow for parts of an outer wall being printed where there is already a wall in place."
#~ msgstr "Vykompenzujte tok částí tisknuté vnější stěny, kde již je zeď na místě."
#~ msgctxt "wireframe_top_jump description"
#~ msgid "Creates a small knot at the top of an upward line, so that the consecutive horizontal layer has a better chance to connect to it. Only applies to Wire Printing."
#~ msgstr "Vytvoří malý uzel v horní části vzestupné linie, takže po sobě jdoucí vodorovná vrstva má lepší šanci se k němu připojit. Platí pouze pro drátový tisk."
#~ msgctxt "wireframe_bottom_delay description"
#~ msgid "Delay time after a downward move. Only applies to Wire Printing."
#~ msgstr "Zpoždění po pohybu dolů. Platí pouze pro drátový tisk."
#~ msgctxt "wireframe_top_delay description"
#~ msgid "Delay time after an upward move, so that the upward line can harden. Only applies to Wire Printing."
#~ msgstr "Zpoždění po pohybu vzhůru, aby mohla stoupající čára ztvrdnout. Platí pouze pro drátový tisk."
#~ msgctxt "wireframe_flat_delay description"
#~ msgid "Delay time between two horizontal segments. Introducing such a delay can cause better adhesion to previous layers at the connection points, while too long delays cause sagging. Only applies to Wire Printing."
#~ msgstr "Doba zpoždění mezi dvěma vodorovnými segmenty. Zavedení takového zpoždění může způsobit lepší přilnavost k předchozím vrstvám ve spojovacích bodech, zatímco příliš dlouhé zpoždění může způsobit ochabnutí. Platí pouze pro drátový tisk."
#~ msgctxt "inset_direction description"
#~ msgid "Determines the order in which walls are printed. Printing outer walls earlier helps with dimensional accuracy, as faults from inner walls cannot propagate to the outside. However printing them later allows them to stack better when overhangs are printed."
#~ msgstr "Určuje pořadí, v jakém budou tištěny zdi. Tištění vnějších zdí jako prvních pomáhá s rozměrovou přesností, jelikož se vady z vnitřních stěn nemohou přenášet na vnějšek. Naproti tomu tištění vnějších zdí nakonec dovoluje jejich lepší vrstvení při tištění převisů."
#~ msgctxt "infill_mesh_order description"
#~ msgid "Determines the priority of this mesh when considering multiple overlapping infill meshes. Areas where multiple infill meshes overlap will take on the settings of the mesh with the lowest rank. An infill mesh with a higher order will modify the infill of infill meshes with lower order and normal meshes."
#~ msgstr "Určuje prioritu této sítě, když se překrývá více sítí výplně. U oblastí, kde se překrývá více sítí výplně, se nastavení přebírá ze sítě s nejnižším pořadím. Síť výplně s vyšším pořadím bude modifikovat výplň sítě výplně s nižším pořadím a běžné sítě."
#~ msgctxt "infill_mesh_order description"
#~ msgid "Determines the priority of this mesh when considering overlapping volumes. Areas where multiple meshes reside will be won by the lower rank mesh. An infill mesh with a higher order will modify the infill of infill meshes with lower order and normal meshes."
#~ msgstr "Určuje prioritu této sítě při zvažování překrývajících se objemů. Oblasti, kde je umístěno více sítí, budou vyhrány sítí s nižším hodnocením. Výplňová síť s vyšším pořádkem upraví výplň síťových výplní s nižším řádem a běžnými oky."
#~ msgctxt "infill_mesh_order description"
#~ msgid "Determines which infill mesh is inside the infill of another infill mesh. An infill mesh with a higher order will modify the infill of infill meshes with lower order and normal meshes."
#~ msgstr "Určuje, která výplň je uvnitř výplně jiné výplně. Výplňová síť s vyšším pořádkem upraví výplň síťových výplní s nižším řádem a normálními oky."
#~ msgctxt "wireframe_nozzle_clearance description"
#~ msgid "Distance between the nozzle and horizontally downward lines. Larger clearance results in diagonally downward lines with a less steep angle, which in turn results in less upward connections with the next layer. Only applies to Wire Printing."
#~ msgstr "Vzdálenost mezi tryskou a vodorovnými liniemi dolů. Větší vůle vede k diagonálně dolů směřujícím liniím s menším strmým úhlem, což zase vede k menšímu spojení nahoru s další vrstvou. Platí pouze pro drátový tisk."
#~ msgctxt "support_bottom_distance description"
#~ msgid "Distance from the print to the bottom of the support."
#~ msgstr "Vzdálenost od tisku ke spodní části podpěry."
#~ msgctxt "support_z_distance description"
#~ msgid "Distance from the top/bottom of the support structure to the print. This gap provides clearance to remove the supports after the model is printed. This value is rounded up to a multiple of the layer height."
#~ msgstr "Vzdálenost od horní / dolní nosné struktury k tisku. Tato mezera poskytuje vůli pro odstranění podpěr po vytištění modelu. Tato hodnota je zaokrouhlena nahoru na násobek výšky vrstvy."
#~ msgctxt "wireframe_up_half_speed description"
#~ msgid ""
#~ "Distance of an upward move which is extruded with half speed.\n"
#~ "This can cause better adhesion to previous layers, while not heating the material in those layers too much. Only applies to Wire Printing."
#~ msgstr ""
#~ "Vzdálenost pohybu nahoru, který je vytlačován poloviční rychlostí.\n"
#~ "To může způsobit lepší přilnavost k předchozím vrstvám, aniž by se materiál v těchto vrstvách příliš zahříval. Platí pouze pro drátový tisk."
#~ msgctxt "support_xy_distance_overhang description"
#~ msgid "Distance of the support structure from the overhang in the X/Y directions. "
#~ msgstr "Vzdálenost podpor od převisu ve směru X / Y. "
#~ msgctxt "wireframe_fall_down description"
#~ msgid "Distance with which the material falls down after an upward extrusion. This distance is compensated for. Only applies to Wire Printing."
#~ msgstr "Vzdálenost, se kterou materiál padá po vytlačení směrem nahoru. Tato vzdálenost je kompenzována. Platí pouze pro drátový tisk."
#~ msgctxt "wireframe_drag_along description"
#~ msgid "Distance with which the material of an upward extrusion is dragged along with the diagonally downward extrusion. This distance is compensated for. Only applies to Wire Printing."
#~ msgstr "Vzdálenost, se kterou je materiál vytlačování směrem vzhůru tažen spolu s diagonálně směrem dolů vytlačováním. Tato vzdálenost je kompenzována. Platí pouze pro drátový tisk."
#~ msgctxt "gradual_flow_discretisation_step_size description"
#~ msgid "Duration of each step in the gradual flow change"
#~ msgstr "Doba trvání každého kroku v postupné změně průtoku"
#~ msgctxt "gradual_flow_enabled description"
#~ msgid "Enable gradual flow changes. When enabled, the flow is gradually increased/decreased to the target flow. This is useful for printers with a bowden tube where the flow is not immediately changed when the extruder motor starts/stops."
#~ msgstr "Povolit postupné změny průtoku. Když je povoleno, průtok se postupně zvyšuje / snižuje na cílový průtok. Toto je užitečné pro tiskárny s Bowdenovou trubicí, kde se průtok okamžitě nezmění, když se spustí / zastaví extrudér."
#~ msgctxt "material_end_of_filament_purge_length label"
#~ msgid "End Of Filament Purge Length"
#~ msgstr "Délka proplachování konce filamentu"
#~ msgctxt "material_end_of_filament_purge_speed label"
#~ msgid "End Of Filament Purge Speed"
#~ msgstr "Rychlost proplachování konce filamentu"
#~ msgctxt "speed_equalize_flow_enabled label"
#~ msgid "Equalize Filament Flow"
#~ msgstr "Vyrovnat tok vlákna"
#~ msgctxt "fill_perimeter_gaps option everywhere"
#~ msgid "Everywhere"
#~ msgstr "Všude"
#~ msgctxt "machine_filament_park_distance label"
#~ msgid "Filament Park Distance"
#~ msgstr "Vzdálenost filamentového parkingu"
#~ msgctxt "fill_perimeter_gaps label"
#~ msgid "Fill Gaps Between Walls"
#~ msgstr "Vyplnit mezery mezi stěnami"
#~ msgctxt "fill_perimeter_gaps description"
#~ msgid "Fills the gaps between walls where no walls fit."
#~ msgstr "Vyplní mezery mezi stěnami, kde se žádné stěny nehodí."
#~ msgctxt "filter_out_tiny_gaps label"
#~ msgid "Filter Out Tiny Gaps"
#~ msgstr "Vyfiltrujte drobné mezery"
#~ msgctxt "filter_out_tiny_gaps description"
#~ msgid "Filter out tiny gaps to reduce blobs on outside of model."
#~ msgstr "Filtrujte drobné mezery, abyste zmenšili kuličky na vnější straně modelu."
#~ msgctxt "wireframe_flow_connection description"
#~ msgid "Flow compensation when going up or down. Only applies to Wire Printing."
#~ msgstr "Kompenzace toku při stoupání nebo klesání. Platí pouze pro drátový tisk."
#~ msgctxt "wireframe_flow_flat description"
#~ msgid "Flow compensation when printing flat lines. Only applies to Wire Printing."
#~ msgstr "Kompenzace toku při tisku rovných čar. Platí pouze pro drátový tisk."
#~ msgctxt "wireframe_flow description"
#~ msgid "Flow compensation: the amount of material extruded is multiplied by this value. Only applies to Wire Printing."
#~ msgstr "Kompenzace toku: množství vytlačovaného materiálu se vynásobí touto hodnotou. Platí pouze pro drátový tisk."
#~ msgctxt "reset_flow_duration description"
#~ msgid "For any travel move longer than this value, the material flow is reset to the paths target flow"
#~ msgstr "Pro jakýkoli pohyb delší než tato hodnota se materiálový průtok resetuje na cílový průtok dráhy"
#~ msgctxt "material_guid description"
#~ msgid "GUID of the material. This is set automatically. "
#~ msgstr "GUID materiálu. Toto je nastaveno automaticky. "
#~ msgctxt "support_tree_enable description"
#~ msgid "Generate a tree-like support with branches that support your print. This may reduce material usage and print time, but greatly increases slicing time."
#~ msgstr "Vygenerujte stromovou podporu s větvemi, které podporují váš tisk. To může snížit spotřebu materiálu a dobu tisku, ale výrazně prodlužuje dobu slicování."
#~ msgctxt "gradual_flow_discretisation_step_size label"
#~ msgid "Gradual flow discretisation step size"
#~ msgstr "Velikost kroku diskretizace postupné změny průtoku"
# ## Settings added by bundled engine backend plugins. Add this manually for now. Should be removed whenever we handle it better.
#~ msgctxt "gradual_flow_enabled label"
#~ msgid "Gradual flow enabled"
#~ msgstr "Postupné změny průtoku povoleny"
#~ msgctxt "max_flow_acceleration label"
#~ msgid "Gradual flow max acceleration"
#~ msgstr "Maximální zrychlení postupných změn průtoku"
#~ msgctxt "support_tree_branch_distance description"
#~ msgid "How far apart the branches need to be when they touch the model. Making this distance small will cause the tree support to touch the model at more points, causing better overhang but making support harder to remove."
#~ msgstr "Jak daleko od sebe musí být větve, když se dotýkají modelu. Zmenšení této vzdálenosti způsobí, že se stromová podpora dotkne modelu ve více bodech, což způsobí lepší přesah, ale těžší odstranění podpory."
#~ msgctxt "machine_steps_per_mm_e description"
#~ msgid "How many steps of the stepper motors will result in one millimeter of extrusion."
#~ msgstr "Kolik kroků krokových motorů vyústí v jeden milimetr vytlačování."
#~ msgctxt "slicing_tolerance description"
#~ msgid "How to slice layers with diagonal surfaces. The areas of a layer can be generated based on where the middle of the layer intersects the surface (Middle). Alternatively each layer can have the areas which fall inside of the volume throughout the height of the layer (Exclusive) or a layer has the areas which fall inside anywhere within the layer (Inclusive). Exclusive retains the most details, Inclusive makes for the best fit and Middle takes the least time to process."
#~ msgstr "Jak krájet vrstvy s diagonálními povrchy. Oblasti vrstvy mohou být generovány na základě toho, kde střed vrstvy protíná povrch (Střední). Alternativně každá vrstva může mít oblasti, které padají uvnitř objemu po celé výšce vrstvy (Exkluzivní), nebo vrstva má oblasti, které padají dovnitř kdekoli v rámci vrstvy (Inkluzivní). Exkluzivní zachovává co nejvíce podrobností, Inkluzivní dělá to nejlepší a Střední trvá zpracování nejméně času."
#~ msgctxt "wall_min_flow_retract description"
#~ msgid "If enabled, retraction is used rather than combing for travel moves that replace walls whose flow is below the minimum flow threshold."
#~ msgstr "Je-li tato funkce povolena, je pro retrakční pohyby, které nahrazují stěny, jejichž průtok je pod prahem minimálního průtoku, používáno spíše zatahování."
#~ msgctxt "infill_mesh_order label"
#~ msgid "Infill Mesh Order"
#~ msgstr "Pořadí sítě výplně"
#~ msgctxt "layer_0_max_flow_acceleration label"
#~ msgid "Initial layer max flow acceleration"
#~ msgstr "Maximální zrychlení průtoku pro první vrstvu"
#~ msgctxt "wireframe_strategy option knot"
#~ msgid "Knot"
#~ msgstr "Uzel"
#~ msgctxt "limit_support_retractions label"
#~ msgid "Limit Support Retractions"
#~ msgstr "Omezení retrakce podpor"
#~ msgctxt "material_end_of_filament_purge_length description"
#~ msgid "Material Station internal value"
#~ msgstr "Interní hodnota stanice materiálu"
#~ msgctxt "material_end_of_filament_purge_speed description"
#~ msgid "Material Station internal value"
#~ msgstr "Interní hodnota stanice materiálu"
#~ msgctxt "material_flush_purge_length description"
#~ msgid "Material Station internal value"
#~ msgstr "Interní hodnota stanice materiálu"
#~ msgctxt "material_flush_purge_speed description"
#~ msgid "Material Station internal value"
#~ msgstr "Interní hodnota stanice materiálu"
#~ msgctxt "material_maximum_park_duration description"
#~ msgid "Material Station internal value"
#~ msgstr "Interní hodnota stanice materiálu"
#~ msgctxt "material_no_load_move_factor description"
#~ msgid "Material Station internal value"
#~ msgstr "Interní hodnota stanice materiálu"
#~ msgctxt "machine_max_feedrate_e label"
#~ msgid "Maximum Feedrate"
#~ msgstr "Maximální feedrate"
#~ msgctxt "speed_equalize_flow_max label"
#~ msgid "Maximum Speed for Flow Equalization"
#~ msgstr "Maximální rychlost pro vyrovnávání průtoku"
#~ msgctxt "max_flow_acceleration description"
#~ msgid "Maximum acceleration for gradual flow changes"
#~ msgstr "Maximální zrychlení pro postupné změny průtoku"
#~ msgctxt "speed_equalize_flow_max description"
#~ msgid "Maximum print speed when adjusting the print speed in order to equalize flow."
#~ msgstr "Maximální rychlost tisku při úpravě rychlosti tisku za účelem vyrovnání toku."
#~ msgctxt "wall_min_flow label"
#~ msgid "Minimum Wall Flow"
#~ msgstr "Minimální průtok zdi"
#~ msgctxt "wall_min_flow description"
#~ msgid "Minimum allowed percentage flow for a wall line. The wall overlap compensation reduces a wall's flow when it lies close to an existing wall. Walls whose flow is less than this value will be replaced with a travel move. When using this setting, you must enable the wall overlap compensation and print the outer wall before inner walls."
#~ msgstr "Minimální povolený procentuální průtok pro linii stěny. Kompenzace překrytí stěny snižuje průtok stěny, když leží blízko ke stávající zdi. Stěny, jejichž průtok je menší než tato hodnota, budou nahrazeny pohybem. Při použití tohoto nastavení musíte povolit kompenzaci překrytí stěny a vnější stěnu vytisknout před vnitřními stěnami."
#~ msgctxt "layer_0_max_flow_acceleration description"
#~ msgid "Minimum speed for gradual flow changes for the first layer"
#~ msgstr "Minimální rychlost pro postupné změny průtoku pro první vrstvu"
#~ msgctxt "fill_perimeter_gaps option nowhere"
#~ msgid "Nowhere"
#~ msgstr "Nikde"
#~ msgctxt "limit_support_retractions description"
#~ msgid "Omit retraction when moving from support to support in a straight line. Enabling this setting saves print time, but can lead to excessive stringing within the support structure."
#~ msgstr "Při přechodu od podpory k podpoře v přímé linii vynechejte stažení. Povolením tohoto nastavení se šetří čas tisku, ale může to vést k nadměrnému strunění uvnitř podpůrné struktury."
#~ msgctxt "outer_inset_first label"
#~ msgid "Outer Before Inner Walls"
#~ msgstr "Vnější stěny před vnitřními"
#~ msgctxt "wireframe_straight_before_down description"
#~ msgid "Percentage of a diagonally downward line which is covered by a horizontal line piece. This can prevent sagging of the top most point of upward lines. Only applies to Wire Printing."
#~ msgstr "Procento diagonálně sestupné linie, která je zakryta vodorovnou čárou. To může zabránit ochabnutí nejvyššího bodu vzhůru. Platí pouze pro drátový tisk."
#~ msgctxt "wall_min_flow_retract label"
#~ msgid "Prefer Retract"
#~ msgstr "Preferovat retrakci"
#~ msgctxt "prime_tower_brim_enable label"
#~ msgid "Prime Tower Brim"
#~ msgstr "Límec hlavní věže"
#~ msgctxt "prime_tower_brim_enable description"
#~ msgid "Prime-towers might need the extra adhesion afforded by a brim even if the model doesn't. Presently can't be used with the 'Raft' adhesion-type."
#~ msgstr "Hlavní věže mohou potřebovat zvláštní přilnavost, kterou poskytuje límec, i když to model neumožňuje. V současnosti nelze použít s adhezním typem „Raft“."
#~ msgctxt "wireframe_enabled description"
#~ msgid "Print only the outside surface with a sparse webbed structure, printing 'in thin air'. This is realized by horizontally printing the contours of the model at given Z intervals which are connected via upward and diagonally downward lines."
#~ msgstr "Tiskněte pouze vnější povrch s řídkou strukturou struktury a tiskněte „na vzduchu“. To je realizováno horizontálním tiskem kontur modelu v daných intervalech Z, které jsou spojeny pomocí linií nahoru a diagonálně dolů."
#~ msgctxt "spaghetti_infill_enabled description"
#~ msgid "Print the infill every so often, so that the filament will curl up chaotically inside the object. This reduces print time, but the behaviour is rather unpredictable."
#~ msgstr "Výplň tiskněte tak často, aby se vlákno chaoticky stočilo uvnitř objektu. To zkracuje dobu tisku, ale chování je spíše nepředvídatelné."
#~ msgctxt "speed_equalize_flow_enabled description"
#~ msgid "Print thinner than normal lines faster so that the amount of material extruded per second remains the same. Thin pieces in your model might require lines printed with smaller line width than provided in the settings. This setting controls the speed changes for such lines."
#~ msgstr "Tiskněte tenčí než normální čáry rychleji, takže množství materiálu vytlačovaného za sekundu zůstává stejné. Tenké kousky ve vašem modelu mohou vyžadovat čáry vytištěné s menší šířkou čáry, než je uvedeno v nastavení. Toto nastavení řídí změny rychlosti těchto linek."
#~ msgctxt "outer_inset_first description"
#~ msgid "Prints walls in order of outside to inside when enabled. This can help improve dimensional accuracy in X and Y when using a high viscosity plastic like ABS; however it can decrease outer surface print quality, especially on overhangs."
#~ msgstr "Když je povoleno, tiskne stěny v pořadí od vnějšku dovnitř. To může pomoci zlepšit rozměrovou přesnost v X a Y při použití plastu s vysokou viskozitou, jako je ABS; může však snížit kvalitu tisku vnějšího povrchu, zejména na převisy."
#~ msgctxt "reset_flow_duration label"
#~ msgid "Reset flow duration"
#~ msgstr "Doba trvání resetování průtoku"
#~ msgctxt "support_tree_collision_resolution description"
#~ msgid "Resolution to compute collisions with to avoid hitting the model. Setting this lower will produce more accurate trees that fail less often, but increases slicing time dramatically."
#~ msgstr "Rozlišení pro výpočet kolizí, aby nedošlo k nárazu do modelu. Nastavením této nižší se vytvoří přesnější stromy, které selhávají méně často, ale dramaticky se zvyšuje doba slicování."
#~ msgctxt "wireframe_strategy option retract"
#~ msgid "Retract"
#~ msgstr "Retrakce"
#~ msgctxt "retraction_enable description"
#~ msgid "Retract the filament when the nozzle is moving over a non-printed area. "
#~ msgstr "Zasuňte vlákno, když se tryska pohybuje po netisknuté oblasti. "
#~ msgctxt "shell label"
#~ msgid "Shell"
#~ msgstr "Shell"
#~ msgctxt "material_shrinkage_percentage label"
#~ msgid "Shrinkage Ratio"
#~ msgstr "Poměr smrštění"
#~ msgctxt "material_shrinkage_percentage description"
#~ msgid "Shrinkage ratio in percentage."
#~ msgstr "Poměr smrštění v procentech."
#~ msgctxt "spaghetti_flow label"
#~ msgid "Spaghetti Flow"
#~ msgstr "Průtok při špagetové výplni"
#~ msgctxt "spaghetti_infill_enabled label"
#~ msgid "Spaghetti Infill"
#~ msgstr "Špagetová výplň"
#~ msgctxt "spaghetti_infill_extra_volume label"
#~ msgid "Spaghetti Infill Extra Volume"
#~ msgstr "Objem navíc při špagetové výplni"
#~ msgctxt "spaghetti_max_height label"
#~ msgid "Spaghetti Infill Maximum Height"
#~ msgstr "Maximální výška špagetové výplně"
#~ msgctxt "spaghetti_infill_stepped label"
#~ msgid "Spaghetti Infill Stepping"
#~ msgstr "Krokování při špagetové výplni"
#~ msgctxt "spaghetti_inset label"
#~ msgid "Spaghetti Inset"
#~ msgstr "Špagetová výplň"
#~ msgctxt "spaghetti_max_infill_angle label"
#~ msgid "Spaghetti Maximum Infill Angle"
#~ msgstr "Maximální úhel špagetové výplně"
#~ msgctxt "wireframe_printspeed description"
#~ msgid "Speed at which the nozzle moves when extruding material. Only applies to Wire Printing."
#~ msgstr "Rychlost, jakou se tryska pohybuje při vytlačování materiálu. Platí pouze pro drátový tisk."
#~ msgctxt "wireframe_printspeed_down description"
#~ msgid "Speed of printing a line diagonally downward. Only applies to Wire Printing."
#~ msgstr "Rychlost tisku linie šikmo dolů. Platí pouze pro drátový tisk."
#~ msgctxt "wireframe_printspeed_up description"
#~ msgid "Speed of printing a line upward 'in thin air'. Only applies to Wire Printing."
#~ msgstr "Rychlost tisku řádku nahoru „na vzduchu“. Platí pouze pro drátový tisk."
#~ msgctxt "wireframe_printspeed_bottom description"
#~ msgid "Speed of printing the first layer, which is the only layer touching the build platform. Only applies to Wire Printing."
#~ msgstr "Rychlost tisku první vrstvy, která je jedinou vrstvou dotýkající se platformy sestavení. Platí pouze pro drátový tisk."
#~ msgctxt "wireframe_printspeed_flat description"
#~ msgid "Speed of printing the horizontal contours of the model. Only applies to Wire Printing."
#~ msgstr "Rychlost tisku vodorovných obrysů modelu. Platí pouze pro drátový tisk."
#~ msgctxt "wall_split_middle_threshold label"
#~ msgid "Split Middle Line Threshold"
#~ msgstr "Mez pro rozdělení prostřední čáry"
#~ msgctxt "wireframe_strategy description"
#~ msgid "Strategy for making sure two consecutive layers connect at each connection point. Retraction lets the upward lines harden in the right position, but may cause filament grinding. A knot can be made at the end of an upward line to heighten the chance of connecting to it and to let the line cool; however, it may require slow printing speeds. Another strategy is to compensate for the sagging of the top of an upward line; however, the lines won't always fall down as predicted."
#~ msgstr "Strategie pro zajištění toho, aby se v každém místě připojení připojily dvě po sobě následující vrstvy. Zpětné zasunutí umožní, aby linie vzhůru ztvrdly ve správné poloze, ale mohou způsobit broušení vlákna. Uzel může být vytvořen na konci vzestupné linie, aby se zvýšila šance na připojení k ní a aby se linka ochladila; to však může vyžadovat nízké rychlosti tisku. Další strategií je kompenzovat prohnutý vrchol horní linie; čáry však nebudou vždy klesat, jak bylo předpovězeno."
#~ msgctxt "support_tree_angle description"
#~ msgid "The angle of the branches. Use a lower angle to make them more vertical and more stable. Use a higher angle to be able to have more reach."
#~ msgstr "Úhel větví. Použijte nižší úhel, aby byly více vertikální a stabilnější. K dosažení většího dosahu použijte vyšší úhel."
#~ msgctxt "lightning_infill_prune_angle description"
#~ msgid "The difference a lightning infill layer can have with the one immediately above w.r.t the pruning of the outer extremities of trees. Measured in the angle given the thickness."
#~ msgstr "Určuje, pod jakým úhlem mezi jednotlivými vrstvami se větve bleskové výplně zkracují."
#~ msgctxt "lightning_infill_straightening_angle description"
#~ msgid "The difference a lightning infill layer can have with the one immediately above w.r.t the smoothing of trees. Measured in the angle given the thickness."
#~ msgstr "Určuje, pod jakým úhlem mezi jednotlivými vrstvami může docházet k vyrovnávání větví bleskové výplně."
#~ msgctxt "wireframe_roof_inset description"
#~ msgid "The distance covered when making a connection from a roof outline inward. Only applies to Wire Printing."
#~ msgstr "Vzdálenost ujetá při vytváření spojení od obrysu střechy dovnitř. Platí pouze pro drátový tisk."
#~ msgctxt "wireframe_roof_drag_along description"
#~ msgid "The distance of the end piece of an inward line which gets dragged along when going back to the outer outline of the roof. This distance is compensated for. Only applies to Wire Printing."
#~ msgstr "Vzdálenost koncového kusu vnitřní linie, která se táhne, když se vrací zpět k vnějšímu obrysu střechy. Tato vzdálenost je kompenzována. Platí pouze pro drátový tisk."
#~ msgctxt "wireframe_roof_fall_down description"
#~ msgid "The distance which horizontal roof lines printed 'in thin air' fall down when being printed. This distance is compensated for. Only applies to Wire Printing."
#~ msgstr "Vzdálenost, kterou vodorovné linie střechy vytištěné „na vzduchu“ klesají při tisku. Tato vzdálenost je kompenzována. Platí pouze pro drátový tisk."
#~ msgctxt "wireframe_height description"
#~ msgid "The height of the upward and diagonally downward lines between two horizontal parts. This determines the overall density of the net structure. Only applies to Wire Printing."
#~ msgstr "Výška nahoru a diagonálně dolů směřujících čar mezi dvěma vodorovnými částmi. To určuje celkovou hustotu struktury sítě. Platí pouze pro drátový tisk."
#~ msgctxt "spaghetti_max_infill_angle description"
#~ msgid "The maximum angle w.r.t. the Z axis of the inside of the print for areas which are to be filled with spaghetti infill afterwards. Lowering this value causes more angled parts in your model to be filled on each layer."
#~ msgstr "Maximální úhel osy Z uvnitř tisku pro oblasti, které mají být poté vyplněny špagetovou výplní. Snížení této hodnoty způsobí, že se na každé vrstvě vyplní více šikmých částí modelu."
#~ msgctxt "spaghetti_max_height description"
#~ msgid "The maximum height of inside space which can be combined and filled from the top."
#~ msgstr "Maximální výška vnitřního prostoru, kterou lze kombinovat a naplnit shora."
#~ msgctxt "mold_width description"
#~ msgid "The minimal distance between the ouside of the mold and the outside of the model."
#~ msgstr "Minimální vzdálenost mezi vnější stranou formy a vnější stranou modelu."
#~ msgctxt "min_odd_wall_line_width description"
#~ msgid "The minimum line width for middle line gap filler polyline walls. This setting determines at which model thickness we switch from printing two wall lines, to printing two outer walls and a single central wall in the middle. A higher Minimum Odd Wall Line Width leads to a higher maximum even wall line width. The maximum odd wall line width is calculated as 2 * Minimum Even Wall Line Width,"
#~ msgstr "Minimální šířka čáry použité jako výplň mezi párovými čárami zdi. Toto nastavení určuje tloušťku modelu, při které se přepíná z tisku dvou čar zdi na tisk dvou vnějších čar zdi a jedné centrální čáry zdi mezi nimi. Vyšší hodnota Minimální šířky nepárové čáry zdi vede k vyšší maximální šířce párové čáry zdi. Maximální šířka nepárové čáry zdi je vypočtena jako 2 * Minimální šířka párové čáry zdi,"
#~ msgctxt "spaghetti_inset description"
#~ msgid "The offset from the walls from where the spaghetti infill will be printed."
#~ msgstr "Odsazení od stěn, odkud bude vytištěna výplň špaget."
#~ msgctxt "infill_pattern description"
#~ msgid "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, tri-hexagon, cubic, octet, quarter cubic, cross and concentric patterns are fully printed every layer. Gyroid, cubic, quarter cubic and octet infill change with every layer to provide a more equal distribution of strength over each direction."
#~ msgstr "Vzor výplňového materiálu tisku. Směr a cik-cak vyplňují směr výměny na alternativních vrstvách, čímž se snižují náklady na materiál. Mřížka, trojúhelník, tri-hexagon, krychlový, oktet, čtvrtý krychlový, křížový a soustředný obrazec jsou plně vytištěny v každé vrstvě. Výplň Gyroid, krychlový, kvartální a oktet se mění s každou vrstvou, aby se zajistilo rovnoměrnější rozložení síly v každém směru."
#~ msgctxt "infill_pattern description"
#~ msgid "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, tri-hexagon, cubic, octet, quarter cubic, cross and concentric patterns are fully printed every layer. Gyroid, cubic, quarter cubic and octet infill change with every layer to provide a more equal distribution of strength over each direction. Lightning infill tries to minimize the infill, by only supporting the (internal) roofs of the object. As such, the infill percentage is only 'valid' one layer below whatever it needs to support of the model."
#~ msgstr "Vzor výplňového materiálu tisku. Čáry a cik-cak s každou vrstvou obracejí směr výplně, čímž se snižují náklady na materiál. Mřížka, trojúhelník, tri-hexagon, krychle, oktet, čtvrtinově krychlový, křížový a soustředný vzor jsou plně vytištěny v každé vrstvě. Vzory gyroid, krychlový, čtvrtinově krychlový a oktet se mění s každou vrstvou, aby se zajistilo rovnoměrnější rozložení síly v každém směru. Bleskový vzor se snaží minimalizovat množství výplně tím, že podporuje pouze horní povrchy objektu. U bleskového vzoru má procento význam pouze v první vrstvě pod každým povrchem."
#~ msgctxt "wall_add_middle_threshold description"
#~ msgid "The smallest line width, as a factor of the normal line width, above which a middle line (if there wasn't one already) will be added. Reduce this setting to use more, thinner lines. Increase to use fewer, wider lines. Note that this applies -as if- the entire shape should be filled with wall, so the middle here refers to the middle of the object between two outer edges of the shape, even if there actually is fill or (other) skin in the print instead of wall."
#~ msgstr "Nejnižší šířka čáry, zadaná jako procento běžné šířky čáry, nad kterou bude přidána prostřední nepárová čára mezi dvě párové čáry (pokud mezi nimi ještě nebyla). Snižte toto nastavení, aby se používalo více tenkých čar. Zvyšte toto nastavení pro použití méně a širších čar. Je třeba si uvědomit, že toto nastavení se použije, jako kdyby byl celý tvar vyplněn zdmi. Takže termín prostřední zde znamená prostředek objektu mezi dvěma vnějšími hranami tvaru, a to i v případě, že se namísto zdi tiskne výplň nebo jiný povrch."
#~ msgctxt "wall_split_middle_threshold description"
#~ msgid "The smallest line width, as a factor of the normal line width, above which the middle line (if there is one) will be split into two. Reduce this setting to use more, thinner lines. Increase to use fewer, wider lines. Note that this applies -as if- the entire shape should be filled with wall, so the middle here refers to the middle of the object between two outer edges of the shape, even if there actually is fill or (other) skin in the print instead of wall."
#~ msgstr "Nejnižší šířka čáry, zadaná jako procento běžné šířky čáry, nad kterou bude prostřední nepárová čára (pokud nějaká je) rozdělena na dvě párové čáry. Snižte toto nastavení, aby se používalo více tenkých čar. Zvyšte toto nastavení pro použití méně a širších čar. Je třeba si uvědomit, že toto nastavení se použije, jako kdyby byl celý tvar vyplněn zdmi. Takže termín prostřední zde znamená prostředek objektu mezi dvěma vnějšími hranami tvaru, a to i v případě, že se namísto zdi tiskne výplň nebo jiný povrch."
#~ msgctxt "speed_layer_0 description"
#~ msgid "The speed for the initial layer. A lower value is advised to improve adhesion to the build plate."
#~ msgstr "Rychlost počáteční vrstvy. Doporučuje se nižší hodnota pro zlepšení přilnavosti k montážní desce."
#~ msgctxt "material_print_temperature_layer_0 description"
#~ msgid "The temperature used for printing the first layer. Set at 0 to disable special handling of the initial layer."
#~ msgstr "Teplota, která se používá pro tisk první vrstvy."
#~ msgctxt "material_bed_temperature_layer_0 description"
#~ msgid "The temperature used for the heated build plate at the first layer."
#~ msgstr "Teplota použitá pro vyhřívanou podložku v první vrstvě."
#~ msgctxt "material_bed_temperature description"
#~ msgid "The temperature used for the heated build plate. If this is 0, the bed temperature will not be adjusted."
#~ msgstr "Teplota použitá pro vyhřívanou podložku. Pokud je to 0, teplota podložky nebude upravena."
#~ msgctxt "wireframe_roof_outer_delay description"
#~ msgid "Time spent at the outer perimeters of hole which is to become a roof. Longer times can ensure a better connection. Only applies to Wire Printing."
#~ msgstr "Čas strávený na vnějším obvodu díry, která se má stát střechou. Delší časy mohou zajistit lepší spojení. Platí pouze pro drátový tisk."
#~ msgctxt "max_skin_angle_for_expansion description"
#~ msgid "Top and/or bottom surfaces of your object with an angle larger than this setting, won't have their top/bottom skin expanded. This avoids expanding the narrow skin areas that are created when the model surface has a near vertical slope. An angle of 0° is horizontal, while an angle of 90° is vertical."
#~ msgstr "Horní a/nebo dolní povrch objektu s větším úhlem, než je toto nastavení, nebudou mít rozbalenou horní/dolní plochu. Tím se zabrání rozšíření úzkých oblastí vzhledu, které jsou vytvořeny, když má povrch modelu téměř svislý sklon. Úhel 0° je vodorovný, zatímco úhel 90° je svislý."
#~ msgctxt "support_tree_enable label"
#~ msgid "Tree Support"
#~ msgstr "Stromová podpora"
#~ msgctxt "support_tree_angle label"
#~ msgid "Tree Support Branch Angle"
#~ msgstr "Úhel větve stromové podpory"
#~ msgctxt "support_tree_branch_diameter label"
#~ msgid "Tree Support Branch Diameter"
#~ msgstr "Průměr větve podpěry stromu"
#~ msgctxt "support_tree_branch_diameter_angle label"
#~ msgid "Tree Support Branch Diameter Angle"
#~ msgstr "Průměr úhlu větve podpěry stromu"
#~ msgctxt "support_tree_branch_distance label"
#~ msgid "Tree Support Branch Distance"
#~ msgstr "Vzdálenost větví stromu"
#~ msgctxt "support_tree_collision_resolution label"
#~ msgid "Tree Support Collision Resolution"
#~ msgstr "Stromová podpora - rozlišení kolize"
#~ msgctxt "support_tree_max_diameter label"
#~ msgid "Tree Support Trunk Diameter"
#~ msgstr "Průměr kmene stromové podpory"
#~ msgctxt "wireframe_bottom_delay label"
#~ msgid "WP Bottom Delay"
#~ msgstr "Zpoždení pohybu dole při tisku DT"
#~ msgctxt "wireframe_printspeed_bottom label"
#~ msgid "WP Bottom Printing Speed"
#~ msgstr "Rychlost tisku spodního DT"
#~ msgctxt "wireframe_flow_connection label"
#~ msgid "WP Connection Flow"
#~ msgstr "Průtok při spojování DT"
#~ msgctxt "wireframe_height label"
#~ msgid "WP Connection Height"
#~ msgstr "Výška připojení DT"
#~ msgctxt "wireframe_printspeed_down label"
#~ msgid "WP Downward Printing Speed"
#~ msgstr "Rychlost tisku směrem dolů u DT"
#~ msgctxt "wireframe_drag_along label"
#~ msgid "WP Drag Along"
#~ msgstr "Tah DT"
#~ msgctxt "wireframe_up_half_speed label"
#~ msgid "WP Ease Upward"
#~ msgstr "Poloviční rychlost DT"
#~ msgctxt "wireframe_fall_down label"
#~ msgid "WP Fall Down"
#~ msgstr "Pád materiálu DT"
#~ msgctxt "wireframe_flat_delay label"
#~ msgid "WP Flat Delay"
#~ msgstr "Zpoždění při tisku plochých segmentů DT"
#~ msgctxt "wireframe_flow_flat label"
#~ msgid "WP Flat Flow"
#~ msgstr "Průtok při plochém DT"
#~ msgctxt "wireframe_flow label"
#~ msgid "WP Flow"
#~ msgstr "Průtok při DT"
#~ msgctxt "wireframe_printspeed_flat label"
#~ msgid "WP Horizontal Printing Speed"
#~ msgstr "Rychlost horizontálního tisku DT"
#~ msgctxt "wireframe_top_jump label"
#~ msgid "WP Knot Size"
#~ msgstr "Velikost uzlu DT"
#~ msgctxt "wireframe_nozzle_clearance label"
#~ msgid "WP Nozzle Clearance"
#~ msgstr "Vyčištění trysky DT"
#~ msgctxt "wireframe_roof_drag_along label"
#~ msgid "WP Roof Drag Along"
#~ msgstr "Tah střechy DT"
#~ msgctxt "wireframe_roof_fall_down label"
#~ msgid "WP Roof Fall Down"
#~ msgstr "Pád materiálu střechy DT"
#~ msgctxt "wireframe_roof_inset label"
#~ msgid "WP Roof Inset Distance"
#~ msgstr "Vzdálenost střechy DT"
#~ msgctxt "wireframe_roof_outer_delay label"
#~ msgid "WP Roof Outer Delay"
#~ msgstr "Vnější zpoždění střechy DT"
#~ msgctxt "wireframe_printspeed label"
#~ msgid "WP Speed"
#~ msgstr "Rychlost DT"
#~ msgctxt "wireframe_straight_before_down label"
#~ msgid "WP Straighten Downward Lines"
#~ msgstr "Vyrovnat spodní linky DT"
#~ msgctxt "wireframe_strategy label"
#~ msgid "WP Strategy"
#~ msgstr "Strategie DT"
#~ msgctxt "wireframe_top_delay label"
#~ msgid "WP Top Delay"
#~ msgstr "Zpoždení pohybu nahoře při tisku DT"
#~ msgctxt "wireframe_printspeed_up label"
#~ msgid "WP Upward Printing Speed"
#~ msgstr "Rychlost tisku nahoru u DT"
#~ msgctxt "retraction_combing_max_distance description"
#~ msgid "When non-zero, combing travel moves that are longer than this distance will use retraction."
#~ msgstr "Pokud nenulové, pohyby combingového pohybu, které jsou delší než tato vzdálenost, použijí zatažení."
#~ msgctxt "print_sequence description"
#~ msgid "Whether to print all models one layer at a time or to wait for one model to finish, before moving on to the next. One at a time mode is possible if a) only one extruder is enabled and b) all models are separated in such a way that the whole print head can move in between and all models are lower than the distance between the nozzle and the X/Y axes. "
#~ msgstr "Zda se mají tisknout všechny modely po jedné vrstvě najednou, nebo počkat na dokončení jednoho modelu, než se přesunete na další. Jeden za časovým režimem je možný, pokud a) je povolen pouze jeden extruder ab) všechny modely jsou odděleny tak, že celá tisková hlava se může pohybovat mezi a všechny modely jsou menší než vzdálenost mezi tryskou a X / Osy Y. "
#~ msgctxt "spaghetti_infill_stepped description"
#~ msgid "Whether to print spaghetti infill in steps or extrude all the infill filament at the end of the print."
#~ msgstr "Zda se má tisknout špagetová výplň po krocích, nebo se vytlačí veškeré výplňové vlákno na konci tisku."
#~ msgctxt "wireframe_enabled label"
#~ msgid "Wire Printing"
#~ msgstr "Drátový tisk"
#~ msgctxt "blackmagic description"
#~ msgid "category_blackmagic"
#~ msgstr "category_blackmagic"
#~ msgctxt "meshfix description"
#~ msgid "category_fixes"
#~ msgstr "category_fixes"
#~ msgctxt "experimental description"
#~ msgid "experimental!"
#~ msgstr "experimentální!"
msgctxt "reset_flow_duration label"
msgid "Reset flow duration"
msgstr "Doba trvání resetování průtoku"

View file

@ -559,7 +559,7 @@ msgstr "Alle Modelle in einem Raster anordnen"
msgctxt "@action:inmenu menubar:edit"
msgid "Arrange Selection"
msgstr ""
msgstr "Auswahl anordnen"
msgctxt "@label:button"
msgid "Ask a question"
@ -1015,7 +1015,7 @@ msgstr "Die Antwort vom Server konnte nicht interpretiert werden."
msgctxt "@error:load"
msgid "Could not load GCodeWriter plugin. Try to re-enable the plugin."
msgstr ""
msgstr "Konnte GCodeWriter-Plugin nicht laden. Versuchen Sie, das Plugin wieder zu aktivieren."
msgctxt "@info:error"
msgid "Could not reach Marketplace."
@ -2356,19 +2356,19 @@ msgstr "Stellen Sie sicher, dass der G-Code für Ihren Drucker und Ihre Druckerk
msgctxt "@item:inlistbox"
msgid "Makerbot Printfile"
msgstr ""
msgstr "Makerbot-Druckdatei"
msgctxt "name"
msgid "Makerbot Printfile Writer"
msgstr ""
msgstr "Makerbot-Druckdatei-Writer"
msgctxt "@error"
msgid "MakerbotWriter could not save to the designated path."
msgstr ""
msgstr "MakerbotWriter konnte nicht im angegebenen Pfad speichern."
msgctxt "@error:not supported"
msgid "MakerbotWriter does not support text mode."
msgstr ""
msgstr "MakerbotWriter unterstützt keinen Textmodus."
msgctxt "@action:inmenu"
msgid "Manage Materials..."
@ -3019,7 +3019,7 @@ msgstr "Geben Sie bitte einen Namen für dieses Profil an."
msgctxt "@info"
msgid "Please provide a new name."
msgstr ""
msgstr "Bitte geben Sie einen neuen Namen an."
msgctxt "@text"
msgid "Please read and agree with the plugin licence."
@ -3456,7 +3456,7 @@ msgstr "Bietet Unterstützung für das Schreiben von 3MF-Dateien."
msgctxt "description"
msgid "Provides support for writing MakerBot Format Packages."
msgstr ""
msgstr "Bietet Unterstützung für das Schreiben von MakerBot-Formatpaketen."
msgctxt "description"
msgid "Provides support for writing Ultimaker Format Packages."
@ -3593,7 +3593,7 @@ msgstr "Umbenennen"
msgctxt "@title:window"
msgid "Rename"
msgstr ""
msgstr "Umbenennen"
msgctxt "@title:window"
msgid "Rename Profile"

View file

@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: plugins@ultimaker.com\n"
"POT-Creation-Date: 2023-10-31 19:13+0000\n"
"POT-Creation-Date: 2023-11-24 12:51+0000\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"
@ -456,6 +456,10 @@ msgctxt "build_volume_temperature label"
msgid "Build Volume Temperature"
msgstr "Temperatur Druckabmessung"
msgctxt "prime_tower_brim_enable description"
msgid "By enabling this setting, your prime-tower will get a brim, even if the model doesn't. If you want a sturdier base for a high tower, you can increase the base height."
msgstr "Durch Aktivieren dieser Einstellung erhält Ihr Prime-Turm einen Rand, auch wenn das Modell keinen hat. Wenn Sie eine stabilere Basis für einen hohen Turm möchten, können Sie die Basis-Höhe erhöhen."
msgctxt "center_object label"
msgid "Center Object"
msgstr "Objekt zentrieren"
@ -742,7 +746,7 @@ msgstr "Der Abstand zwischen den gedruckten Stützstrukturlinien. Diese Einstell
msgctxt "support_bottom_distance description"
msgid "Distance from the print to the bottom of the support. Note that this is rounded up to the next layer height."
msgstr ""
msgstr "Abstand vom Druck zum Boden der Stütze. Beachten Sie, dass dies auf die nächste Schichthöhe aufgerundet wird."
msgctxt "support_top_distance description"
msgid "Distance from the top of the support to the print."
@ -750,7 +754,7 @@ msgstr "Der Abstand von der Oberseite der Stützstruktur zum gedruckten Objekt."
msgctxt "support_z_distance description"
msgid "Distance from the top/bottom of the support structure to the print. This gap provides clearance to remove the supports after the model is printed. The topmost support layer below the model might be a fraction of regular layers."
msgstr ""
msgstr "Abstand von der Ober-/Unterseite der Stützstruktur zum Druck. Diese Lücke ermöglicht es, die Stützen nach dem Drucken des Modells zu entfernen. Die oberste Stützschicht unter dem Modell könnte ein Bruchteil der normalen Schichten sein."
msgctxt "infill_wipe_dist description"
msgid "Distance of a travel move inserted after every infill line, to make the infill stick to the walls better. This option is similar to infill overlap, but without extrusion and only on one end of the infill line."
@ -1938,7 +1942,7 @@ msgstr "Marlin (Volumetrisch)"
msgctxt "material description"
msgid "Material"
msgstr ""
msgstr "Material"
msgctxt "material label"
msgid "Material"
@ -2514,19 +2518,19 @@ msgstr "Beschleunigung Einzugsturm"
msgctxt "prime_tower_brim_enable label"
msgid "Prime Tower Base"
msgstr ""
msgctxt "prime_tower_base_curve_magnitude label"
msgid "Prime Tower Base Curve Magnitude"
msgstr ""
msgstr "Grundfläche des Prime-Turms"
msgctxt "prime_tower_base_height label"
msgid "Prime Tower Base Height"
msgstr ""
msgstr "Höhe der Prime-Turm-Basis"
msgctxt "prime_tower_base_size label"
msgid "Prime Tower Base Size"
msgstr ""
msgstr "Größe der Prime-Turm-Basis"
msgctxt "prime_tower_base_curve_magnitude label"
msgid "Prime Tower Base Slope"
msgstr "Neigung der Prime-Turm-Basis"
msgctxt "prime_tower_flow label"
msgid "Prime Tower Flow"
@ -2546,7 +2550,7 @@ msgstr "Mindestvolumen Einzugsturm"
msgctxt "prime_tower_raft_base_line_spacing label"
msgid "Prime Tower Raft Line Spacing"
msgstr ""
msgstr "Linienabstand des Prime-Turm-Floßes"
msgctxt "prime_tower_size label"
msgid "Prime Tower Size"
@ -2564,10 +2568,6 @@ msgctxt "prime_tower_position_y label"
msgid "Prime Tower Y Position"
msgstr "Y-Position des Einzugsturms"
msgctxt "prime_tower_brim_enable description"
msgid "Prime-towers might need the extra adhesion afforded by a brim or raft, even if the model doesn't."
msgstr ""
msgctxt "acceleration_print label"
msgid "Print Acceleration"
msgstr "Beschleunigung Druck"
@ -3786,7 +3786,7 @@ msgstr "Der Abstand zwischen den Raft-Linien der Raft-Oberflächenschichten. Der
msgctxt "prime_tower_raft_base_line_spacing description"
msgid "The distance between the raft lines for the unique prime tower raft layer. Wide spacing makes for easy removal of the raft from the build plate."
msgstr ""
msgstr "Der Abstand zwischen den Floßlinien für die einzigartige Prime-Turm-Floßschicht. Ein großer Abstand erleichtert das Entfernen des Floßes von der Bauplatte."
msgctxt "interlocking_depth description"
msgid "The distance from the boundary between models to generate interlocking structure, measured in cells. Too few cells will result in poor adhesion."
@ -3985,8 +3985,8 @@ msgid "The height of the initial layer in mm. A thicker initial layer makes adhe
msgstr "Die Dicke der ersten Schicht in mm. Eine dicke erste Schicht erleichtert die Haftung am Druckbett."
msgctxt "prime_tower_base_height description"
msgid "The height of the prime tower base."
msgstr ""
msgid "The height of the prime tower base. Increasing this value will result in a more sturdy prime tower because the base will be wider. If this setting is too low, the prime tower will not have a sturdy base."
msgstr "Die Höhe der Prime-Turm-Basis. Eine Erhöhung dieses Wertes führt zu einem stabileren Prime-Turm, da die Basis breiter wird. Ist dieser Wert zu niedrig, hat der Prime-Turm keine stabile Basis."
msgctxt "support_bottom_stair_step_height description"
msgid "The height of the steps of the stair-like bottom of support resting on the model. A low value makes the support harder to remove, but too high values can lead to unstable support structures. Set to zero to turn off the stair-like behaviour."
@ -4061,8 +4061,8 @@ msgid "The length of material retracted during a retraction move."
msgstr "Die Länge des Materials, das während der Einzugsbewegung eingezogen wird."
msgctxt "prime_tower_base_curve_magnitude description"
msgid "The magnitude factor used for the curve of the prime tower foot."
msgstr ""
msgid "The magnitude factor used for the slope of the prime tower base. If you increase this value, the base will become slimmer. If you decrease it, the base will become thicker."
msgstr "Der Größenfaktor, der für die Neigung der Prime-Turm-Basis verwendet wird. Wenn Sie diesen Wert erhöhen, wird die Basis schlanker. Wenn Sie ihn verringern, wird die Basis dicker."
msgctxt "machine_buildplate_type description"
msgid "The material of the build plate installed on the printer."
@ -4618,7 +4618,7 @@ msgstr "Die Temperatur, bei der das Abkühlen bereits beginnen kann, bevor der D
msgctxt "material_print_temperature_layer_0 description"
msgid "The temperature used for printing the first layer."
msgstr ""
msgstr "Die Temperatur, die für den Druck der ersten Schicht verwendet wird."
msgctxt "material_print_temperature description"
msgid "The temperature used for printing."
@ -4697,8 +4697,8 @@ msgid "The width of the interlocking structure beams."
msgstr "Die Breite der Balken in der ineinandergreifenden Struktur."
msgctxt "prime_tower_base_size description"
msgid "The width of the prime tower base."
msgstr ""
msgid "The width of the prime tower brim/base. A larger base enhances adhesion to the build plate, but also reduces the effective print area."
msgstr "Die Breite des Prime-Turm-Randes/Basis. Eine größere Basis verbessert die Haftung auf der Bauplatte, verringert jedoch auch den effektiven Druckbereich."
msgctxt "prime_tower_size description"
msgid "The width of the prime tower."
@ -5488,62 +5488,42 @@ msgctxt "travel description"
msgid "travel"
msgstr "Bewegungen"
#~ msgctxt "support_bottom_distance description"
#~ msgid "Distance from the print to the bottom of the support."
#~ msgstr "Der Abstand vom gedruckten Objekt bis zur Unterseite der Stützstruktur."
msgctxt "gradual_flow_discretisation_step_size description"
msgid "Duration of each step in the gradual flow change"
msgstr "Dauer der einzelnen Schritte bei der stufenweisen Änderung des Flusses"
#~ msgctxt "support_z_distance description"
#~ msgid "Distance from the top/bottom of the support structure to the print. This gap provides clearance to remove the supports after the model is printed. This value is rounded up to a multiple of the layer height."
#~ msgstr "Der Abstand der Ober-/Unterseite der Stützstruktur vom Druck. So wird ein Zwischenraum geschaffen, der die Entfernung der Stützstrukturen nach dem Drucken des Modells ermöglicht. Dieser Wert wird auf ein Vielfaches der Schichtdicke aufgerundet."
msgctxt "gradual_flow_enabled description"
msgid "Enable gradual flow changes. When enabled, the flow is gradually increased/decreased to the target flow. This is useful for printers with a bowden tube where the flow is not immediately changed when the extruder motor starts/stops."
msgstr "Aktivieren Sie stufenweise Flussänderungen. Wenn diese Option aktiviert ist, wird der Fluss stufenweise auf den Sollwert des Flusses erhöht bzw. verringert. Dies ist bei Druckern mit Bowden-Röhren sinnvoll, bei denen der Fluss nicht sofort geändert wird, sobald der Extrudermotor startet/stoppt."
#~ msgctxt "gradual_flow_discretisation_step_size description"
#~ msgid "Duration of each step in the gradual flow change"
#~ msgstr "Dauer der einzelnen Schritte bei der stufenweisen Änderung des Flusses"
msgctxt "reset_flow_duration description"
msgid "For any travel move longer than this value, the material flow is reset to the paths target flow"
msgstr "Bei jeder Fahrtbewegung, die diesen Wert überschreitet, wird der Materialfluss auf den Sollwert des Flusses für den Weg zurückgesetzt"
#~ msgctxt "gradual_flow_enabled description"
#~ msgid "Enable gradual flow changes. When enabled, the flow is gradually increased/decreased to the target flow. This is useful for printers with a bowden tube where the flow is not immediately changed when the extruder motor starts/stops."
#~ msgstr "Aktivieren Sie stufenweise Flussänderungen. Wenn diese Option aktiviert ist, wird der Fluss stufenweise auf den Sollwert des Flusses erhöht bzw. verringert. Dies ist bei Druckern mit Bowden-Röhren sinnvoll, bei denen der Fluss nicht sofort geändert wird, sobald der Extrudermotor startet/stoppt."
msgctxt "gradual_flow_discretisation_step_size label"
msgid "Gradual flow discretisation step size"
msgstr "Schrittgröße der stufenweisen Fluss-Diskretisierung"
#~ msgctxt "reset_flow_duration description"
#~ msgid "For any travel move longer than this value, the material flow is reset to the paths target flow"
#~ msgstr "Bei jeder Fahrtbewegung, die diesen Wert überschreitet, wird der Materialfluss auf den Sollwert des Flusses für den Weg zurückgesetzt"
msgctxt "gradual_flow_enabled label"
msgid "Gradual flow enabled"
msgstr "Stufenweiser Fluss aktiviert"
#~ msgctxt "gradual_flow_discretisation_step_size label"
#~ msgid "Gradual flow discretisation step size"
#~ msgstr "Schrittgröße der stufenweisen Fluss-Diskretisierung"
msgctxt "max_flow_acceleration label"
msgid "Gradual flow max acceleration"
msgstr "Maximale Beschleunigung bei stufenweisem Fluss"
#~ msgctxt "gradual_flow_enabled label"
#~ msgid "Gradual flow enabled"
#~ msgstr "Stufenweiser Fluss aktiviert"
msgctxt "layer_0_max_flow_acceleration label"
msgid "Initial layer max flow acceleration"
msgstr "Maximale Flussbeschleunigung bei erster Schicht"
#~ msgctxt "max_flow_acceleration label"
#~ msgid "Gradual flow max acceleration"
#~ msgstr "Maximale Beschleunigung bei stufenweisem Fluss"
msgctxt "max_flow_acceleration description"
msgid "Maximum acceleration for gradual flow changes"
msgstr "Maximale Beschleunigung für stufenweise Änderung des Flusses"
#~ msgctxt "layer_0_max_flow_acceleration label"
#~ msgid "Initial layer max flow acceleration"
#~ msgstr "Maximale Flussbeschleunigung bei erster Schicht"
msgctxt "layer_0_max_flow_acceleration description"
msgid "Minimum speed for gradual flow changes for the first layer"
msgstr "Mindestgeschwindigkeit für stufenweise Änderung des Flusses in der ersten Schicht"
#~ msgctxt "max_flow_acceleration description"
#~ msgid "Maximum acceleration for gradual flow changes"
#~ msgstr "Maximale Beschleunigung für stufenweise Änderung des Flusses"
#~ msgctxt "layer_0_max_flow_acceleration description"
#~ msgid "Minimum speed for gradual flow changes for the first layer"
#~ msgstr "Mindestgeschwindigkeit für stufenweise Änderung des Flusses in der ersten Schicht"
#~ msgctxt "prime_tower_brim_enable label"
#~ msgid "Prime Tower Brim"
#~ msgstr "Brim Einzugsturm"
#~ msgctxt "prime_tower_brim_enable description"
#~ msgid "Prime-towers might need the extra adhesion afforded by a brim even if the model doesn't. Presently can't be used with the 'Raft' adhesion-type."
#~ msgstr "Einzugstürme benötigen möglicherweise zusätzliche Haftung in Form eines Brims, auch wenn das Modell selbst dies nicht benötigt. Kann derzeit nicht mit dem „Raft“-Haftungstyp verwendet werden."
#~ msgctxt "reset_flow_duration label"
#~ msgid "Reset flow duration"
#~ msgstr "Flussdauer zurücksetzen"
#~ msgctxt "material_print_temperature_layer_0 description"
#~ msgid "The temperature used for printing the first layer. Set at 0 to disable special handling of the initial layer."
#~ msgstr "Die Temperatur, die für das Drucken der ersten Schicht verwendet wird. Wählen Sie hier 0, um eine spezielle Behandlung der ersten Schicht zu deaktivieren."
msgctxt "reset_flow_duration label"
msgid "Reset flow duration"
msgstr "Flussdauer zurücksetzen"

View file

@ -559,7 +559,7 @@ msgstr "Organizar todos los modelos en una cuadrícula"
msgctxt "@action:inmenu menubar:edit"
msgid "Arrange Selection"
msgstr ""
msgstr "Organizar selección"
msgctxt "@label:button"
msgid "Ask a question"
@ -1015,7 +1015,7 @@ msgstr "Imposible interpretar la respuesta del servidor."
msgctxt "@error:load"
msgid "Could not load GCodeWriter plugin. Try to re-enable the plugin."
msgstr ""
msgstr "No se pudo cargar el plugin GCodeWriter. Intenta volver a habilitar el plugin."
msgctxt "@info:error"
msgid "Could not reach Marketplace."
@ -2356,19 +2356,19 @@ msgstr "Asegúrese de que el GCode es adecuado para la impresora y para su confi
msgctxt "@item:inlistbox"
msgid "Makerbot Printfile"
msgstr ""
msgstr "Archivo de impresión Makerbot"
msgctxt "name"
msgid "Makerbot Printfile Writer"
msgstr ""
msgstr "Escritor de archivos de impresión Makerbot"
msgctxt "@error"
msgid "MakerbotWriter could not save to the designated path."
msgstr ""
msgstr "MakerbotWriter no pudo guardar en la ruta designada."
msgctxt "@error:not supported"
msgid "MakerbotWriter does not support text mode."
msgstr ""
msgstr "MakerbotWriter no soporta el modo texto."
msgctxt "@action:inmenu"
msgid "Manage Materials..."
@ -3020,7 +3020,7 @@ msgstr "Introduzca un nombre para este perfil."
msgctxt "@info"
msgid "Please provide a new name."
msgstr ""
msgstr "Por favor, proporciona un nuevo nombre."
msgctxt "@text"
msgid "Please read and agree with the plugin licence."
@ -3457,7 +3457,7 @@ msgstr "Proporciona asistencia para escribir archivos 3MF."
msgctxt "description"
msgid "Provides support for writing MakerBot Format Packages."
msgstr ""
msgstr "Proporciona soporte para escribir paquetes de formato MakerBot."
msgctxt "description"
msgid "Provides support for writing Ultimaker Format Packages."
@ -3594,7 +3594,7 @@ msgstr "Cambiar nombre"
msgctxt "@title:window"
msgid "Rename"
msgstr ""
msgstr "Renombrar"
msgctxt "@title:window"
msgid "Rename Profile"

View file

@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: plugins@ultimaker.com\n"
"POT-Creation-Date: 2023-10-31 19:13+0000\n"
"POT-Creation-Date: 2023-11-24 12:51+0000\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"
@ -456,6 +456,10 @@ msgctxt "build_volume_temperature label"
msgid "Build Volume Temperature"
msgstr "Temperatura de volumen de impresión"
msgctxt "prime_tower_brim_enable description"
msgid "By enabling this setting, your prime-tower will get a brim, even if the model doesn't. If you want a sturdier base for a high tower, you can increase the base height."
msgstr "Al habilitar esta configuración, tu torre de cebado tendrá un borde, incluso si el modelo no lo tiene. Si quieres una base más robusta para una torre alta, puedes aumentar la altura de la base."
msgctxt "center_object label"
msgid "Center Object"
msgstr "Centrar objeto"
@ -742,7 +746,7 @@ msgstr "Distancia entre las líneas de estructuras del soporte impresas. Este aj
msgctxt "support_bottom_distance description"
msgid "Distance from the print to the bottom of the support. Note that this is rounded up to the next layer height."
msgstr ""
msgstr "Distancia de la impresión hasta la parte inferior del soporte. Ten en cuenta que esto se redondea al siguiente altura de capa."
msgctxt "support_top_distance description"
msgid "Distance from the top of the support to the print."
@ -750,7 +754,7 @@ msgstr "Distancia desde la parte superior del soporte a la impresión."
msgctxt "support_z_distance description"
msgid "Distance from the top/bottom of the support structure to the print. This gap provides clearance to remove the supports after the model is printed. The topmost support layer below the model might be a fraction of regular layers."
msgstr ""
msgstr "Distancia desde la parte superior/inferior de la estructura de soporte hasta la impresión. Este espacio proporciona la holgura necesaria para remover los soportes después de imprimir el modelo. La capa de soporte más cercana al modelo podría ser una fracción de las capas regulares."
msgctxt "infill_wipe_dist description"
msgid "Distance of a travel move inserted after every infill line, to make the infill stick to the walls better. This option is similar to infill overlap, but without extrusion and only on one end of the infill line."
@ -2514,19 +2518,19 @@ msgstr "Aceleración de la torre auxiliar"
msgctxt "prime_tower_brim_enable label"
msgid "Prime Tower Base"
msgstr ""
msgctxt "prime_tower_base_curve_magnitude label"
msgid "Prime Tower Base Curve Magnitude"
msgstr ""
msgstr "Base de la torre de cebado"
msgctxt "prime_tower_base_height label"
msgid "Prime Tower Base Height"
msgstr ""
msgstr "Altura de la base de la torre de cebado"
msgctxt "prime_tower_base_size label"
msgid "Prime Tower Base Size"
msgstr ""
msgstr "Tamaño de la base de la torre de cebado"
msgctxt "prime_tower_base_curve_magnitude label"
msgid "Prime Tower Base Slope"
msgstr "Pendiente de la Base de la Torre de Cebado"
msgctxt "prime_tower_flow label"
msgid "Prime Tower Flow"
@ -2546,7 +2550,7 @@ msgstr "Volumen mínimo de la torre auxiliar"
msgctxt "prime_tower_raft_base_line_spacing label"
msgid "Prime Tower Raft Line Spacing"
msgstr ""
msgstr "Espaciado de las líneas del raft de la torre de cebado"
msgctxt "prime_tower_size label"
msgid "Prime Tower Size"
@ -2564,10 +2568,6 @@ msgctxt "prime_tower_position_y label"
msgid "Prime Tower Y Position"
msgstr "Posición de la torre auxiliar sobre el eje Y"
msgctxt "prime_tower_brim_enable description"
msgid "Prime-towers might need the extra adhesion afforded by a brim or raft, even if the model doesn't."
msgstr ""
msgctxt "acceleration_print label"
msgid "Print Acceleration"
msgstr "Aceleración de la impresión"
@ -3786,7 +3786,7 @@ msgstr "Distancia entre las líneas de la balsa para las capas superiores de la
msgctxt "prime_tower_raft_base_line_spacing description"
msgid "The distance between the raft lines for the unique prime tower raft layer. Wide spacing makes for easy removal of the raft from the build plate."
msgstr ""
msgstr "La distancia entre las líneas del raft para la capa única del raft de la torre de cebado. Un espaciado amplio facilita la eliminación del raft de la placa de construcción."
msgctxt "interlocking_depth description"
msgid "The distance from the boundary between models to generate interlocking structure, measured in cells. Too few cells will result in poor adhesion."
@ -3985,8 +3985,8 @@ msgid "The height of the initial layer in mm. A thicker initial layer makes adhe
msgstr "Altura de capa inicial en mm. Una capa inicial más gruesa se adhiere a la placa de impresión con mayor facilidad."
msgctxt "prime_tower_base_height description"
msgid "The height of the prime tower base."
msgstr ""
msgid "The height of the prime tower base. Increasing this value will result in a more sturdy prime tower because the base will be wider. If this setting is too low, the prime tower will not have a sturdy base."
msgstr "La altura de la base de la torre de cebado. Aumentar este valor resultará en una torre de cebado más robusta porque la base será más ancha. Si esta configuración es demasiado baja, la torre de cebado no tendrá una base resistente."
msgctxt "support_bottom_stair_step_height description"
msgid "The height of the steps of the stair-like bottom of support resting on the model. A low value makes the support harder to remove, but too high values can lead to unstable support structures. Set to zero to turn off the stair-like behaviour."
@ -4061,8 +4061,8 @@ msgid "The length of material retracted during a retraction move."
msgstr "Longitud del material retraído durante un movimiento de retracción."
msgctxt "prime_tower_base_curve_magnitude description"
msgid "The magnitude factor used for the curve of the prime tower foot."
msgstr ""
msgid "The magnitude factor used for the slope of the prime tower base. If you increase this value, the base will become slimmer. If you decrease it, the base will become thicker."
msgstr "El factor de magnitud utilizado para la pendiente de la base de la torre de cebado. Si aumentas este valor, la base se volverá más delgada. Si lo disminuyes, la base se volverá más gruesa."
msgctxt "machine_buildplate_type description"
msgid "The material of the build plate installed on the printer."
@ -4618,7 +4618,7 @@ msgstr "La temperatura a la que se puede empezar a enfriar justo antes de finali
msgctxt "material_print_temperature_layer_0 description"
msgid "The temperature used for printing the first layer."
msgstr ""
msgstr "La temperatura utilizada para imprimir la primera capa."
msgctxt "material_print_temperature description"
msgid "The temperature used for printing."
@ -4697,8 +4697,8 @@ msgid "The width of the interlocking structure beams."
msgstr "El ancho de los haces de la estructura entrelazada."
msgctxt "prime_tower_base_size description"
msgid "The width of the prime tower base."
msgstr ""
msgid "The width of the prime tower brim/base. A larger base enhances adhesion to the build plate, but also reduces the effective print area."
msgstr "El ancho del borde/base de la torre de cebado. Una base más grande mejora la adhesión a la placa de construcción, pero también reduce el área efectiva de impresión."
msgctxt "prime_tower_size description"
msgid "The width of the prime tower."
@ -5488,62 +5488,42 @@ msgctxt "travel description"
msgid "travel"
msgstr "desplazamiento"
#~ msgctxt "support_bottom_distance description"
#~ msgid "Distance from the print to the bottom of the support."
#~ msgstr "Distancia desde la parte inferior del soporte a la impresión."
msgctxt "gradual_flow_discretisation_step_size description"
msgid "Duration of each step in the gradual flow change"
msgstr "Duración de cada paso en el cambio de flujo gradual"
#~ msgctxt "support_z_distance description"
#~ msgid "Distance from the top/bottom of the support structure to the print. This gap provides clearance to remove the supports after the model is printed. This value is rounded up to a multiple of the layer height."
#~ msgstr "Distancia desde la parte superior/inferior de la estructura de soporte a la impresión. Este hueco ofrece holgura para retirar los soportes tras imprimir el modelo. Este valor se redondea hacia el múltiplo de la altura de la capa."
msgctxt "gradual_flow_enabled description"
msgid "Enable gradual flow changes. When enabled, the flow is gradually increased/decreased to the target flow. This is useful for printers with a bowden tube where the flow is not immediately changed when the extruder motor starts/stops."
msgstr "Activar cambios graduales de flujo. Cuando está activado, el flujo aumenta/disminuye gradualmente hasta el flujo objetivo. Esto es útil para impresoras con un tubo bowden donde el flujo no cambia inmediatamente cuando el motor del extrusor se enciende/apaga."
#~ msgctxt "gradual_flow_discretisation_step_size description"
#~ msgid "Duration of each step in the gradual flow change"
#~ msgstr "Duración de cada paso en el cambio de flujo gradual"
msgctxt "reset_flow_duration description"
msgid "For any travel move longer than this value, the material flow is reset to the paths target flow"
msgstr "Para cualquier movimiento de desplazamiento superior a este valor, el flujo de material se restablece con el flujo objetivo de las trayectorias"
#~ msgctxt "gradual_flow_enabled description"
#~ msgid "Enable gradual flow changes. When enabled, the flow is gradually increased/decreased to the target flow. This is useful for printers with a bowden tube where the flow is not immediately changed when the extruder motor starts/stops."
#~ msgstr "Activar cambios graduales de flujo. Cuando está activado, el flujo aumenta/disminuye gradualmente hasta el flujo objetivo. Esto es útil para impresoras con un tubo bowden donde el flujo no cambia inmediatamente cuando el motor del extrusor se enciende/apaga."
msgctxt "gradual_flow_discretisation_step_size label"
msgid "Gradual flow discretisation step size"
msgstr "Tamaño del paso de discretización del flujo gradual"
#~ msgctxt "reset_flow_duration description"
#~ msgid "For any travel move longer than this value, the material flow is reset to the paths target flow"
#~ msgstr "Para cualquier movimiento de desplazamiento superior a este valor, el flujo de material se restablece con el flujo objetivo de las trayectorias"
msgctxt "gradual_flow_enabled label"
msgid "Gradual flow enabled"
msgstr "Flujo gradual activado"
#~ msgctxt "gradual_flow_discretisation_step_size label"
#~ msgid "Gradual flow discretisation step size"
#~ msgstr "Tamaño del paso de discretización del flujo gradual"
msgctxt "max_flow_acceleration label"
msgid "Gradual flow max acceleration"
msgstr "Aceleración máxima del flujo gradual"
#~ msgctxt "gradual_flow_enabled label"
#~ msgid "Gradual flow enabled"
#~ msgstr "Flujo gradual activado"
msgctxt "layer_0_max_flow_acceleration label"
msgid "Initial layer max flow acceleration"
msgstr "Aceleración máxima del flujo de la capa inicial"
#~ msgctxt "max_flow_acceleration label"
#~ msgid "Gradual flow max acceleration"
#~ msgstr "Aceleración máxima del flujo gradual"
msgctxt "max_flow_acceleration description"
msgid "Maximum acceleration for gradual flow changes"
msgstr "Aceleración máxima para los cambios de flujo graduales"
#~ msgctxt "layer_0_max_flow_acceleration label"
#~ msgid "Initial layer max flow acceleration"
#~ msgstr "Aceleración máxima del flujo de la capa inicial"
msgctxt "layer_0_max_flow_acceleration description"
msgid "Minimum speed for gradual flow changes for the first layer"
msgstr "Velocidad mínima para los cambios de flujo graduales de la primera capa"
#~ msgctxt "max_flow_acceleration description"
#~ msgid "Maximum acceleration for gradual flow changes"
#~ msgstr "Aceleración máxima para los cambios de flujo graduales"
#~ msgctxt "layer_0_max_flow_acceleration description"
#~ msgid "Minimum speed for gradual flow changes for the first layer"
#~ msgstr "Velocidad mínima para los cambios de flujo graduales de la primera capa"
#~ msgctxt "prime_tower_brim_enable label"
#~ msgid "Prime Tower Brim"
#~ msgstr "Borde de la torre auxiliar"
#~ msgctxt "prime_tower_brim_enable description"
#~ msgid "Prime-towers might need the extra adhesion afforded by a brim even if the model doesn't. Presently can't be used with the 'Raft' adhesion-type."
#~ msgstr "Puede que las torres auxiliares necesiten la adherencia adicional que proporciona un borde, aunque no sea requisito del modelo. Actualmente, no se puede usar con el tipo de adherencia «balsa»."
#~ msgctxt "reset_flow_duration label"
#~ msgid "Reset flow duration"
#~ msgstr "Restablecer duración del flujo"
#~ msgctxt "material_print_temperature_layer_0 description"
#~ msgid "The temperature used for printing the first layer. Set at 0 to disable special handling of the initial layer."
#~ msgstr "Temperatura que se usa para imprimir la primera capa. Se ajusta a 0 para desactivar la manipulación especial de la capa inicial."
msgctxt "reset_flow_duration label"
msgid "Reset flow duration"
msgstr "Restablecer duración del flujo"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Uranium json setting files\n"
"Report-Msgid-Bugs-To: plugins@ultimaker.com\n"
"POT-Creation-Date: 2023-10-31 19:13+0000\n"
"POT-Creation-Date: 2023-11-24 12:51+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE\n"
@ -4337,7 +4337,7 @@ msgid "Prime Tower Base"
msgstr ""
msgctxt "prime_tower_brim_enable description"
msgid "Prime-towers might need the extra adhesion afforded by a brim or raft, even if the model doesn't."
msgid "By enabling this setting, your prime-tower will get a brim, even if the model doesn't. If you want a sturdier base for a high tower, you can increase the base height."
msgstr ""
msgctxt "prime_tower_base_size label"
@ -4345,7 +4345,7 @@ msgid "Prime Tower Base Size"
msgstr ""
msgctxt "prime_tower_base_size description"
msgid "The width of the prime tower base."
msgid "The width of the prime tower brim/base. A larger base enhances adhesion to the build plate, but also reduces the effective print area."
msgstr ""
msgctxt "prime_tower_base_height label"
@ -4353,15 +4353,15 @@ msgid "Prime Tower Base Height"
msgstr ""
msgctxt "prime_tower_base_height description"
msgid "The height of the prime tower base."
msgid "The height of the prime tower base. Increasing this value will result in a more sturdy prime tower because the base will be wider. If this setting is too low, the prime tower will not have a sturdy base."
msgstr ""
msgctxt "prime_tower_base_curve_magnitude label"
msgid "Prime Tower Base Curve Magnitude"
msgid "Prime Tower Base Slope"
msgstr ""
msgctxt "prime_tower_base_curve_magnitude description"
msgid "The magnitude factor used for the curve of the prime tower foot."
msgid "The magnitude factor used for the slope of the prime tower base. If you increase this value, the base will become slimmer. If you decrease it, the base will become thicker."
msgstr ""
msgctxt "prime_tower_raft_base_line_spacing label"
@ -5476,3 +5476,42 @@ msgctxt "mesh_rotation_matrix description"
msgid "Transformation matrix to be applied to the model when loading it from file."
msgstr ""
msgctxt "gradual_flow_enabled label"
msgid "Gradual flow enabled"
msgstr ""
msgctxt "gradual_flow_enabled description"
msgid "Enable gradual flow changes. When enabled, the flow is gradually increased/decreased to the target flow. This is useful for printers with a bowden tube where the flow is not immediately changed when the extruder motor starts/stops."
msgstr ""
msgctxt "max_flow_acceleration label"
msgid "Gradual flow max acceleration"
msgstr ""
msgctxt "max_flow_acceleration description"
msgid "Maximum acceleration for gradual flow changes"
msgstr ""
msgctxt "layer_0_max_flow_acceleration label"
msgid "Initial layer max flow acceleration"
msgstr ""
msgctxt "layer_0_max_flow_acceleration description"
msgid "Minimum speed for gradual flow changes for the first layer"
msgstr ""
msgctxt "gradual_flow_discretisation_step_size label"
msgid "Gradual flow discretisation step size"
msgstr ""
msgctxt "gradual_flow_discretisation_step_size description"
msgid "Duration of each step in the gradual flow change"
msgstr ""
msgctxt "reset_flow_duration label"
msgid "Reset flow duration"
msgstr ""
msgctxt "reset_flow_duration description"
msgid "For any travel move longer than this value, the material flow is reset to the paths target flow"
msgstr ""

File diff suppressed because it is too large Load diff

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