mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-07 06:57:28 -06:00
Merge branch 'PP-245-high-speed-profiles' of github.com:Ultimaker/Cura into CURA-10953_introduce_any_color_material
This commit is contained in:
commit
e899b9987c
236 changed files with 9064 additions and 1321 deletions
23
.github/workflows/conan-package-create.yml
vendored
23
.github/workflows/conan-package-create.yml
vendored
|
@ -119,18 +119,12 @@ jobs:
|
||||||
sudo apt upgrade
|
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
|
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-12 on ubuntu-22.04
|
- name: Install GCC-132 on ubuntu
|
||||||
if: ${{ startsWith(inputs.runs_on, 'ubuntu-22.04') }}
|
if: ${{ startsWith(inputs.runs_on, 'ubuntu') }}
|
||||||
run: |
|
run: |
|
||||||
sudo apt install g++-12 gcc-12 -y
|
sudo apt install g++-13 gcc-13 -y
|
||||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 12
|
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13
|
||||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 12
|
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
|
||||||
|
|
||||||
- name: Use GCC-10 on ubuntu-20.04
|
|
||||||
if: ${{ startsWith(inputs.runs_on, 'ubuntu-20.04') }}
|
|
||||||
run: |
|
|
||||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 10
|
|
||||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 10
|
|
||||||
|
|
||||||
- name: Create the default Conan profile
|
- name: Create the default Conan profile
|
||||||
run: conan profile new default --detect
|
run: conan profile new default --detect
|
||||||
|
@ -140,14 +134,15 @@ jobs:
|
||||||
run: conan config install https://github.com/Ultimaker/conan-config.git -a "-b ${{ 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
|
- name: Get Conan configuration
|
||||||
if: ${{ inputs.conan_config_branch == '' }}
|
run: |
|
||||||
run: conan config install https://github.com/Ultimaker/conan-config.git
|
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
|
- name: Add Cura private Artifactory remote
|
||||||
run: conan remote add cura-private https://ultimaker.jfrog.io/artifactory/api/conan/cura-private True
|
run: conan remote add cura-private https://ultimaker.jfrog.io/artifactory/api/conan/cura-private True
|
||||||
|
|
||||||
- name: Create the Packages
|
- name: Create the Packages
|
||||||
run: conan install ${{ inputs.recipe_id_full }} --build=missing --update
|
run: conan install ${{ inputs.recipe_id_full }} --build=missing --update -c tools.build:skip_test=True
|
||||||
|
|
||||||
- name: Upload the Package(s)
|
- name: Upload the Package(s)
|
||||||
if: ${{ always() && inputs.conan_upload_community }}
|
if: ${{ always() && inputs.conan_upload_community }}
|
||||||
|
|
17
.github/workflows/conan-package.yml
vendored
17
.github/workflows/conan-package.yml
vendored
|
@ -57,7 +57,7 @@ env:
|
||||||
CONAN_LOGGING_LEVEL: ${{ inputs.conan_logging_level }}
|
CONAN_LOGGING_LEVEL: ${{ inputs.conan_logging_level }}
|
||||||
CONAN_NON_INTERACTIVE: 1
|
CONAN_NON_INTERACTIVE: 1
|
||||||
|
|
||||||
permissions: {}
|
permissions: { }
|
||||||
jobs:
|
jobs:
|
||||||
conan-recipe-version:
|
conan-recipe-version:
|
||||||
permissions:
|
permissions:
|
||||||
|
@ -103,18 +103,23 @@ jobs:
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt upgrade
|
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
|
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
|
||||||
sudo apt install g++-12 gcc-12 -y
|
|
||||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 12
|
- name: Install GCC-13
|
||||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 12
|
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
|
- name: Create the default Conan profile
|
||||||
run: conan profile new default --detect --force
|
run: conan profile new default --detect --force
|
||||||
|
|
||||||
- name: Get Conan configuration
|
- name: Get Conan configuration
|
||||||
run: conan config install https://github.com/Ultimaker/conan-config.git
|
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
|
- 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
|
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
|
- name: Create the latest alias
|
||||||
if: always()
|
if: always()
|
||||||
|
|
7
.github/workflows/conan-recipe-export.yml
vendored
7
.github/workflows/conan-recipe-export.yml
vendored
|
@ -75,15 +75,16 @@ jobs:
|
||||||
run: conan config install https://github.com/Ultimaker/conan-config.git -a "-b ${{ 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
|
- name: Get Conan configuration
|
||||||
if: ${{ inputs.conan_config_branch == '' }}
|
run: |
|
||||||
run: conan config install https://github.com/Ultimaker/conan-config.git
|
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
|
- name: Add Cura private Artifactory remote
|
||||||
run: conan remote add cura-private https://ultimaker.jfrog.io/artifactory/api/conan/cura-private True
|
run: conan remote add cura-private https://ultimaker.jfrog.io/artifactory/api/conan/cura-private True
|
||||||
|
|
||||||
- name: Export the Package (binaries)
|
- name: Export the Package (binaries)
|
||||||
if: ${{ inputs.conan_export_binaries }}
|
if: ${{ inputs.conan_export_binaries }}
|
||||||
run: conan create . ${{ inputs.recipe_id_full }} --build=missing --update
|
run: conan create . ${{ inputs.recipe_id_full }} --build=missing --update -c tools.build:skip_test=True
|
||||||
|
|
||||||
- name: Export the Package
|
- name: Export the Package
|
||||||
if: ${{ !inputs.conan_export_binaries }}
|
if: ${{ !inputs.conan_export_binaries }}
|
||||||
|
|
151
.github/workflows/cura-all-installers.yml
vendored
151
.github/workflows/cura-all-installers.yml
vendored
|
@ -1,151 +0,0 @@
|
||||||
name: Cura All Installers
|
|
||||||
run-name: ${{ inputs.cura_conan_version }} for exe ${{ inputs.build_windows_exe }}, msi ${{ inputs.build_windows_msi }}, dmg ${{ inputs.build_macos }}, pkg ${{ inputs.build_macos_installer }}, appimage ${{ inputs.build_linux }} - enterprise ${{ inputs.enterprise }}
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
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
|
|
||||||
conan_config:
|
|
||||||
description: 'Conan config branch to use'
|
|
||||||
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
|
|
||||||
installer:
|
|
||||||
description: 'Create the installer'
|
|
||||||
default: true
|
|
||||||
required: true
|
|
||||||
type: boolean
|
|
||||||
build_windows_exe:
|
|
||||||
description: 'Build for Windows exe'
|
|
||||||
default: false
|
|
||||||
required: true
|
|
||||||
type: boolean
|
|
||||||
build_windows_msi:
|
|
||||||
description: 'Build for msi+pkg'
|
|
||||||
default: true
|
|
||||||
required: true
|
|
||||||
type: boolean
|
|
||||||
build_linux:
|
|
||||||
description: 'Build for Linux'
|
|
||||||
default: true
|
|
||||||
required: true
|
|
||||||
type: boolean
|
|
||||||
build_macos:
|
|
||||||
description: 'Build dmg for MacOS'
|
|
||||||
default: true
|
|
||||||
required: true
|
|
||||||
type: boolean
|
|
||||||
|
|
||||||
# Run the nightly at 3:25 UTC on working days
|
|
||||||
schedule:
|
|
||||||
- cron: '25 3 * * 1-5'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
windows-installer-create-exe:
|
|
||||||
if: ${{ inputs.build_windows_exe }}
|
|
||||||
uses: ./.github/workflows/cura-installer.yml
|
|
||||||
with:
|
|
||||||
platform: 'windows-2022'
|
|
||||||
os_name: 'win64'
|
|
||||||
cura_conan_version: ${{ inputs.cura_conan_version }}
|
|
||||||
conan_args: ${{ inputs.conan_args }}
|
|
||||||
conan_config: ${{ inputs.conan_config }}
|
|
||||||
enterprise: ${{ inputs.enterprise }}
|
|
||||||
staging: ${{ inputs.staging }}
|
|
||||||
installer: ${{ inputs.installer }}
|
|
||||||
msi_installer: false
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
windows-installer-create-msi:
|
|
||||||
if: ${{ inputs.build_windows_msi }}
|
|
||||||
uses: ./.github/workflows/cura-installer.yml
|
|
||||||
with:
|
|
||||||
platform: 'windows-2022'
|
|
||||||
os_name: 'win64'
|
|
||||||
cura_conan_version: ${{ inputs.cura_conan_version }}
|
|
||||||
conan_args: ${{ inputs.conan_args }}
|
|
||||||
conan_config: ${{ inputs.conan_config }}
|
|
||||||
enterprise: ${{ inputs.enterprise }}
|
|
||||||
staging: ${{ inputs.staging }}
|
|
||||||
installer: ${{ inputs.installer }}
|
|
||||||
msi_installer: true
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
linux-installer-create:
|
|
||||||
if: ${{ inputs.build_linux }}
|
|
||||||
uses: ./.github/workflows/cura-installer.yml
|
|
||||||
with:
|
|
||||||
platform: 'ubuntu-20.04'
|
|
||||||
os_name: 'linux'
|
|
||||||
cura_conan_version: ${{ inputs.cura_conan_version }}
|
|
||||||
conan_args: ${{ inputs.conan_args }}
|
|
||||||
conan_config: ${{ inputs.conan_config }}
|
|
||||||
enterprise: ${{ inputs.enterprise }}
|
|
||||||
staging: ${{ inputs.staging }}
|
|
||||||
installer: ${{ inputs.installer }}
|
|
||||||
msi_installer: false
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
linux-modern-installer-create:
|
|
||||||
if: ${{ inputs.build_linux }}
|
|
||||||
uses: ./.github/workflows/cura-installer.yml
|
|
||||||
with:
|
|
||||||
platform: 'ubuntu-22.04'
|
|
||||||
os_name: 'linux-modern'
|
|
||||||
cura_conan_version: ${{ inputs.cura_conan_version }}
|
|
||||||
conan_args: ${{ inputs.conan_args }}
|
|
||||||
conan_config: ${{ inputs.conan_config }}
|
|
||||||
enterprise: ${{ inputs.enterprise }}
|
|
||||||
staging: ${{ inputs.staging }}
|
|
||||||
installer: ${{ inputs.installer }}
|
|
||||||
msi_installer: false
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
macos-dmg-create:
|
|
||||||
if: ${{ inputs.build_macos }}
|
|
||||||
uses: ./.github/workflows/cura-installer.yml
|
|
||||||
with:
|
|
||||||
platform: 'macos-11'
|
|
||||||
os_name: 'mac'
|
|
||||||
cura_conan_version: ${{ inputs.cura_conan_version }}
|
|
||||||
conan_args: ${{ inputs.conan_args }}
|
|
||||||
conan_config: ${{ inputs.conan_config }}
|
|
||||||
enterprise: ${{ inputs.enterprise }}
|
|
||||||
staging: ${{ inputs.staging }}
|
|
||||||
installer: ${{ inputs.installer }}
|
|
||||||
msi_installer: false
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
macos-installer-create:
|
|
||||||
if: ${{ inputs.build_macos }}
|
|
||||||
uses: ./.github/workflows/cura-installer.yml
|
|
||||||
with:
|
|
||||||
platform: 'macos-11'
|
|
||||||
os_name: 'mac'
|
|
||||||
cura_conan_version: ${{ inputs.cura_conan_version }}
|
|
||||||
conan_args: ${{ inputs.conan_args }}
|
|
||||||
conan_config: ${{ inputs.conan_config }}
|
|
||||||
enterprise: ${{ inputs.enterprise }}
|
|
||||||
staging: ${{ inputs.staging }}
|
|
||||||
installer: ${{ inputs.installer }}
|
|
||||||
msi_installer: true
|
|
||||||
secrets: inherit
|
|
390
.github/workflows/cura-installer.yml
vendored
390
.github/workflows/cura-installer.yml
vendored
|
@ -1,390 +0,0 @@
|
||||||
name: Cura Installer
|
|
||||||
run-name: ${{ inputs.cura_conan_version }} for ${{ inputs.platform }} by @${{ github.actor }}
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
platform:
|
|
||||||
description: 'Selected Installer OS'
|
|
||||||
default: 'ubuntu-20.04'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
os_name:
|
|
||||||
description: 'OS Friendly Name'
|
|
||||||
default: 'linux'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
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
|
|
||||||
conan_config:
|
|
||||||
description: 'Conan config branch to use'
|
|
||||||
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
|
|
||||||
installer:
|
|
||||||
description: 'Create the installer'
|
|
||||||
default: true
|
|
||||||
required: true
|
|
||||||
type: boolean
|
|
||||||
msi_installer:
|
|
||||||
description: 'Create the msi'
|
|
||||||
default: false
|
|
||||||
required: true
|
|
||||||
type: boolean
|
|
||||||
|
|
||||||
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
|
|
||||||
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 }}
|
|
||||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
|
||||||
MACOS_CERT_PASSPHRASE: ${{ secrets.MACOS_CERT_PASSPHRASE }}
|
|
||||||
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.platform }}
|
|
||||||
|
|
||||||
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 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-${{ runner.os }}-${{ runner.arch }}-installer-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-${{ runner.os }}-${{ runner.arch }}-installer-cache
|
|
||||||
|
|
||||||
- name: Install MacOS system requirements
|
|
||||||
if: ${{ runner.os == 'Macos' }}
|
|
||||||
run: brew install autoconf automake ninja create-dmg # Delete create-dmg when deprecating dmg
|
|
||||||
|
|
||||||
- name: Hack needed specifically for ubuntu-22.04 from mid-Feb 2023 onwards
|
|
||||||
if: ${{ runner.os == 'Linux' && startsWith(inputs.platform, 'ubuntu-22.04') }}
|
|
||||||
run: sudo apt remove libodbc2 libodbcinst2 unixodbc-common -y
|
|
||||||
|
|
||||||
# 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
|
|
||||||
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
|
|
||||||
|
|
||||||
- name: Install GCC-12 on ubuntu-22.04
|
|
||||||
if: ${{ startsWith(inputs.platform, 'ubuntu-22.04') }}
|
|
||||||
run: |
|
|
||||||
sudo apt install g++-12 gcc-12 -y
|
|
||||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 12
|
|
||||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 12
|
|
||||||
|
|
||||||
- name: Use GCC-10 on ubuntu-20.04
|
|
||||||
if: ${{ startsWith(inputs.platform, 'ubuntu-20.04') }}
|
|
||||||
run: |
|
|
||||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 10
|
|
||||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 10
|
|
||||||
|
|
||||||
- name: Create the default Conan profile
|
|
||||||
run: conan profile new default --detect
|
|
||||||
|
|
||||||
- name: Configure GPG Key Linux (Bash)
|
|
||||||
if: ${{ runner.os == 'Linux' }}
|
|
||||||
run: echo -n "$GPG_PRIVATE_KEY" | base64 --decode | gpg --import
|
|
||||||
|
|
||||||
- name: Configure Macos keychain Developer Cert(Bash)
|
|
||||||
id: macos-keychain-developer-cert
|
|
||||||
if: ${{ runner.os == 'Macos' }}
|
|
||||||
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
|
|
||||||
if: ${{ runner.os == 'Macos' }}
|
|
||||||
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: Create PFX certificate from BASE64_PFX_CONTENT secret
|
|
||||||
if: ${{ runner.os == 'Windows' }}
|
|
||||||
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: Get Conan configuration from branch
|
|
||||||
if: ${{ inputs.conan_config != '' }}
|
|
||||||
run: conan config install https://github.com/Ultimaker/conan-config.git -a "-b ${{ inputs.conan_config }}"
|
|
||||||
|
|
||||||
- name: Get Conan configuration
|
|
||||||
if: ${{ inputs.conan_config == '' }}
|
|
||||||
run: conan config install https://github.com/Ultimaker/conan-config.git
|
|
||||||
|
|
||||||
- name: Create the Packages (Bash)
|
|
||||||
if: ${{ runner.os != 'Windows' }}
|
|
||||||
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 --json "cura_inst/conan_install_info.json"
|
|
||||||
|
|
||||||
- name: Create the Packages (Powershell)
|
|
||||||
if: ${{ runner.os == 'Windows' }}
|
|
||||||
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 --json "cura_inst/conan_install_info.json"
|
|
||||||
|
|
||||||
- name: Set Environment variables for Cura (bash)
|
|
||||||
if: ${{ runner.os != 'Windows' }}
|
|
||||||
run: |
|
|
||||||
. ./cura_inst/bin/activate_github_actions_env.sh
|
|
||||||
. ./cura_inst/bin/activate_github_actions_version_env.sh
|
|
||||||
|
|
||||||
- name: Set Environment variables for Cura (Powershell)
|
|
||||||
if: ${{ runner.os == 'Windows' }}
|
|
||||||
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: Unlock Macos keychain (Bash)
|
|
||||||
if: ${{ runner.os == 'Macos' }}
|
|
||||||
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)
|
|
||||||
if: ${{ runner.os != 'Windows' }}
|
|
||||||
run: |
|
|
||||||
cp ./openssl/lib/*.so* ./cura_inst/bin/ || true
|
|
||||||
cp ./openssl/lib/*.dylib* ./cura_inst/bin/ || true
|
|
||||||
|
|
||||||
- name: Copy OpenSSL shared (Powershell)
|
|
||||||
if: ${{ runner.os == 'Windows' }}
|
|
||||||
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}-${{ inputs.os_name }}"
|
|
||||||
if "${{ runner.os }}" == "Windows":
|
|
||||||
installer_ext = "msi" if "${{ inputs.msi_installer }}" == "true" else "exe"
|
|
||||||
elif "${{ runner.os }}" == "macOS":
|
|
||||||
installer_ext = "pkg" if "${{ inputs.msi_installer }}" == "true" else "dmg"
|
|
||||||
else:
|
|
||||||
installer_ext = "AppImage"
|
|
||||||
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")
|
|
||||||
f.writelines(f"INSTALLER_EXT={installer_ext}\n")
|
|
||||||
f.writelines(f"FULL_INSTALLER_FILENAME={installer_filename}.{installer_ext}\n")
|
|
||||||
|
|
||||||
- name: Summarize the used Conan dependencies
|
|
||||||
shell: python
|
|
||||||
run: |
|
|
||||||
import os
|
|
||||||
import json
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
conan_install_info_path = Path("cura_inst/conan_install_info.json")
|
|
||||||
conan_info = {"installed": []}
|
|
||||||
if os.path.exists(conan_install_info_path):
|
|
||||||
with open(conan_install_info_path, "r") as f:
|
|
||||||
conan_info = json.load(f)
|
|
||||||
sorted_deps = sorted([dep["recipe"]["id"].replace('#', r' rev: ') for dep in conan_info["installed"]])
|
|
||||||
|
|
||||||
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.FULL_INSTALLER_FILENAME }}\n")
|
|
||||||
f.writelines("## Conan packages:\n")
|
|
||||||
for dep in sorted_deps:
|
|
||||||
f.writelines(f"`{dep}`\n")
|
|
||||||
|
|
||||||
- name: Summarize the used Python modules
|
|
||||||
shell: python
|
|
||||||
run: |
|
|
||||||
import os
|
|
||||||
import pkg_resources
|
|
||||||
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("## Python modules:\n")
|
|
||||||
for package in pkg_resources.working_set:
|
|
||||||
f.writelines(f"`{package.key}/{package.version}`\n")
|
|
||||||
|
|
||||||
- name: Archive the artifacts (bash)
|
|
||||||
if: ${{ !inputs.installer && runner.os != 'Windows' }}
|
|
||||||
run: tar -zcf "./${{ steps.filename.outputs.INSTALLER_FILENAME }}.tar.gz" "./UltiMaker-Cura/"
|
|
||||||
working-directory: dist
|
|
||||||
|
|
||||||
- name: Archive the artifacts (Powershell)
|
|
||||||
if: ${{ !inputs.installer && runner.os == 'Windows' }}
|
|
||||||
run: Compress-Archive -Path ".\UltiMaker-Cura" -DestinationPath ".\${{ steps.filename.outputs.INSTALLER_FILENAME }}.zip"
|
|
||||||
working-directory: dist
|
|
||||||
|
|
||||||
- name: Create the Windows exe installer (Powershell)
|
|
||||||
if: ${{ inputs.installer && runner.os == 'Windows' && !inputs.msi_installer }}
|
|
||||||
run: |
|
|
||||||
python ..\cura_inst\packaging\NSIS\create_windows_installer.py ../cura_inst . "${{ steps.filename.outputs.FULL_INSTALLER_FILENAME }}"
|
|
||||||
working-directory: dist
|
|
||||||
|
|
||||||
- name: Create the Windows msi installer (Powershell)
|
|
||||||
if: ${{ inputs.installer && runner.os == 'Windows' && inputs.msi_installer }}
|
|
||||||
run: |
|
|
||||||
python ..\cura_inst\packaging\msi\create_windows_msi.py ..\cura_inst .\UltiMaker-Cura "${{ steps.filename.outputs.FULL_INSTALLER_FILENAME }}" "$Env:CURA_APP_NAME"
|
|
||||||
working-directory: dist
|
|
||||||
|
|
||||||
- name: Sign the Windows exe installer (Powershell)
|
|
||||||
if: ${{ inputs.installer && runner.os == 'Windows' && !inputs.msi_installer }}
|
|
||||||
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.FULL_INSTALLER_FILENAME }}"
|
|
||||||
working-directory: dist
|
|
||||||
|
|
||||||
- name: Sign the Windows msi installer (Powershell)
|
|
||||||
if: ${{ inputs.installer && runner.os == 'Windows' && inputs.msi_installer }}
|
|
||||||
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.FULL_INSTALLER_FILENAME }}"
|
|
||||||
working-directory: dist
|
|
||||||
|
|
||||||
- name: Create the Linux AppImage (Bash)
|
|
||||||
if: ${{ inputs.installer && runner.os == 'Linux' }}
|
|
||||||
run: python ../cura_inst/packaging/AppImage/create_appimage.py ./UltiMaker-Cura $CURA_VERSION_FULL "${{ steps.filename.outputs.FULL_INSTALLER_FILENAME }}"
|
|
||||||
working-directory: dist
|
|
||||||
|
|
||||||
- name: Create the MacOS dmg and/or pkg (Bash)
|
|
||||||
if: ${{ github.event.inputs.installer == 'true' && runner.os == 'Macos' }}
|
|
||||||
run: python ../cura_inst/packaging/MacOS/build_macos.py ../cura_inst . $CURA_CONAN_VERSION "${{ steps.filename.outputs.FULL_INSTALLER_FILENAME }}" "$CURA_APP_NAME"
|
|
||||||
working-directory: dist
|
|
||||||
|
|
||||||
- name: Upload the artifacts
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: ${{ steps.filename.outputs.INSTALLER_FILENAME }}-${{ steps.filename.outputs.INSTALLER_EXT }}
|
|
||||||
path: |
|
|
||||||
dist/*.tar.gz
|
|
||||||
dist/*.zip
|
|
||||||
dist/${{ steps.filename.outputs.FULL_INSTALLER_FILENAME }}
|
|
||||||
dist/*.asc
|
|
||||||
retention-days: 5
|
|
||||||
|
|
||||||
notify-export:
|
|
||||||
if: ${{ always() }}
|
|
||||||
needs: [ cura-installer-create ]
|
|
||||||
|
|
||||||
uses: ultimaker/cura/.github/workflows/notify.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
|
|
82
.github/workflows/installers.yml
vendored
Normal file
82
.github/workflows/installers.yml
vendored
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
name: All installers
|
||||||
|
run-name: ${{ inputs.cura_conan_version }} by @${{ github.actor }}
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
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
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
windows-installer:
|
||||||
|
uses: ./.github/workflows/windows.yml
|
||||||
|
with:
|
||||||
|
cura_conan_version: ${{ inputs.cura_conan_version }}
|
||||||
|
conan_args: ${{ inputs.conan_args }}
|
||||||
|
enterprise: ${{ inputs.enterprise }}
|
||||||
|
staging: ${{ inputs.staging }}
|
||||||
|
architecture: X64
|
||||||
|
operating_system: windows-2022
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
linux-modern-installer:
|
||||||
|
uses: ./.github/workflows/linux.yml
|
||||||
|
with:
|
||||||
|
cura_conan_version: ${{ inputs.cura_conan_version }}
|
||||||
|
conan_args: ${{ inputs.conan_args }}
|
||||||
|
enterprise: ${{ inputs.enterprise }}
|
||||||
|
staging: ${{ inputs.staging }}
|
||||||
|
architecture: X64
|
||||||
|
operating_system: ubuntu-22.04
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
linux-legacy-installer:
|
||||||
|
uses: ./.github/workflows/linux.yml
|
||||||
|
with:
|
||||||
|
cura_conan_version: ${{ inputs.cura_conan_version }}
|
||||||
|
conan_args: ${{ inputs.conan_args }}
|
||||||
|
enterprise: ${{ inputs.enterprise }}
|
||||||
|
staging: ${{ inputs.staging }}
|
||||||
|
architecture: X64
|
||||||
|
operating_system: ubuntu-20.04
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
macos-installer:
|
||||||
|
uses: ./.github/workflows/macos.yml
|
||||||
|
with:
|
||||||
|
cura_conan_version: ${{ inputs.cura_conan_version }}
|
||||||
|
conan_args: ${{ inputs.conan_args }}
|
||||||
|
enterprise: ${{ inputs.enterprise }}
|
||||||
|
staging: ${{ inputs.staging }}
|
||||||
|
architecture: X64
|
||||||
|
operating_system: macos-11.0
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
macos-arm-installer:
|
||||||
|
uses: ./.github/workflows/macos.yml
|
||||||
|
with:
|
||||||
|
cura_conan_version: ${{ inputs.cura_conan_version }}
|
||||||
|
conan_args: ${{ inputs.conan_args }}
|
||||||
|
enterprise: ${{ inputs.enterprise }}
|
||||||
|
staging: ${{ inputs.staging }}
|
||||||
|
architecture: ARM64
|
||||||
|
operating_system: self-hosted
|
||||||
|
secrets: inherit
|
264
.github/workflows/linux.yml
vendored
Normal file
264
.github/workflows/linux.yml
vendored
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
name: Linux Installer
|
||||||
|
run-name: ${{ inputs.cura_conan_version }} for Linux-${{ inputs.architecture }} by @${{ github.actor }}
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
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: choice
|
||||||
|
options:
|
||||||
|
- X64
|
||||||
|
operating_system:
|
||||||
|
description: 'OS'
|
||||||
|
required: true
|
||||||
|
default: 'ubuntu-22.04'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- ubuntu-22.04
|
||||||
|
- ubuntu-20.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: Hack needed specifically for ubuntu-22.04 from mid-Feb 2023 onwards
|
||||||
|
if: ${{ startsWith(inputs.operating_system, 'ubuntu-22.04') }}
|
||||||
|
run: sudo apt remove libodbc2 libodbcinst2 unixodbc-common -y
|
||||||
|
|
||||||
|
# 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
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
- 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 --json "cura_inst/conan_install_info.json"
|
||||||
|
|
||||||
|
- 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 ""
|
||||||
|
if "${{ inputs.operating_system }}" == "ubuntu-22.04":
|
||||||
|
installer_filename = f"UltiMaker-Cura-{os.getenv('CURA_VERSION_FULL')}{enterprise}-linux-modern-${{ inputs.architecture }}"
|
||||||
|
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 Conan dependencies
|
||||||
|
shell: python
|
||||||
|
run: |
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
conan_install_info_path = Path("cura_inst/conan_install_info.json")
|
||||||
|
conan_info = {"installed": []}
|
||||||
|
if os.path.exists(conan_install_info_path):
|
||||||
|
with open(conan_install_info_path, "r") as f:
|
||||||
|
conan_info = json.load(f)
|
||||||
|
sorted_deps = sorted([dep["recipe"]["id"].replace('#', r' rev: ') for dep in conan_info["installed"]])
|
||||||
|
|
||||||
|
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 in sorted_deps:
|
||||||
|
f.writelines(f"`{dep}`\n")
|
||||||
|
|
||||||
|
- name: Summarize the used Python modules
|
||||||
|
shell: python
|
||||||
|
run: |
|
||||||
|
import os
|
||||||
|
import pkg_resources
|
||||||
|
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("## Python modules:\n")
|
||||||
|
for package in pkg_resources.working_set:
|
||||||
|
f.writelines(f"`{package.key}/{package.version}`\n")
|
||||||
|
|
||||||
|
- name: Create the Linux AppImage (Bash)
|
||||||
|
run: |
|
||||||
|
python ../cura_inst/packaging/AppImage/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
|
||||||
|
|
||||||
|
notify-export:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: [ cura-installer-create ]
|
||||||
|
|
||||||
|
uses: ultimaker/cura/.github/workflows/notify.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
|
279
.github/workflows/macos.yml
vendored
Normal file
279
.github/workflows/macos.yml
vendored
Normal file
|
@ -0,0 +1,279 @@
|
||||||
|
name: Macos Installer
|
||||||
|
run-name: ${{ inputs.cura_conan_version }} for Macos-${{ inputs.architecture }} by @${{ github.actor }}
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
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: choice
|
||||||
|
options:
|
||||||
|
- X64
|
||||||
|
- ARM64
|
||||||
|
operating_system:
|
||||||
|
description: 'OS'
|
||||||
|
required: true
|
||||||
|
default: 'macos-11'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- self-hosted
|
||||||
|
- 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: 'X64'
|
||||||
|
type: string
|
||||||
|
operating_system:
|
||||||
|
description: 'OS'
|
||||||
|
required: true
|
||||||
|
default: 'macos-11'
|
||||||
|
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.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 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: 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 --json "cura_inst/conan_install_info.json"
|
||||||
|
|
||||||
|
- 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
|
||||||
|
|
||||||
|
- 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 Conan dependencies
|
||||||
|
shell: python
|
||||||
|
run: |
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
conan_install_info_path = Path("cura_inst/conan_install_info.json")
|
||||||
|
conan_info = {"installed": []}
|
||||||
|
if os.path.exists(conan_install_info_path):
|
||||||
|
with open(conan_install_info_path, "r") as f:
|
||||||
|
conan_info = json.load(f)
|
||||||
|
sorted_deps = sorted([dep["recipe"]["id"].replace('#', r' rev: ') for dep in conan_info["installed"]])
|
||||||
|
|
||||||
|
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 in sorted_deps:
|
||||||
|
f.writelines(f"`{dep}`\n")
|
||||||
|
|
||||||
|
- name: Summarize the used Python modules
|
||||||
|
shell: python
|
||||||
|
run: |
|
||||||
|
import os
|
||||||
|
import pkg_resources
|
||||||
|
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("## Python modules:\n")
|
||||||
|
for package in pkg_resources.working_set:
|
||||||
|
f.writelines(f"`{package.key}/{package.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
|
||||||
|
|
||||||
|
|
||||||
|
notify-export:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: [ cura-installer-create ]
|
||||||
|
|
||||||
|
uses: ultimaker/cura/.github/workflows/notify.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
|
|
@ -1,2 +1,2 @@
|
||||||
conan==1.56.0
|
conan>=1.60.2,<2.0.0
|
||||||
sip
|
sip
|
||||||
|
|
12
.github/workflows/unit-test.yml
vendored
12
.github/workflows/unit-test.yml
vendored
|
@ -115,14 +115,16 @@ jobs:
|
||||||
sudo apt upgrade
|
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
|
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-12 on ubuntu-22.04
|
- name: Install GCC-13
|
||||||
run: |
|
run: |
|
||||||
sudo apt install g++-12 gcc-12 -y
|
sudo apt install g++-13 gcc-13 -y
|
||||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 12
|
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13
|
||||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 12
|
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
|
||||||
|
|
||||||
- name: Get Conan configuration
|
- name: Get Conan configuration
|
||||||
run: conan config install https://github.com/Ultimaker/conan-config.git
|
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
|
- name: Get Conan profile
|
||||||
run: conan profile new default --detect --force
|
run: conan profile new default --detect --force
|
||||||
|
|
15
.github/workflows/update-translation.yml
vendored
15
.github/workflows/update-translation.yml
vendored
|
@ -44,7 +44,7 @@ jobs:
|
||||||
- name: Setup Python and pip
|
- name: Setup Python and pip
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: 3.10.x
|
python-version: 3.11.x
|
||||||
cache: pip
|
cache: pip
|
||||||
cache-dependency-path: .github/workflows/requirements-conan-package.txt
|
cache-dependency-path: .github/workflows/requirements-conan-package.txt
|
||||||
|
|
||||||
|
@ -62,15 +62,20 @@ jobs:
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt upgrade
|
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
|
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
|
||||||
sudo apt install g++-12 gcc-12 -y
|
|
||||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 12
|
- name: Install GCC-13
|
||||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 12
|
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
|
- name: Create the default Conan profile
|
||||||
run: conan profile new default --detect --force
|
run: conan profile new default --detect --force
|
||||||
|
|
||||||
- name: Get Conan configuration
|
- name: Get Conan configuration
|
||||||
run: conan config install https://github.com/Ultimaker/conan-config.git
|
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: generate the files using Conan install
|
- name: generate the files using Conan install
|
||||||
run: conan install . --build=missing --update -o cura:devtools=True
|
run: conan install . --build=missing --update -o cura:devtools=True
|
||||||
|
|
270
.github/workflows/windows.yml
vendored
Normal file
270
.github/workflows/windows.yml
vendored
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
name: Windows Installer
|
||||||
|
run-name: ${{ inputs.cura_conan_version }} for Windows-${{ inputs.architecture }} by @${{ github.actor }}
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
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: choice
|
||||||
|
options:
|
||||||
|
- X64
|
||||||
|
operating_system:
|
||||||
|
description: 'OS'
|
||||||
|
required: true
|
||||||
|
default: 'windows-2022'
|
||||||
|
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 --json "cura_inst/conan_install_info.json"
|
||||||
|
|
||||||
|
- 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 Conan dependencies
|
||||||
|
shell: python
|
||||||
|
run: |
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
conan_install_info_path = Path("cura_inst/conan_install_info.json")
|
||||||
|
conan_info = {"installed": []}
|
||||||
|
if os.path.exists(conan_install_info_path):
|
||||||
|
with open(conan_install_info_path, "r") as f:
|
||||||
|
conan_info = json.load(f)
|
||||||
|
sorted_deps = sorted([dep["recipe"]["id"].replace('#', r' rev: ') for dep in conan_info["installed"]])
|
||||||
|
|
||||||
|
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 in sorted_deps:
|
||||||
|
f.writelines(f"`{dep}`\n")
|
||||||
|
|
||||||
|
- name: Summarize the used Python modules
|
||||||
|
shell: python
|
||||||
|
run: |
|
||||||
|
import os
|
||||||
|
import pkg_resources
|
||||||
|
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("## Python modules:\n")
|
||||||
|
for package in pkg_resources.working_set:
|
||||||
|
f.writelines(f"`{package.key}/{package.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
|
||||||
|
|
||||||
|
notify-export:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: [ cura-installer-create ]
|
||||||
|
|
||||||
|
uses: ultimaker/cura/.github/workflows/notify.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
|
|
@ -18,8 +18,8 @@ url: "https://ultimaker.com/software/ultimaker-cura"
|
||||||
repository-code: "https://github.com/Ultimaker/Cura"
|
repository-code: "https://github.com/Ultimaker/Cura"
|
||||||
license: LGPL-3.0
|
license: LGPL-3.0
|
||||||
license-url: "https://github.com/Ultimaker/Cura/blob/main/LICENSE"
|
license-url: "https://github.com/Ultimaker/Cura/blob/main/LICENSE"
|
||||||
version: 5.2.1
|
version: 5.4.0
|
||||||
date-released: "2022-10-19"
|
date-released: "2023-07-04"
|
||||||
keywords:
|
keywords:
|
||||||
- Ultimaker
|
- Ultimaker
|
||||||
- Cura
|
- Cura
|
||||||
|
|
1
FUNDING.yml
Normal file
1
FUNDING.yml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
github: [ultimaker]
|
66
conanfile.py
66
conanfile.py
|
@ -10,7 +10,7 @@ from conan.tools.env import VirtualRunEnv, Environment, VirtualBuildEnv
|
||||||
from conan.tools.scm import Version
|
from conan.tools.scm import Version
|
||||||
from conan.errors import ConanInvalidConfiguration, ConanException
|
from conan.errors import ConanInvalidConfiguration, ConanException
|
||||||
|
|
||||||
required_conan_version = ">=1.54 <=1.56.0 || >=1.58.0 <2.0.0"
|
required_conan_version = ">=1.58.0 <2.0.0"
|
||||||
|
|
||||||
|
|
||||||
class CuraConan(ConanFile):
|
class CuraConan(ConanFile):
|
||||||
|
@ -293,6 +293,7 @@ class CuraConan(ConanFile):
|
||||||
self.options["pysavitar"].shared = True
|
self.options["pysavitar"].shared = True
|
||||||
self.options["pynest2d"].shared = True
|
self.options["pynest2d"].shared = True
|
||||||
self.options["cpython"].shared = True
|
self.options["cpython"].shared = True
|
||||||
|
self.options["boost"].header_only = True
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
version = self.conf_info.get("user.cura:version", default = self.version, check_type = str)
|
version = self.conf_info.get("user.cura:version", default = self.version, check_type = str)
|
||||||
|
@ -300,10 +301,11 @@ class CuraConan(ConanFile):
|
||||||
raise ConanInvalidConfiguration("Only versions 5+ are support")
|
raise ConanInvalidConfiguration("Only versions 5+ are support")
|
||||||
|
|
||||||
def requirements(self):
|
def requirements(self):
|
||||||
self.requires("pyarcus/5.2.2")
|
self.requires("boost/1.82.0")
|
||||||
|
self.requires("pyarcus/(latest)@ultimaker/cura_10951")
|
||||||
self.requires("curaengine/(latest)@ultimaker/testing")
|
self.requires("curaengine/(latest)@ultimaker/testing")
|
||||||
self.requires("pysavitar/5.2.2")
|
self.requires("pysavitar/(latest)@ultimaker/cura_10951")
|
||||||
self.requires("pynest2d/5.2.2")
|
self.requires("pynest2d/(latest)@ultimaker/cura_10951")
|
||||||
self.requires("uranium/(latest)@ultimaker/testing")
|
self.requires("uranium/(latest)@ultimaker/testing")
|
||||||
self.requires("cura_binary_data/(latest)@ultimaker/testing")
|
self.requires("cura_binary_data/(latest)@ultimaker/testing")
|
||||||
self.requires("cpython/3.10.4")
|
self.requires("cpython/3.10.4")
|
||||||
|
@ -338,7 +340,38 @@ class CuraConan(ConanFile):
|
||||||
vr.generate()
|
vr.generate()
|
||||||
|
|
||||||
self._generate_cura_version(os.path.join(self.source_folder, "cura"))
|
self._generate_cura_version(os.path.join(self.source_folder, "cura"))
|
||||||
|
self._generate_about_versions(os.path.join(self.source_folder, "resources","qml", "Dialogs"))
|
||||||
|
|
||||||
|
if not self.in_local_cache:
|
||||||
|
# Copy CuraEngine.exe to bindirs of Virtual Python Environment
|
||||||
|
curaengine = self.dependencies["curaengine"].cpp_info
|
||||||
|
copy(self, "CuraEngine.exe", curaengine.bindirs[0], self.source_folder, keep_path = False)
|
||||||
|
copy(self, "CuraEngine", curaengine.bindirs[0], self.source_folder, keep_path = False)
|
||||||
|
|
||||||
|
# Copy resources of cura_binary_data
|
||||||
|
cura_binary_data = self.dependencies["cura_binary_data"].cpp_info
|
||||||
|
copy(self, "*", cura_binary_data.resdirs[0], str(self._share_dir.joinpath("cura")), keep_path = True)
|
||||||
|
copy(self, "*", cura_binary_data.resdirs[1], str(self._share_dir.joinpath("uranium")), keep_path = True)
|
||||||
|
if self.settings.os == "Windows":
|
||||||
|
copy(self, "*", cura_binary_data.resdirs[2], str(self._share_dir.joinpath("windows")), keep_path = True)
|
||||||
|
|
||||||
|
for dependency in self.dependencies.host.values():
|
||||||
|
for bindir in dependency.cpp_info.bindirs:
|
||||||
|
copy(self, "*.dll", bindir, str(self._site_packages), keep_path = False)
|
||||||
|
for libdir in dependency.cpp_info.libdirs:
|
||||||
|
copy(self, "*.pyd", libdir, str(self._site_packages), keep_path = False)
|
||||||
|
copy(self, "*.pyi", libdir, str(self._site_packages), keep_path = False)
|
||||||
|
copy(self, "*.dylib", libdir, str(self._base_dir.joinpath("lib")), keep_path = False)
|
||||||
|
|
||||||
|
# Copy materials (flat)
|
||||||
|
rmdir(self, os.path.join(self.source_folder, "resources", "materials"))
|
||||||
|
fdm_materials = self.dependencies["fdm_materials"].cpp_info
|
||||||
|
copy(self, "*", fdm_materials.resdirs[0], self.source_folder)
|
||||||
|
|
||||||
|
# Copy internal resources
|
||||||
|
if self.options.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:
|
if self.options.devtools:
|
||||||
entitlements_file = "'{}'".format(os.path.join(self.source_folder, "packaging", "MacOS", "cura.entitlements"))
|
entitlements_file = "'{}'".format(os.path.join(self.source_folder, "packaging", "MacOS", "cura.entitlements"))
|
||||||
|
@ -357,8 +390,6 @@ class CuraConan(ConanFile):
|
||||||
pot = self.python_requires["translationextractor"].module.ExtractTranslations(self, cpp_info.bindirs[0])
|
pot = self.python_requires["translationextractor"].module.ExtractTranslations(self, cpp_info.bindirs[0])
|
||||||
pot.generate()
|
pot.generate()
|
||||||
|
|
||||||
self._generate_about_versions(os.path.join(self.source_folder, "resources","qml", "Dialogs"))
|
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
if self.options.devtools:
|
if self.options.devtools:
|
||||||
if self.settings.os != "Windows" or self.conf.get("tools.microsoft.bash:path", check_type = str):
|
if self.settings.os != "Windows" or self.conf.get("tools.microsoft.bash:path", check_type = str):
|
||||||
|
@ -370,29 +401,6 @@ class CuraConan(ConanFile):
|
||||||
cpp_info = self.dependencies["gettext"].cpp_info
|
cpp_info = self.dependencies["gettext"].cpp_info
|
||||||
self.run(f"{cpp_info.bindirs[0]}/msgfmt {po_file} -o {mo_file} -f", env="conanbuild", ignore_errors=True)
|
self.run(f"{cpp_info.bindirs[0]}/msgfmt {po_file} -o {mo_file} -f", env="conanbuild", ignore_errors=True)
|
||||||
|
|
||||||
def imports(self):
|
|
||||||
self.copy("CuraEngine.exe", root_package = "curaengine", src = "@bindirs", dst = "", keep_path = False)
|
|
||||||
self.copy("CuraEngine", root_package = "curaengine", src = "@bindirs", dst = "", keep_path = False)
|
|
||||||
|
|
||||||
rmdir(self, os.path.join(self.source_folder, "resources", "materials"))
|
|
||||||
self.copy("*.fdm_material", root_package = "fdm_materials", src = "@resdirs", dst = "resources/materials", keep_path = False)
|
|
||||||
self.copy("*.sig", root_package = "fdm_materials", src = "@resdirs", dst = "resources/materials", keep_path = False)
|
|
||||||
|
|
||||||
if self.options.internal:
|
|
||||||
self.copy("*", root_package = "cura_private_data", src = self.deps_cpp_info["cura_private_data"].resdirs[0],
|
|
||||||
dst = self._share_dir.joinpath("cura", "resources"), keep_path = True)
|
|
||||||
|
|
||||||
# Copy resources of cura_binary_data
|
|
||||||
self.copy("*", root_package = "cura_binary_data", src = self.deps_cpp_info["cura_binary_data"].resdirs[0],
|
|
||||||
dst = self._share_dir.joinpath("cura", "resources"), keep_path = True)
|
|
||||||
self.copy("*", root_package = "cura_binary_data", src = self.deps_cpp_info["cura_binary_data"].resdirs[1],
|
|
||||||
dst =self._share_dir.joinpath("uranium", "resources"), keep_path = True)
|
|
||||||
|
|
||||||
self.copy("*.dll", src = "@bindirs", dst = self._site_packages)
|
|
||||||
self.copy("*.pyd", src = "@libdirs", dst = self._site_packages)
|
|
||||||
self.copy("*.pyi", src = "@libdirs", dst = self._site_packages)
|
|
||||||
self.copy("*.dylib", src = "@libdirs", dst = self._script_dir)
|
|
||||||
|
|
||||||
def deploy(self):
|
def deploy(self):
|
||||||
# Copy CuraEngine.exe to bindirs of Virtual Python Environment
|
# Copy CuraEngine.exe to bindirs of Virtual Python Environment
|
||||||
curaengine = self.dependencies["curaengine"].cpp_info
|
curaengine = self.dependencies["curaengine"].cpp_info
|
||||||
|
|
|
@ -8,17 +8,20 @@ from UM.Logger import Logger
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
from cura.Arranging.Nest2DArrange import arrange
|
from cura.Arranging.GridArrange import GridArrange
|
||||||
|
from cura.Arranging.Nest2DArrange import Nest2DArrange
|
||||||
|
|
||||||
i18n_catalog = i18nCatalog("cura")
|
i18n_catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
|
||||||
class ArrangeObjectsJob(Job):
|
class ArrangeObjectsJob(Job):
|
||||||
def __init__(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], min_offset = 8) -> None:
|
def __init__(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], min_offset = 8,
|
||||||
|
*, grid_arrange: bool = False) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._nodes = nodes
|
self._nodes = nodes
|
||||||
self._fixed_nodes = fixed_nodes
|
self._fixed_nodes = fixed_nodes
|
||||||
self._min_offset = min_offset
|
self._min_offset = min_offset
|
||||||
|
self._grid_arrange = grid_arrange
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
found_solution_for_all = False
|
found_solution_for_all = False
|
||||||
|
@ -29,10 +32,18 @@ class ArrangeObjectsJob(Job):
|
||||||
title = i18n_catalog.i18nc("@info:title", "Finding Location"))
|
title = i18n_catalog.i18nc("@info:title", "Finding Location"))
|
||||||
status_message.show()
|
status_message.show()
|
||||||
|
|
||||||
|
if self._grid_arrange:
|
||||||
|
arranger = GridArrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes)
|
||||||
|
else:
|
||||||
|
arranger = Nest2DArrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes,
|
||||||
|
factor=1000)
|
||||||
|
|
||||||
|
found_solution_for_all = False
|
||||||
try:
|
try:
|
||||||
found_solution_for_all = arrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes)
|
found_solution_for_all = arranger.arrange()
|
||||||
except: # If the thread crashes, the message should still close
|
except: # If the thread crashes, the message should still close
|
||||||
Logger.logException("e", "Unable to arrange the objects on the buildplate. The arrange algorithm has crashed.")
|
Logger.logException("e",
|
||||||
|
"Unable to arrange the objects on the buildplate. The arrange algorithm has crashed.")
|
||||||
|
|
||||||
status_message.hide()
|
status_message.hide()
|
||||||
|
|
||||||
|
|
28
cura/Arranging/Arranger.py
Normal file
28
cura/Arranging/Arranger.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
from typing import List, TYPE_CHECKING, Optional, Tuple, Set
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from UM.Operations.GroupedOperation import GroupedOperation
|
||||||
|
|
||||||
|
|
||||||
|
class Arranger:
|
||||||
|
def createGroupOperationForArrange(self, *, add_new_nodes_in_scene: bool = False) -> Tuple["GroupedOperation", int]:
|
||||||
|
"""
|
||||||
|
Find placement for a set of scene nodes, but don't actually move them just yet.
|
||||||
|
:param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations
|
||||||
|
:return: tuple (found_solution_for_all, node_items)
|
||||||
|
WHERE
|
||||||
|
found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects
|
||||||
|
node_items: A list of the nodes return by libnest2d, which contain the new positions on the buildplate
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def arrange(self, *, add_new_nodes_in_scene: bool = False) -> bool:
|
||||||
|
"""
|
||||||
|
Find placement for a set of scene nodes, and move them by using a single grouped operation.
|
||||||
|
:param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations
|
||||||
|
:return: found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects
|
||||||
|
"""
|
||||||
|
grouped_operation, not_fit_count = self.createGroupOperationForArrange(
|
||||||
|
add_new_nodes_in_scene=add_new_nodes_in_scene)
|
||||||
|
grouped_operation.push()
|
||||||
|
return not_fit_count == 0
|
331
cura/Arranging/GridArrange.py
Normal file
331
cura/Arranging/GridArrange.py
Normal file
|
@ -0,0 +1,331 @@
|
||||||
|
import math
|
||||||
|
from typing import List, TYPE_CHECKING, Tuple, Set
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from UM.Scene.SceneNode import SceneNode
|
||||||
|
from cura.BuildVolume import BuildVolume
|
||||||
|
|
||||||
|
from UM.Application import Application
|
||||||
|
from UM.Math.Vector import Vector
|
||||||
|
from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
|
||||||
|
from UM.Operations.GroupedOperation import GroupedOperation
|
||||||
|
from UM.Operations.TranslateOperation import TranslateOperation
|
||||||
|
from cura.Arranging.Arranger import Arranger
|
||||||
|
|
||||||
|
|
||||||
|
class GridArrange(Arranger):
|
||||||
|
def __init__(self, nodes_to_arrange: List["SceneNode"], build_volume: "BuildVolume", fixed_nodes: List["SceneNode"] = None):
|
||||||
|
if fixed_nodes is None:
|
||||||
|
fixed_nodes = []
|
||||||
|
self._nodes_to_arrange = nodes_to_arrange
|
||||||
|
self._build_volume = build_volume
|
||||||
|
self._build_volume_bounding_box = build_volume.getBoundingBox()
|
||||||
|
self._fixed_nodes = fixed_nodes
|
||||||
|
|
||||||
|
self._margin_x: float = 1
|
||||||
|
self._margin_y: float = 1
|
||||||
|
|
||||||
|
self._grid_width = 0
|
||||||
|
self._grid_height = 0
|
||||||
|
for node in self._nodes_to_arrange:
|
||||||
|
bounding_box = node.getBoundingBox()
|
||||||
|
self._grid_width = max(self._grid_width, bounding_box.width)
|
||||||
|
self._grid_height = max(self._grid_height, bounding_box.depth)
|
||||||
|
self._grid_width += self._margin_x
|
||||||
|
self._grid_height += self._margin_y
|
||||||
|
|
||||||
|
# Round up the grid size to the nearest cm
|
||||||
|
grid_precision = 10 # 1cm
|
||||||
|
self._grid_width = math.ceil(self._grid_width / grid_precision) * grid_precision
|
||||||
|
self._grid_height = math.ceil(self._grid_height / grid_precision) * grid_precision
|
||||||
|
|
||||||
|
self._offset_x = 0
|
||||||
|
self._offset_y = 0
|
||||||
|
self._findOptimalGridOffset()
|
||||||
|
|
||||||
|
coord_initial_leftover_x = self._build_volume_bounding_box.right + 2 * self._grid_width
|
||||||
|
coord_initial_leftover_y = (self._build_volume_bounding_box.back + self._build_volume_bounding_box.front) * 0.5
|
||||||
|
self._initial_leftover_grid_x, self._initial_leftover_grid_y = self._coordSpaceToGridSpace(
|
||||||
|
coord_initial_leftover_x, coord_initial_leftover_y)
|
||||||
|
self._initial_leftover_grid_x = math.floor(self._initial_leftover_grid_x)
|
||||||
|
self._initial_leftover_grid_y = math.floor(self._initial_leftover_grid_y)
|
||||||
|
|
||||||
|
# Find grid indexes that intersect with fixed objects
|
||||||
|
self._fixed_nodes_grid_ids = set()
|
||||||
|
for node in self._fixed_nodes:
|
||||||
|
self._fixed_nodes_grid_ids = self._fixed_nodes_grid_ids.union(
|
||||||
|
self._intersectingGridIdxInclusive(node.getBoundingBox()))
|
||||||
|
|
||||||
|
#grid indexes that are in disallowed area
|
||||||
|
for polygon in self._build_volume.getDisallowedAreas():
|
||||||
|
self._fixed_nodes_grid_ids = self._fixed_nodes_grid_ids.union(
|
||||||
|
self._getIntersectingGridIdForPolygon(polygon))
|
||||||
|
|
||||||
|
self._build_plate_grid_ids = self._intersectingGridIdxExclusive(self._build_volume_bounding_box)
|
||||||
|
|
||||||
|
# Filter out the corner grid squares if the build plate shape is elliptic
|
||||||
|
if self._build_volume.getShape() == "elliptic":
|
||||||
|
self._build_plate_grid_ids = set(
|
||||||
|
filter(lambda grid_id: self._checkGridUnderDiscSpace(grid_id[0], grid_id[1]),
|
||||||
|
self._build_plate_grid_ids))
|
||||||
|
|
||||||
|
self._allowed_grid_idx = self._build_plate_grid_ids.difference(self._fixed_nodes_grid_ids)
|
||||||
|
|
||||||
|
def createGroupOperationForArrange(self, *, add_new_nodes_in_scene: bool = False) -> Tuple[GroupedOperation, int]:
|
||||||
|
# Find the sequence in which items are placed
|
||||||
|
coord_build_plate_center_x = self._build_volume_bounding_box.width * 0.5 + self._build_volume_bounding_box.left
|
||||||
|
coord_build_plate_center_y = self._build_volume_bounding_box.depth * 0.5 + self._build_volume_bounding_box.back
|
||||||
|
grid_build_plate_center_x, grid_build_plate_center_y = self._coordSpaceToGridSpace(coord_build_plate_center_x,
|
||||||
|
coord_build_plate_center_y)
|
||||||
|
|
||||||
|
sequence: List[Tuple[int, int]] = list(self._allowed_grid_idx)
|
||||||
|
sequence.sort(key=lambda grid_id: (grid_build_plate_center_x - grid_id[0]) ** 2 + (
|
||||||
|
grid_build_plate_center_y - grid_id[1]) ** 2)
|
||||||
|
scene_root = Application.getInstance().getController().getScene().getRoot()
|
||||||
|
grouped_operation = GroupedOperation()
|
||||||
|
|
||||||
|
for grid_id, node in zip(sequence, self._nodes_to_arrange):
|
||||||
|
if add_new_nodes_in_scene:
|
||||||
|
grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root))
|
||||||
|
grid_x, grid_y = grid_id
|
||||||
|
operation = self._moveNodeOnGrid(node, grid_x, grid_y)
|
||||||
|
grouped_operation.addOperation(operation)
|
||||||
|
|
||||||
|
leftover_nodes = self._nodes_to_arrange[len(sequence):]
|
||||||
|
|
||||||
|
left_over_grid_y = self._initial_leftover_grid_y
|
||||||
|
for node in leftover_nodes:
|
||||||
|
if add_new_nodes_in_scene:
|
||||||
|
grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root))
|
||||||
|
# find the first next grid position that isn't occupied by a fixed node
|
||||||
|
while (self._initial_leftover_grid_x, left_over_grid_y) in self._fixed_nodes_grid_ids:
|
||||||
|
left_over_grid_y = left_over_grid_y - 1
|
||||||
|
|
||||||
|
operation = self._moveNodeOnGrid(node, self._initial_leftover_grid_x, left_over_grid_y)
|
||||||
|
grouped_operation.addOperation(operation)
|
||||||
|
left_over_grid_y = left_over_grid_y - 1
|
||||||
|
|
||||||
|
return grouped_operation, len(leftover_nodes)
|
||||||
|
|
||||||
|
def _findOptimalGridOffset(self):
|
||||||
|
if len(self._fixed_nodes) == 0:
|
||||||
|
self._offset_x = 0
|
||||||
|
self._offset_y = 0
|
||||||
|
return
|
||||||
|
|
||||||
|
if len(self._fixed_nodes) == 1:
|
||||||
|
center_grid_x = 0.5 * self._grid_width + self._build_volume_bounding_box.left
|
||||||
|
center_grid_y = 0.5 * self._grid_height + self._build_volume_bounding_box.back
|
||||||
|
|
||||||
|
bounding_box = self._fixed_nodes[0].getBoundingBox()
|
||||||
|
center_node_x = (bounding_box.left + bounding_box.right) * 0.5
|
||||||
|
center_node_y = (bounding_box.back + bounding_box.front) * 0.5
|
||||||
|
|
||||||
|
self._offset_x = center_node_x - center_grid_x
|
||||||
|
self._offset_y = center_node_y - center_grid_y
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
# If there are multiple fixed nodes, an optimal solution is not always possible
|
||||||
|
# We will try to find an offset that minimizes the number of grid intersections
|
||||||
|
# with fixed nodes. The algorithm below achieves this by utilizing a scanline
|
||||||
|
# algorithm. In this algorithm each axis is solved separately as offsetting
|
||||||
|
# is completely independent in each axis. The comments explaining the algorithm
|
||||||
|
# below are for the x-axis, but the same applies for the y-axis.
|
||||||
|
#
|
||||||
|
# Each node either occupies ceil((node.right - node.right) / grid_width) or
|
||||||
|
# ceil((node.right - node.right) / grid_width) + 1 grid squares. We will call
|
||||||
|
# these the node's "footprint".
|
||||||
|
#
|
||||||
|
# ┌────────────────┐
|
||||||
|
# minimum foot-print │ NODE │
|
||||||
|
# └────────────────┘
|
||||||
|
# │ grid 1 │ grid 2 │ grid 3 │ grid 4 | grid 5 |
|
||||||
|
# ┌────────────────┐
|
||||||
|
# maximum foot-print │ NODE │
|
||||||
|
# └────────────────┘
|
||||||
|
#
|
||||||
|
# The algorithm will find the grid offset such that the number of nodes with
|
||||||
|
# a _minimal_ footprint is _maximized_.
|
||||||
|
|
||||||
|
# The scanline algorithm works as follows, we create events for both end points
|
||||||
|
# of each node's footprint. The event have two properties,
|
||||||
|
# - the coordinate: the amount the endpoint can move to the
|
||||||
|
# left before it crosses a grid line
|
||||||
|
# - the change: either +1 or -1, indicating whether crossing the grid line
|
||||||
|
# would result in a minimal footprint node becoming a maximal footprint
|
||||||
|
class Event:
|
||||||
|
def __init__(self, coord: float, change: float):
|
||||||
|
self.coord = coord
|
||||||
|
self.change = change
|
||||||
|
|
||||||
|
# create events for both the horizontal and vertical axis
|
||||||
|
events_horizontal: List[Event] = []
|
||||||
|
events_vertical: List[Event] = []
|
||||||
|
|
||||||
|
for node in self._fixed_nodes:
|
||||||
|
bounding_box = node.getBoundingBox()
|
||||||
|
|
||||||
|
left = bounding_box.left - self._build_volume_bounding_box.left
|
||||||
|
right = bounding_box.right - self._build_volume_bounding_box.left
|
||||||
|
back = bounding_box.back - self._build_volume_bounding_box.back
|
||||||
|
front = bounding_box.front - self._build_volume_bounding_box.back
|
||||||
|
|
||||||
|
value_left = math.ceil(left / self._grid_width) * self._grid_width - left
|
||||||
|
value_right = math.ceil(right / self._grid_width) * self._grid_width - right
|
||||||
|
value_back = math.ceil(back / self._grid_height) * self._grid_height - back
|
||||||
|
value_front = math.ceil(front / self._grid_height) * self._grid_height - front
|
||||||
|
|
||||||
|
# give nodes a weight according to their size. This
|
||||||
|
# weight is heuristically chosen to be proportional to
|
||||||
|
# the number of grid squares the node-boundary occupies
|
||||||
|
weight = bounding_box.width + bounding_box.depth
|
||||||
|
|
||||||
|
events_horizontal.append(Event(value_left, weight))
|
||||||
|
events_horizontal.append(Event(value_right, -weight))
|
||||||
|
events_vertical.append(Event(value_back, weight))
|
||||||
|
events_vertical.append(Event(value_front, -weight))
|
||||||
|
|
||||||
|
events_horizontal.sort(key=lambda event: event.coord)
|
||||||
|
events_vertical.sort(key=lambda event: event.coord)
|
||||||
|
|
||||||
|
def findOptimalShiftAxis(events: List[Event], interval: float) -> float:
|
||||||
|
# executing the actual scanline algorithm
|
||||||
|
# iteratively go through events (left to right) and keep track of the
|
||||||
|
# current footprint. The optimal location is the one with the minimal
|
||||||
|
# footprint. If there are multiple locations with the same minimal
|
||||||
|
# footprint, the optimal location is the one with the largest range
|
||||||
|
# between the left and right endpoint of the footprint.
|
||||||
|
prev_offset = events[-1].coord - interval
|
||||||
|
current_minimal_footprint_count = 0
|
||||||
|
|
||||||
|
best_minimal_footprint_count = float('inf')
|
||||||
|
best_offset_span = float('-inf')
|
||||||
|
best_offset = 0.0
|
||||||
|
|
||||||
|
for event in events:
|
||||||
|
offset_span = event.coord - prev_offset
|
||||||
|
|
||||||
|
if current_minimal_footprint_count < best_minimal_footprint_count or (
|
||||||
|
current_minimal_footprint_count == best_minimal_footprint_count and offset_span > best_offset_span):
|
||||||
|
best_minimal_footprint_count = current_minimal_footprint_count
|
||||||
|
best_offset_span = offset_span
|
||||||
|
best_offset = event.coord
|
||||||
|
|
||||||
|
current_minimal_footprint_count += event.change
|
||||||
|
prev_offset = event.coord
|
||||||
|
|
||||||
|
return best_offset - best_offset_span * 0.5
|
||||||
|
|
||||||
|
center_grid_x = 0.5 * self._grid_width
|
||||||
|
center_grid_y = 0.5 * self._grid_height
|
||||||
|
|
||||||
|
optimal_center_x = self._grid_width - findOptimalShiftAxis(events_horizontal, self._grid_width)
|
||||||
|
optimal_center_y = self._grid_height - findOptimalShiftAxis(events_vertical, self._grid_height)
|
||||||
|
|
||||||
|
self._offset_x = optimal_center_x - center_grid_x
|
||||||
|
self._offset_y = optimal_center_y - center_grid_y
|
||||||
|
|
||||||
|
def _moveNodeOnGrid(self, node: "SceneNode", grid_x: int, grid_y: int) -> "Operation.Operation":
|
||||||
|
coord_grid_x, coord_grid_y = self._gridSpaceToCoordSpace(grid_x, grid_y)
|
||||||
|
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))
|
||||||
|
|
||||||
|
def _getGridCornerPoints(self, bounding_box: "BoundingVolume") -> Tuple[float, float, float, float]:
|
||||||
|
coord_x1 = bounding_box.left
|
||||||
|
coord_x2 = bounding_box.right
|
||||||
|
coord_y1 = bounding_box.back
|
||||||
|
coord_y2 = bounding_box.front
|
||||||
|
grid_x1, grid_y1 = self._coordSpaceToGridSpace(coord_x1, coord_y1)
|
||||||
|
grid_x2, grid_y2 = self._coordSpaceToGridSpace(coord_x2, coord_y2)
|
||||||
|
return grid_x1, grid_y1, grid_x2, grid_y2
|
||||||
|
|
||||||
|
def _getIntersectingGridIdForPolygon(self, polygon)-> Set[Tuple[int, int]]:
|
||||||
|
# (x0, y0)
|
||||||
|
# |
|
||||||
|
# v
|
||||||
|
# ┌─────────────┐
|
||||||
|
# │ │
|
||||||
|
# │ │
|
||||||
|
# └─────────────┘ < (x1, y1)
|
||||||
|
x0 = float('inf')
|
||||||
|
y0 = float('inf')
|
||||||
|
x1 = float('-inf')
|
||||||
|
y1 = float('-inf')
|
||||||
|
grid_idx = set()
|
||||||
|
for [x, y] in polygon.getPoints():
|
||||||
|
x0 = min(x0, x)
|
||||||
|
y0 = min(y0, y)
|
||||||
|
x1 = max(x1, x)
|
||||||
|
y1 = max(y1, y)
|
||||||
|
grid_x1, grid_y1 = self._coordSpaceToGridSpace(x0, y0)
|
||||||
|
grid_x2, grid_y2 = self._coordSpaceToGridSpace(x1, y1)
|
||||||
|
|
||||||
|
for grid_x in range(math.floor(grid_x1), math.ceil(grid_x2)):
|
||||||
|
for grid_y in range(math.floor(grid_y1), math.ceil(grid_y2)):
|
||||||
|
grid_idx.add((grid_x, grid_y))
|
||||||
|
return grid_idx
|
||||||
|
|
||||||
|
def _intersectingGridIdxInclusive(self, bounding_box: "BoundingVolume") -> Set[Tuple[int, int]]:
|
||||||
|
grid_x1, grid_y1, grid_x2, grid_y2 = self._getGridCornerPoints(bounding_box)
|
||||||
|
grid_idx = set()
|
||||||
|
for grid_x in range(math.floor(grid_x1), math.ceil(grid_x2)):
|
||||||
|
for grid_y in range(math.floor(grid_y1), math.ceil(grid_y2)):
|
||||||
|
grid_idx.add((grid_x, grid_y))
|
||||||
|
return grid_idx
|
||||||
|
|
||||||
|
def _intersectingGridIdxExclusive(self, bounding_box: "BoundingVolume") -> Set[Tuple[int, int]]:
|
||||||
|
grid_x1, grid_y1, grid_x2, grid_y2 = self._getGridCornerPoints(bounding_box)
|
||||||
|
grid_idx = set()
|
||||||
|
for grid_x in range(math.ceil(grid_x1), math.floor(grid_x2)):
|
||||||
|
for grid_y in range(math.ceil(grid_y1), math.floor(grid_y2)):
|
||||||
|
grid_idx.add((grid_x, grid_y))
|
||||||
|
return grid_idx
|
||||||
|
|
||||||
|
def _gridSpaceToCoordSpace(self, x: float, y: float) -> Tuple[float, float]:
|
||||||
|
grid_x = x * self._grid_width + self._build_volume_bounding_box.left + self._offset_x
|
||||||
|
grid_y = y * self._grid_height + self._build_volume_bounding_box.back + self._offset_y
|
||||||
|
return grid_x, grid_y
|
||||||
|
|
||||||
|
def _coordSpaceToGridSpace(self, grid_x: float, grid_y: float) -> Tuple[float, float]:
|
||||||
|
coord_x = (grid_x - self._build_volume_bounding_box.left - self._offset_x) / self._grid_width
|
||||||
|
coord_y = (grid_y - self._build_volume_bounding_box.back - self._offset_y) / self._grid_height
|
||||||
|
return coord_x, coord_y
|
||||||
|
|
||||||
|
def _checkGridUnderDiscSpace(self, grid_x: int, grid_y: int) -> bool:
|
||||||
|
left, back = self._gridSpaceToCoordSpace(grid_x, grid_y)
|
||||||
|
right, front = self._gridSpaceToCoordSpace(grid_x + 1, grid_y + 1)
|
||||||
|
corners = [(left, back), (right, back), (right, front), (left, front)]
|
||||||
|
return all([self._checkPointUnderDiscSpace(x, y) for x, y in corners])
|
||||||
|
|
||||||
|
def _checkPointUnderDiscSpace(self, x: float, y: float) -> bool:
|
||||||
|
disc_x, disc_y = self._coordSpaceToDiscSpace(x, y)
|
||||||
|
distance_to_center_squared = disc_x ** 2 + disc_y ** 2
|
||||||
|
return distance_to_center_squared <= 1.0
|
||||||
|
|
||||||
|
def _coordSpaceToDiscSpace(self, x: float, y: float) -> Tuple[float, float]:
|
||||||
|
# Transform coordinate system to
|
||||||
|
#
|
||||||
|
# coord_build_plate_left = -1
|
||||||
|
# | coord_build_plate_right = 1
|
||||||
|
# v (0,1) v
|
||||||
|
# ┌───────┬───────┐ < coord_build_plate_back = -1
|
||||||
|
# │ │ │
|
||||||
|
# │ │(0,0) │
|
||||||
|
# (-1,0)├───────o───────┤(1,0)
|
||||||
|
# │ │ │
|
||||||
|
# │ │ │
|
||||||
|
# └───────┴───────┘ < coord_build_plate_front = +1
|
||||||
|
# (0,-1)
|
||||||
|
disc_x = ((x - self._build_volume_bounding_box.left) / self._build_volume_bounding_box.width) * 2.0 - 1.0
|
||||||
|
disc_y = ((y - self._build_volume_bounding_box.back) / self._build_volume_bounding_box.depth) * 2.0 - 1.0
|
||||||
|
return disc_x, disc_y
|
|
@ -15,46 +15,56 @@ from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
|
||||||
from UM.Operations.GroupedOperation import GroupedOperation
|
from UM.Operations.GroupedOperation import GroupedOperation
|
||||||
from UM.Operations.RotateOperation import RotateOperation
|
from UM.Operations.RotateOperation import RotateOperation
|
||||||
from UM.Operations.TranslateOperation import TranslateOperation
|
from UM.Operations.TranslateOperation import TranslateOperation
|
||||||
|
from cura.Arranging.Arranger import Arranger
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from cura.BuildVolume import BuildVolume
|
from cura.BuildVolume import BuildVolume
|
||||||
|
|
||||||
|
|
||||||
def findNodePlacement(nodes_to_arrange: List["SceneNode"], build_volume: "BuildVolume", fixed_nodes: Optional[List["SceneNode"]] = None, factor = 10000) -> Tuple[bool, List[Item]]:
|
class Nest2DArrange(Arranger):
|
||||||
|
def __init__(self,
|
||||||
|
nodes_to_arrange: List["SceneNode"],
|
||||||
|
build_volume: "BuildVolume",
|
||||||
|
fixed_nodes: Optional[List["SceneNode"]] = None,
|
||||||
|
*,
|
||||||
|
factor: int = 10000,
|
||||||
|
lock_rotation: bool = False):
|
||||||
"""
|
"""
|
||||||
Find placement for a set of scene nodes, but don't actually move them just yet.
|
|
||||||
:param nodes_to_arrange: The list of nodes that need to be moved.
|
:param nodes_to_arrange: The list of nodes that need to be moved.
|
||||||
:param build_volume: The build volume that we want to place the nodes in. It gets size & disallowed areas from this.
|
:param build_volume: The build volume that we want to place the nodes in. It gets size & disallowed areas from this.
|
||||||
:param fixed_nodes: List of nods that should not be moved, but should be used when deciding where the others nodes
|
:param fixed_nodes: List of nods that should not be moved, but should be used when deciding where the others nodes
|
||||||
are placed.
|
are placed.
|
||||||
:param factor: The library that we use is int based. This factor defines how accurate we want it to be.
|
:param factor: The library that we use is int based. This factor defines how accuracte we want it to be.
|
||||||
|
:param lock_rotation: If set to true the orientation of the object will remain the same
|
||||||
:return: tuple (found_solution_for_all, node_items)
|
|
||||||
WHERE
|
|
||||||
found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects
|
|
||||||
node_items: A list of the nodes return by libnest2d, which contain the new positions on the buildplate
|
|
||||||
"""
|
"""
|
||||||
spacing = int(1.5 * factor) # 1.5mm spacing.
|
super().__init__()
|
||||||
|
self._nodes_to_arrange = nodes_to_arrange
|
||||||
|
self._build_volume = build_volume
|
||||||
|
self._fixed_nodes = fixed_nodes
|
||||||
|
self._factor = factor
|
||||||
|
self._lock_rotation = lock_rotation
|
||||||
|
|
||||||
machine_width = build_volume.getWidth()
|
def findNodePlacement(self) -> Tuple[bool, List[Item]]:
|
||||||
machine_depth = build_volume.getDepth()
|
spacing = int(1.5 * self._factor) # 1.5mm spacing.
|
||||||
build_plate_bounding_box = Box(int(machine_width * factor), int(machine_depth * factor))
|
|
||||||
|
|
||||||
if fixed_nodes is None:
|
machine_width = self._build_volume.getWidth()
|
||||||
fixed_nodes = []
|
machine_depth = self._build_volume.getDepth()
|
||||||
|
build_plate_bounding_box = Box(int(machine_width * self._factor), int(machine_depth * self._factor))
|
||||||
|
|
||||||
|
if self._fixed_nodes is None:
|
||||||
|
self._fixed_nodes = []
|
||||||
|
|
||||||
# Add all the items we want to arrange
|
# Add all the items we want to arrange
|
||||||
node_items = []
|
node_items = []
|
||||||
for node in nodes_to_arrange:
|
for node in self._nodes_to_arrange:
|
||||||
hull_polygon = node.callDecoration("getConvexHull")
|
hull_polygon = node.callDecoration("getConvexHull")
|
||||||
if not hull_polygon or hull_polygon.getPoints is None:
|
if not hull_polygon or hull_polygon.getPoints is None:
|
||||||
Logger.log("w", "Object {} cannot be arranged because it has no convex hull.".format(node.getName()))
|
Logger.log("w", "Object {} cannot be arranged because it has no convex hull.".format(node.getName()))
|
||||||
continue
|
continue
|
||||||
converted_points = []
|
converted_points = []
|
||||||
for point in hull_polygon.getPoints():
|
for point in hull_polygon.getPoints():
|
||||||
converted_points.append(Point(int(point[0] * factor), int(point[1] * factor)))
|
converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor)))
|
||||||
item = Item(converted_points)
|
item = Item(converted_points)
|
||||||
node_items.append(item)
|
node_items.append(item)
|
||||||
|
|
||||||
|
@ -68,7 +78,7 @@ def findNodePlacement(nodes_to_arrange: List["SceneNode"], build_volume: "BuildV
|
||||||
[half_machine_width, half_machine_depth]
|
[half_machine_width, half_machine_depth]
|
||||||
], numpy.float32))
|
], numpy.float32))
|
||||||
|
|
||||||
disallowed_areas = build_volume.getDisallowedAreas()
|
disallowed_areas = self._build_volume.getDisallowedAreas()
|
||||||
num_disallowed_areas_added = 0
|
num_disallowed_areas_added = 0
|
||||||
for area in disallowed_areas:
|
for area in disallowed_areas:
|
||||||
converted_points = []
|
converted_points = []
|
||||||
|
@ -76,22 +86,24 @@ def findNodePlacement(nodes_to_arrange: List["SceneNode"], build_volume: "BuildV
|
||||||
# Clip the disallowed areas so that they don't overlap the bounding box (The arranger chokes otherwise)
|
# Clip the disallowed areas so that they don't overlap the bounding box (The arranger chokes otherwise)
|
||||||
clipped_area = area.intersectionConvexHulls(build_plate_polygon)
|
clipped_area = area.intersectionConvexHulls(build_plate_polygon)
|
||||||
|
|
||||||
if clipped_area.getPoints() is not None and len(clipped_area.getPoints()) > 2: # numpy array has to be explicitly checked against None
|
if clipped_area.getPoints() is not None and len(
|
||||||
|
clipped_area.getPoints()) > 2: # numpy array has to be explicitly checked against None
|
||||||
for point in clipped_area.getPoints():
|
for point in clipped_area.getPoints():
|
||||||
converted_points.append(Point(int(point[0] * factor), int(point[1] * factor)))
|
converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor)))
|
||||||
|
|
||||||
disallowed_area = Item(converted_points)
|
disallowed_area = Item(converted_points)
|
||||||
disallowed_area.markAsDisallowedAreaInBin(0)
|
disallowed_area.markAsDisallowedAreaInBin(0)
|
||||||
node_items.append(disallowed_area)
|
node_items.append(disallowed_area)
|
||||||
num_disallowed_areas_added += 1
|
num_disallowed_areas_added += 1
|
||||||
|
|
||||||
for node in fixed_nodes:
|
for node in self._fixed_nodes:
|
||||||
converted_points = []
|
converted_points = []
|
||||||
hull_polygon = node.callDecoration("getConvexHull")
|
hull_polygon = node.callDecoration("getConvexHull")
|
||||||
|
|
||||||
if hull_polygon is not None and hull_polygon.getPoints() is not None and len(hull_polygon.getPoints()) > 2: # numpy array has to be explicitly checked against None
|
if hull_polygon is not None and hull_polygon.getPoints() is not None and len(
|
||||||
|
hull_polygon.getPoints()) > 2: # numpy array has to be explicitly checked against None
|
||||||
for point in hull_polygon.getPoints():
|
for point in hull_polygon.getPoints():
|
||||||
converted_points.append(Point(int(point[0] * factor), int(point[1] * factor)))
|
converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor)))
|
||||||
item = Item(converted_points)
|
item = Item(converted_points)
|
||||||
item.markAsFixedInBin(0)
|
item.markAsFixedInBin(0)
|
||||||
node_items.append(item)
|
node_items.append(item)
|
||||||
|
@ -100,6 +112,8 @@ def findNodePlacement(nodes_to_arrange: List["SceneNode"], build_volume: "BuildV
|
||||||
config = NfpConfig()
|
config = NfpConfig()
|
||||||
config.accuracy = 1.0
|
config.accuracy = 1.0
|
||||||
config.alignment = NfpConfig.Alignment.DONT_ALIGN
|
config.alignment = NfpConfig.Alignment.DONT_ALIGN
|
||||||
|
if self._lock_rotation:
|
||||||
|
config.rotations = [0.0]
|
||||||
|
|
||||||
num_bins = nest(node_items, build_plate_bounding_box, spacing, config)
|
num_bins = nest(node_items, build_plate_bounding_box, spacing, config)
|
||||||
|
|
||||||
|
@ -110,18 +124,13 @@ def findNodePlacement(nodes_to_arrange: List["SceneNode"], build_volume: "BuildV
|
||||||
|
|
||||||
return found_solution_for_all, node_items
|
return found_solution_for_all, node_items
|
||||||
|
|
||||||
|
def createGroupOperationForArrange(self, *, add_new_nodes_in_scene: bool = False) -> Tuple[GroupedOperation, int]:
|
||||||
def createGroupOperationForArrange(nodes_to_arrange: List["SceneNode"],
|
|
||||||
build_volume: "BuildVolume",
|
|
||||||
fixed_nodes: Optional[List["SceneNode"]] = None,
|
|
||||||
factor = 10000,
|
|
||||||
add_new_nodes_in_scene: bool = False) -> Tuple[GroupedOperation, int]:
|
|
||||||
scene_root = Application.getInstance().getController().getScene().getRoot()
|
scene_root = Application.getInstance().getController().getScene().getRoot()
|
||||||
found_solution_for_all, node_items = findNodePlacement(nodes_to_arrange, build_volume, fixed_nodes, factor)
|
found_solution_for_all, node_items = self.findNodePlacement()
|
||||||
|
|
||||||
not_fit_count = 0
|
not_fit_count = 0
|
||||||
grouped_operation = GroupedOperation()
|
grouped_operation = GroupedOperation()
|
||||||
for node, node_item in zip(nodes_to_arrange, node_items):
|
for node, node_item in zip(self._nodes_to_arrange, node_items):
|
||||||
if add_new_nodes_in_scene:
|
if add_new_nodes_in_scene:
|
||||||
grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root))
|
grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root))
|
||||||
|
|
||||||
|
@ -130,8 +139,9 @@ def createGroupOperationForArrange(nodes_to_arrange: List["SceneNode"],
|
||||||
rotation_matrix = Matrix()
|
rotation_matrix = Matrix()
|
||||||
rotation_matrix.setByRotationAxis(node_item.rotation(), Vector(0, -1, 0))
|
rotation_matrix.setByRotationAxis(node_item.rotation(), Vector(0, -1, 0))
|
||||||
grouped_operation.addOperation(RotateOperation(node, Quaternion.fromMatrix(rotation_matrix)))
|
grouped_operation.addOperation(RotateOperation(node, Quaternion.fromMatrix(rotation_matrix)))
|
||||||
grouped_operation.addOperation(TranslateOperation(node, Vector(node_item.translation().x() / factor, 0,
|
grouped_operation.addOperation(
|
||||||
node_item.translation().y() / factor)))
|
TranslateOperation(node, Vector(node_item.translation().x() / self._factor, 0,
|
||||||
|
node_item.translation().y() / self._factor)))
|
||||||
else:
|
else:
|
||||||
# We didn't find a spot
|
# We didn't find a spot
|
||||||
grouped_operation.addOperation(
|
grouped_operation.addOperation(
|
||||||
|
@ -139,25 +149,3 @@ def createGroupOperationForArrange(nodes_to_arrange: List["SceneNode"],
|
||||||
not_fit_count += 1
|
not_fit_count += 1
|
||||||
|
|
||||||
return grouped_operation, not_fit_count
|
return grouped_operation, not_fit_count
|
||||||
|
|
||||||
|
|
||||||
def arrange(nodes_to_arrange: List["SceneNode"],
|
|
||||||
build_volume: "BuildVolume",
|
|
||||||
fixed_nodes: Optional[List["SceneNode"]] = None,
|
|
||||||
factor = 10000,
|
|
||||||
add_new_nodes_in_scene: bool = False) -> bool:
|
|
||||||
"""
|
|
||||||
Find placement for a set of scene nodes, and move them by using a single grouped operation.
|
|
||||||
:param nodes_to_arrange: The list of nodes that need to be moved.
|
|
||||||
:param build_volume: The build volume that we want to place the nodes in. It gets size & disallowed areas from this.
|
|
||||||
:param fixed_nodes: List of nods that should not be moved, but should be used when deciding where the others nodes
|
|
||||||
are placed.
|
|
||||||
:param factor: The library that we use is int based. This factor defines how accuracte we want it to be.
|
|
||||||
:param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations
|
|
||||||
|
|
||||||
:return: found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects
|
|
||||||
"""
|
|
||||||
|
|
||||||
grouped_operation, not_fit_count = createGroupOperationForArrange(nodes_to_arrange, build_volume, fixed_nodes, factor, add_new_nodes_in_scene)
|
|
||||||
grouped_operation.push()
|
|
||||||
return not_fit_count == 0
|
|
||||||
|
|
|
@ -203,6 +203,9 @@ class BuildVolume(SceneNode):
|
||||||
if shape:
|
if shape:
|
||||||
self._shape = shape
|
self._shape = shape
|
||||||
|
|
||||||
|
def getShape(self) -> str:
|
||||||
|
return self._shape
|
||||||
|
|
||||||
def getDiagonalSize(self) -> float:
|
def getDiagonalSize(self) -> float:
|
||||||
"""Get the length of the 3D diagonal through the build volume.
|
"""Get the length of the 3D diagonal through the build volume.
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,10 @@ from cura.Operations.SetParentOperation import SetParentOperation
|
||||||
from cura.MultiplyObjectsJob import MultiplyObjectsJob
|
from cura.MultiplyObjectsJob import MultiplyObjectsJob
|
||||||
from cura.Settings.SetObjectExtruderOperation import SetObjectExtruderOperation
|
from cura.Settings.SetObjectExtruderOperation import SetObjectExtruderOperation
|
||||||
from cura.Settings.ExtruderManager import ExtruderManager
|
from cura.Settings.ExtruderManager import ExtruderManager
|
||||||
from cura.Arranging.Nest2DArrange import createGroupOperationForArrange
|
|
||||||
|
from cura.Arranging.GridArrange import GridArrange
|
||||||
|
from cura.Arranging.Nest2DArrange import Nest2DArrange
|
||||||
|
|
||||||
|
|
||||||
from cura.Operations.SetBuildPlateNumberOperation import SetBuildPlateNumberOperation
|
from cura.Operations.SetBuildPlateNumberOperation import SetBuildPlateNumberOperation
|
||||||
|
|
||||||
|
@ -82,16 +85,25 @@ class CuraActions(QObject):
|
||||||
center_operation = TranslateOperation(current_node, Vector(0, center_y, 0), set_position = True)
|
center_operation = TranslateOperation(current_node, Vector(0, center_y, 0), set_position = True)
|
||||||
operation.addOperation(center_operation)
|
operation.addOperation(center_operation)
|
||||||
operation.push()
|
operation.push()
|
||||||
|
|
||||||
@pyqtSlot(int)
|
@pyqtSlot(int)
|
||||||
def multiplySelection(self, count: int) -> None:
|
def multiplySelection(self, count: int) -> None:
|
||||||
"""Multiply all objects in the selection
|
"""Multiply all objects in the selection
|
||||||
|
:param count: The number of times to multiply the selection.
|
||||||
|
"""
|
||||||
|
min_offset = cura.CuraApplication.CuraApplication.getInstance().getBuildVolume().getEdgeDisallowedSize() + 2 # Allow for some rounding errors
|
||||||
|
job = MultiplyObjectsJob(Selection.getAllSelectedObjects(), count, min_offset = max(min_offset, 8))
|
||||||
|
job.start()
|
||||||
|
|
||||||
|
@pyqtSlot(int)
|
||||||
|
def multiplySelectionToGrid(self, count: int) -> None:
|
||||||
|
"""Multiply all objects in the selection
|
||||||
|
|
||||||
:param count: The number of times to multiply the selection.
|
:param count: The number of times to multiply the selection.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
min_offset = cura.CuraApplication.CuraApplication.getInstance().getBuildVolume().getEdgeDisallowedSize() + 2 # Allow for some rounding errors
|
min_offset = cura.CuraApplication.CuraApplication.getInstance().getBuildVolume().getEdgeDisallowedSize() + 2 # Allow for some rounding errors
|
||||||
job = MultiplyObjectsJob(Selection.getAllSelectedObjects(), count, min_offset = max(min_offset, 8))
|
job = MultiplyObjectsJob(Selection.getAllSelectedObjects(), count, min_offset=max(min_offset, 8),
|
||||||
|
grid_arrange=True)
|
||||||
job.start()
|
job.start()
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
|
@ -229,9 +241,9 @@ class CuraActions(QObject):
|
||||||
if node.callDecoration("isSliceable"):
|
if node.callDecoration("isSliceable"):
|
||||||
fixed_nodes.append(node)
|
fixed_nodes.append(node)
|
||||||
# Add the new nodes to the scene, and arrange them
|
# Add the new nodes to the scene, and arrange them
|
||||||
group_operation, not_fit_count = createGroupOperationForArrange(nodes, application.getBuildVolume(),
|
|
||||||
fixed_nodes, factor=10000,
|
arranger = GridArrange(nodes, application.getBuildVolume(), fixed_nodes)
|
||||||
add_new_nodes_in_scene=True)
|
group_operation, not_fit_count = arranger.createGroupOperationForArrange(add_new_nodes_in_scene = True)
|
||||||
group_operation.push()
|
group_operation.push()
|
||||||
|
|
||||||
# deselect currently selected nodes, and select the new nodes
|
# deselect currently selected nodes, and select the new nodes
|
||||||
|
|
|
@ -54,7 +54,6 @@ from cura import ApplicationMetadata
|
||||||
from cura.API import CuraAPI
|
from cura.API import CuraAPI
|
||||||
from cura.API.Account import Account
|
from cura.API.Account import Account
|
||||||
from cura.Arranging.ArrangeObjectsJob import ArrangeObjectsJob
|
from cura.Arranging.ArrangeObjectsJob import ArrangeObjectsJob
|
||||||
from cura.Arranging.Nest2DArrange import arrange
|
|
||||||
from cura.Machines.MachineErrorChecker import MachineErrorChecker
|
from cura.Machines.MachineErrorChecker import MachineErrorChecker
|
||||||
from cura.Machines.Models.BuildPlateModel import BuildPlateModel
|
from cura.Machines.Models.BuildPlateModel import BuildPlateModel
|
||||||
from cura.Machines.Models.CustomQualityProfilesDropDownMenuModel import CustomQualityProfilesDropDownMenuModel
|
from cura.Machines.Models.CustomQualityProfilesDropDownMenuModel import CustomQualityProfilesDropDownMenuModel
|
||||||
|
@ -115,6 +114,7 @@ from . import CameraAnimation
|
||||||
from . import CuraActions
|
from . import CuraActions
|
||||||
from . import PlatformPhysics
|
from . import PlatformPhysics
|
||||||
from . import PrintJobPreviewImageProvider
|
from . import PrintJobPreviewImageProvider
|
||||||
|
from .Arranging.Nest2DArrange import Nest2DArrange
|
||||||
from .AutoSave import AutoSave
|
from .AutoSave import AutoSave
|
||||||
from .Machines.Models.CompatibleMachineModel import CompatibleMachineModel
|
from .Machines.Models.CompatibleMachineModel import CompatibleMachineModel
|
||||||
from .Machines.Models.MachineListModel import MachineListModel
|
from .Machines.Models.MachineListModel import MachineListModel
|
||||||
|
@ -409,7 +409,9 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
SettingFunction.registerOperator("extruderValue", self._cura_formula_functions.getValueInExtruder)
|
SettingFunction.registerOperator("extruderValue", self._cura_formula_functions.getValueInExtruder)
|
||||||
SettingFunction.registerOperator("extruderValues", self._cura_formula_functions.getValuesInAllExtruders)
|
SettingFunction.registerOperator("extruderValues", self._cura_formula_functions.getValuesInAllExtruders)
|
||||||
SettingFunction.registerOperator("anyExtruderNrWithOrDefault", self._cura_formula_functions.getAnyExtruderPositionWithOrDefault)
|
SettingFunction.registerOperator("anyExtruderWithMaterial", self._cura_formula_functions.getExtruderPositionWithMaterial)
|
||||||
|
SettingFunction.registerOperator("anyExtruderNrWithOrDefault",
|
||||||
|
self._cura_formula_functions.getAnyExtruderPositionWithOrDefault)
|
||||||
SettingFunction.registerOperator("resolveOrValue", self._cura_formula_functions.getResolveOrValue)
|
SettingFunction.registerOperator("resolveOrValue", self._cura_formula_functions.getResolveOrValue)
|
||||||
SettingFunction.registerOperator("defaultExtruderPosition", self._cura_formula_functions.getDefaultExtruderPosition)
|
SettingFunction.registerOperator("defaultExtruderPosition", self._cura_formula_functions.getDefaultExtruderPosition)
|
||||||
SettingFunction.registerOperator("valueFromContainer", self._cura_formula_functions.getValueFromContainerAtIndex)
|
SettingFunction.registerOperator("valueFromContainer", self._cura_formula_functions.getValueFromContainerAtIndex)
|
||||||
|
@ -495,6 +497,36 @@ class CuraApplication(QtApplication):
|
||||||
def startSplashWindowPhase(self) -> None:
|
def startSplashWindowPhase(self) -> None:
|
||||||
"""Runs preparations that needs to be done before the starting process."""
|
"""Runs preparations that needs to be done before the starting process."""
|
||||||
|
|
||||||
|
self.setRequiredPlugins([
|
||||||
|
# Misc.:
|
||||||
|
"ConsoleLogger", # You want to be able to read the log if something goes wrong.
|
||||||
|
"CuraEngineBackend", # Cura is useless without this one since you can't slice.
|
||||||
|
"FileLogger", # You want to be able to read the log if something goes wrong.
|
||||||
|
"XmlMaterialProfile", # Cura crashes without this one.
|
||||||
|
"Marketplace",
|
||||||
|
# This contains the interface to enable/disable plug-ins, so if you disable it you can't enable it back.
|
||||||
|
"PrepareStage", # Cura is useless without this one since you can't load models.
|
||||||
|
"PreviewStage", # This shows the list of the plugin views that are installed in Cura.
|
||||||
|
"MonitorStage", # Major part of Cura's functionality.
|
||||||
|
"LocalFileOutputDevice", # Major part of Cura's functionality.
|
||||||
|
"LocalContainerProvider", # Cura is useless without any profiles or setting definitions.
|
||||||
|
|
||||||
|
# Views:
|
||||||
|
"SimpleView", # Dependency of SolidView.
|
||||||
|
"SolidView", # Displays models. Cura is useless without it.
|
||||||
|
|
||||||
|
# Readers & Writers:
|
||||||
|
"GCodeWriter", # Cura is useless if it can't write its output.
|
||||||
|
"STLReader", # Most common model format, so disabling this makes Cura 90% useless.
|
||||||
|
"3MFWriter", # Required for writing project files.
|
||||||
|
|
||||||
|
# Tools:
|
||||||
|
"CameraTool", # Needed to see the scene. Cura is useless without it.
|
||||||
|
"SelectionTool", # Dependency of the rest of the tools.
|
||||||
|
"TranslateTool", # You'll need this for almost every print.
|
||||||
|
])
|
||||||
|
# Plugins need to be set here, since in the super the check is done if they are actually loaded.
|
||||||
|
|
||||||
super().startSplashWindowPhase()
|
super().startSplashWindowPhase()
|
||||||
|
|
||||||
if not self.getIsHeadLess():
|
if not self.getIsHeadLess():
|
||||||
|
@ -503,33 +535,7 @@ class CuraApplication(QtApplication):
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
Logger.log("w", "Unable to find the window icon.")
|
Logger.log("w", "Unable to find the window icon.")
|
||||||
|
|
||||||
self.setRequiredPlugins([
|
|
||||||
# Misc.:
|
|
||||||
"ConsoleLogger", #You want to be able to read the log if something goes wrong.
|
|
||||||
"CuraEngineBackend", #Cura is useless without this one since you can't slice.
|
|
||||||
"FileLogger", #You want to be able to read the log if something goes wrong.
|
|
||||||
"XmlMaterialProfile", #Cura crashes without this one.
|
|
||||||
"Marketplace", #This contains the interface to enable/disable plug-ins, so if you disable it you can't enable it back.
|
|
||||||
"PrepareStage", #Cura is useless without this one since you can't load models.
|
|
||||||
"PreviewStage", #This shows the list of the plugin views that are installed in Cura.
|
|
||||||
"MonitorStage", #Major part of Cura's functionality.
|
|
||||||
"LocalFileOutputDevice", #Major part of Cura's functionality.
|
|
||||||
"LocalContainerProvider", #Cura is useless without any profiles or setting definitions.
|
|
||||||
|
|
||||||
# Views:
|
|
||||||
"SimpleView", #Dependency of SolidView.
|
|
||||||
"SolidView", #Displays models. Cura is useless without it.
|
|
||||||
|
|
||||||
# Readers & Writers:
|
|
||||||
"GCodeWriter", #Cura is useless if it can't write its output.
|
|
||||||
"STLReader", #Most common model format, so disabling this makes Cura 90% useless.
|
|
||||||
"3MFWriter", #Required for writing project files.
|
|
||||||
|
|
||||||
# Tools:
|
|
||||||
"CameraTool", #Needed to see the scene. Cura is useless without it.
|
|
||||||
"SelectionTool", #Dependency of the rest of the tools.
|
|
||||||
"TranslateTool", #You'll need this for almost every print.
|
|
||||||
])
|
|
||||||
self._i18n_catalog = i18nCatalog("cura")
|
self._i18n_catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
self._update_platform_activity_timer = QTimer()
|
self._update_platform_activity_timer = QTimer()
|
||||||
|
@ -1438,6 +1444,13 @@ class CuraApplication(QtApplication):
|
||||||
# Single build plate
|
# Single build plate
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def arrangeAll(self) -> None:
|
def arrangeAll(self) -> None:
|
||||||
|
self._arrangeAll(grid_arrangement = False)
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def arrangeAllInGrid(self) -> None:
|
||||||
|
self._arrangeAll(grid_arrangement = True)
|
||||||
|
|
||||||
|
def _arrangeAll(self, *, grid_arrangement: bool) -> None:
|
||||||
nodes_to_arrange = []
|
nodes_to_arrange = []
|
||||||
active_build_plate = self.getMultiBuildPlateModel().activeBuildPlate
|
active_build_plate = self.getMultiBuildPlateModel().activeBuildPlate
|
||||||
locked_nodes = []
|
locked_nodes = []
|
||||||
|
@ -1467,17 +1480,17 @@ class CuraApplication(QtApplication):
|
||||||
locked_nodes.append(node)
|
locked_nodes.append(node)
|
||||||
else:
|
else:
|
||||||
nodes_to_arrange.append(node)
|
nodes_to_arrange.append(node)
|
||||||
self.arrange(nodes_to_arrange, locked_nodes)
|
self.arrange(nodes_to_arrange, locked_nodes, grid_arrangement = grid_arrangement)
|
||||||
|
|
||||||
def arrange(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode]) -> None:
|
def arrange(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], *, grid_arrangement: bool = False) -> None:
|
||||||
"""Arrange a set of nodes given a set of fixed nodes
|
"""Arrange a set of nodes given a set of fixed nodes
|
||||||
|
|
||||||
:param nodes: nodes that we have to place
|
:param nodes: nodes that we have to place
|
||||||
:param fixed_nodes: nodes that are placed in the arranger before finding spots for nodes
|
:param fixed_nodes: nodes that are placed in the arranger before finding spots for nodes
|
||||||
|
:param grid_arrangement: If set to true if objects are to be placed in a grid
|
||||||
"""
|
"""
|
||||||
|
|
||||||
min_offset = self.getBuildVolume().getEdgeDisallowedSize() + 2 # Allow for some rounding errors
|
min_offset = self.getBuildVolume().getEdgeDisallowedSize() + 2 # Allow for some rounding errors
|
||||||
job = ArrangeObjectsJob(nodes, fixed_nodes, min_offset = max(min_offset, 8))
|
job = ArrangeObjectsJob(nodes, fixed_nodes, min_offset = max(min_offset, 8), grid_arrange = grid_arrangement)
|
||||||
job.start()
|
job.start()
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
|
@ -1964,7 +1977,8 @@ class CuraApplication(QtApplication):
|
||||||
if select_models_on_load:
|
if select_models_on_load:
|
||||||
Selection.add(node)
|
Selection.add(node)
|
||||||
try:
|
try:
|
||||||
arrange(nodes_to_arrange, self.getBuildVolume(), fixed_nodes)
|
arranger = Nest2DArrange(nodes_to_arrange, self.getBuildVolume(), fixed_nodes)
|
||||||
|
arranger.arrange()
|
||||||
except:
|
except:
|
||||||
Logger.logException("e", "Failed to arrange the models")
|
Logger.logException("e", "Failed to arrange the models")
|
||||||
|
|
||||||
|
|
|
@ -14,17 +14,19 @@ from UM.Operations.TranslateOperation import TranslateOperation
|
||||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
from cura.Arranging.Nest2DArrange import arrange, createGroupOperationForArrange
|
from cura.Arranging.GridArrange import GridArrange
|
||||||
|
from cura.Arranging.Nest2DArrange import Nest2DArrange
|
||||||
|
|
||||||
i18n_catalog = i18nCatalog("cura")
|
i18n_catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
|
||||||
class MultiplyObjectsJob(Job):
|
class MultiplyObjectsJob(Job):
|
||||||
def __init__(self, objects, count, min_offset = 8):
|
def __init__(self, objects, count: int, min_offset: int = 8 ,* , grid_arrange: bool = False):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._objects = objects
|
self._objects = objects
|
||||||
self._count = count
|
self._count: int = count
|
||||||
self._min_offset = min_offset
|
self._min_offset: int = min_offset
|
||||||
|
self._grid_arrange: bool = grid_arrange
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
status_message = Message(i18n_catalog.i18nc("@info:status", "Multiplying and placing objects"), lifetime = 0,
|
status_message = Message(i18n_catalog.i18nc("@info:status", "Multiplying and placing objects"), lifetime = 0,
|
||||||
|
@ -39,7 +41,7 @@ class MultiplyObjectsJob(Job):
|
||||||
|
|
||||||
root = scene.getRoot()
|
root = scene.getRoot()
|
||||||
|
|
||||||
processed_nodes = [] # type: List[SceneNode]
|
processed_nodes: List[SceneNode] = []
|
||||||
nodes = []
|
nodes = []
|
||||||
|
|
||||||
fixed_nodes = []
|
fixed_nodes = []
|
||||||
|
@ -76,12 +78,12 @@ class MultiplyObjectsJob(Job):
|
||||||
found_solution_for_all = True
|
found_solution_for_all = True
|
||||||
group_operation = GroupedOperation()
|
group_operation = GroupedOperation()
|
||||||
if nodes:
|
if nodes:
|
||||||
group_operation, not_fit_count = createGroupOperationForArrange(nodes,
|
if self._grid_arrange:
|
||||||
Application.getInstance().getBuildVolume(),
|
arranger = GridArrange(nodes, Application.getInstance().getBuildVolume(), fixed_nodes)
|
||||||
fixed_nodes,
|
else:
|
||||||
factor = 10000,
|
arranger = Nest2DArrange(nodes, Application.getInstance().getBuildVolume(), fixed_nodes, factor=1000)
|
||||||
add_new_nodes_in_scene = True)
|
|
||||||
found_solution_for_all = not_fit_count == 0
|
group_operation, not_fit_count = arranger.createGroupOperationForArrange(add_new_nodes_in_scene=True)
|
||||||
|
|
||||||
if nodes_to_add_without_arrange:
|
if nodes_to_add_without_arrange:
|
||||||
for nested_node in nodes_to_add_without_arrange:
|
for nested_node in nodes_to_add_without_arrange:
|
||||||
|
|
|
@ -111,11 +111,7 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
||||||
|
|
||||||
# Parent can be None if node is just loaded.
|
# Parent can be None if node is just loaded.
|
||||||
if self._isSingularOneAtATimeNode():
|
if self._isSingularOneAtATimeNode():
|
||||||
hull = self.getConvexHullHeadFull()
|
return self.getConvexHullHeadFull()
|
||||||
if hull is None:
|
|
||||||
return None
|
|
||||||
hull = self._add2DAdhesionMargin(hull)
|
|
||||||
return hull
|
|
||||||
|
|
||||||
return self._compute2DConvexHull()
|
return self._compute2DConvexHull()
|
||||||
|
|
||||||
|
@ -323,6 +319,7 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
||||||
|
|
||||||
def _compute2DConvexHeadFull(self) -> Optional[Polygon]:
|
def _compute2DConvexHeadFull(self) -> Optional[Polygon]:
|
||||||
convex_hull = self._compute2DConvexHull()
|
convex_hull = self._compute2DConvexHull()
|
||||||
|
convex_hull = self._add2DAdhesionMargin(convex_hull)
|
||||||
if convex_hull:
|
if convex_hull:
|
||||||
return convex_hull.getMinkowskiHull(self._getHeadAndFans())
|
return convex_hull.getMinkowskiHull(self._getHeadAndFans())
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -105,6 +105,15 @@ class CuraFormulaFunctions:
|
||||||
if value is None or not value:
|
if value is None or not value:
|
||||||
continue
|
continue
|
||||||
return str(extruder.position)
|
return str(extruder.position)
|
||||||
|
|
||||||
|
# Get the first extruder with material that adheres to a specific (boolean) property, like 'material_is_support_material'.
|
||||||
|
def getExtruderPositionWithMaterial(self, filter_key: str,
|
||||||
|
context: Optional["PropertyEvaluationContext"] = None) -> str:
|
||||||
|
for extruder in self._getActiveExtruders(context):
|
||||||
|
material_container = extruder.material
|
||||||
|
value = material_container.getProperty(filter_key, "value", context)
|
||||||
|
if value is not None:
|
||||||
|
return str(extruder.position)
|
||||||
return self.getDefaultExtruderPosition()
|
return self.getDefaultExtruderPosition()
|
||||||
|
|
||||||
# Get the resolve value or value for a given key.
|
# Get the resolve value or value for a given key.
|
||||||
|
|
|
@ -54,7 +54,10 @@ There are also a few extra things that can be used in these expressions:
|
||||||
* The function `extruderValue(extruder, key)` will evaluate a particular setting for a particular extruder.
|
* The function `extruderValue(extruder, key)` will evaluate a particular setting for a particular extruder.
|
||||||
* The function `resolveOrValue(key)` will perform the full setting evaluation as described in this document for the current context (so if this setting is being evaluated for the second extruder it would perform it as if coming from the second extruder).
|
* The function `resolveOrValue(key)` will perform the full setting evaluation as described in this document for the current context (so if this setting is being evaluated for the second extruder it would perform it as if coming from the second extruder).
|
||||||
* The function `defaultExtruderPosition()` will get the first extruder that is not disabled. For instance, if a printer has three extruders but the first is disabled, this would return `1` to indicate the second extruder (0-indexed).
|
* The function `defaultExtruderPosition()` will get the first extruder that is not disabled. For instance, if a printer has three extruders but the first is disabled, this would return `1` to indicate the second extruder (0-indexed).
|
||||||
* The function `anyExtruderNrWithOrDefault(key)` will filter the list of extruders on the key, and then give the first index for which it is true, or if none of them are, the default one as specified by the 'default extruder position' function above.
|
* The function `anyExtruderNrWithOrDefault(key)` will filter the list of extruders on the key, and then give the first
|
||||||
|
index for which it is true, or if none of them are, the default one as specified by the 'default extruder position'
|
||||||
|
function above.
|
||||||
|
* The function `anyExtruderWithMaterial(key)` will filter the list of extruders on the key of material quality, and then give the first index for which it is true, or if none of them are, the default one as specified by the 'default extruder position' function above.
|
||||||
* The function `valueFromContainer(key, index)` will get a setting value from the global stack, but skip the first few containers in that stack. It will skip until it reaches a particular index in the container stack.
|
* The function `valueFromContainer(key, index)` will get a setting value from the global stack, but skip the first few containers in that stack. It will skip until it reaches a particular index in the container stack.
|
||||||
* The function `extruderValueFromContainer(key, index)` will get a setting value from the current extruder stack, but skip the first few containers in that stack. It will skip until it reaches a particular index in the container stack.
|
* The function `extruderValueFromContainer(key, index)` will get a setting value from the current extruder stack, but skip the first few containers in that stack. It will skip until it reaches a particular index in the container stack.
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ def build_dmg(source_path: str, dist_path: str, filename: str, app_name: str) ->
|
||||||
"--icon", app_name, "169", "272",
|
"--icon", app_name, "169", "272",
|
||||||
"--eula", f"{source_path}/packaging/cura_license.txt",
|
"--eula", f"{source_path}/packaging/cura_license.txt",
|
||||||
"--background", f"{source_path}/packaging/MacOs/cura_background_dmg.png",
|
"--background", f"{source_path}/packaging/MacOs/cura_background_dmg.png",
|
||||||
|
"--hdiutil-quiet",
|
||||||
f"{dist_path}/{filename}",
|
f"{dist_path}/{filename}",
|
||||||
f"{dist_path}/{app_name}"]
|
f"{dist_path}/{app_name}"]
|
||||||
|
|
||||||
|
@ -138,18 +139,20 @@ def create_dmg(filename: str, dist_path: str, source_path: str, app_name: str) -
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description = "Create installer for Cura.")
|
parser = argparse.ArgumentParser(description = "Create installer for Cura.")
|
||||||
parser.add_argument("source_path", type = str, help = "Path to Pyinstaller source folder")
|
parser.add_argument("--source_path", required = True, type = str, help = "Path to Pyinstaller source folder")
|
||||||
parser.add_argument("dist_path", type = str, help = "Path to Pyinstaller dist folder")
|
parser.add_argument("--dist_path", required = True, type = str, help = "Path to Pyinstaller dist folder")
|
||||||
parser.add_argument("cura_conan_version", type = str, help="The version of cura")
|
parser.add_argument("--cura_conan_version", required = True, type = str, help = "The version of cura")
|
||||||
parser.add_argument("filename", type = str, help = "Filename of the pkg/dmg (e.g. 'UltiMaker-Cura-5.1.0-beta-Macos-X64.pkg' or 'UltiMaker-Cura-5.1.0-beta-Macos-X64.dmg')")
|
parser.add_argument("--filename", required = True, type = str, help = "Filename of the pkg/dmg (e.g. 'UltiMaker-Cura-5.5.0-Macos-X64' or 'UltiMaker-Cura-5.5.0-beta.1-Macos-ARM64')")
|
||||||
parser.add_argument("app_name", type = str, help = "Filename of the .app that will be contained within the dmg/pkg")
|
parser.add_argument("--build_pkg", action="store_true", default = False, help = "build the pkg")
|
||||||
|
parser.add_argument("--build_dmg", action="store_true", default = True, help = "build the dmg")
|
||||||
|
parser.add_argument("--app_name", required = True, type = str, help = "Filename of the .app that will be contained within the dmg/pkg")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
cura_version = args.cura_conan_version.split("/")[-1]
|
cura_version = args.cura_conan_version.split("/")[-1]
|
||||||
|
|
||||||
app_name = f"{args.app_name}.app"
|
app_name = f"{args.app_name}.app"
|
||||||
|
|
||||||
if Path(args.filename).suffix == ".pkg":
|
if args.build_pkg:
|
||||||
create_pkg_installer(args.filename, args.dist_path, cura_version, app_name)
|
create_pkg_installer(f"{args.filename}.pkg", args.dist_path, cura_version, app_name)
|
||||||
else:
|
if args.build_dmg:
|
||||||
create_dmg(args.filename, args.dist_path, args.source_path, app_name)
|
create_dmg(f"{args.filename}.dmg", args.dist_path, args.source_path, app_name)
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 381 KiB After Width: | Height: | Size: 417 KiB |
|
@ -1,5 +1,5 @@
|
||||||
# Copyright (c) 2018 Jaime van Kessel, Ultimaker B.V.
|
# Copyright (c) 2018 Jaime van Kessel, Ultimaker B.V.
|
||||||
# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.
|
# The PostProcessingPlugin is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
import configparser # The script lists are stored in metadata as serialised config files.
|
import configparser # The script lists are stored in metadata as serialised config files.
|
||||||
import importlib.util
|
import importlib.util
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2022 Jaime van Kessel, Ultimaker B.V.
|
// Copyright (c) 2022 Jaime van Kessel, Ultimaker B.V.
|
||||||
// The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.
|
// The PostProcessingPlugin is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
import QtQuick 2.2
|
import QtQuick 2.2
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Copyright (c) 2015 Jaime van Kessel
|
# Copyright (c) 2015 Jaime van Kessel
|
||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.
|
# The PostProcessingPlugin is released under the terms of the LGPLv3 or higher.
|
||||||
from typing import Optional, Any, Dict, TYPE_CHECKING, List
|
from typing import Optional, Any, Dict, TYPE_CHECKING, List
|
||||||
|
|
||||||
from UM.Signal import Signal, signalemitter
|
from UM.Signal import Signal, signalemitter
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# ChangeAtZ script - Change printing parameters at a given height
|
# ChangeAtZ script - Change printing parameters at a given height
|
||||||
# This script is the successor of the TweakAtZ plugin for legacy Cura.
|
# This script is the successor of the TweakAtZ plugin for legacy Cura.
|
||||||
# It contains code from the TweakAtZ plugin V1.0-V4.x and from the ExampleScript by Jaime van Kessel, Ultimaker B.V.
|
# It contains code from the TweakAtZ plugin V1.0-V4.x and from the ExampleScript by Jaime van Kessel, Ultimaker B.V.
|
||||||
# It runs with the PostProcessingPlugin which is released under the terms of the AGPLv3 or higher.
|
# It runs with the PostProcessingPlugin which is released under the terms of the LGPLv3 or higher.
|
||||||
# This script is licensed under the Creative Commons - Attribution - Share Alike (CC BY-SA) terms
|
# This script is licensed under the Creative Commons - Attribution - Share Alike (CC BY-SA) terms
|
||||||
|
|
||||||
# Authors of the ChangeAtZ plugin / script:
|
# Authors of the ChangeAtZ plugin / script:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# ColorMix script - 2-1 extruder color mix and blending
|
# ColorMix script - 2-1 extruder color mix and blending
|
||||||
# This script is specific for the Geeetech A10M dual extruder but should work with other Marlin printers.
|
# This script is specific for the Geeetech A10M dual extruder but should work with other Marlin printers.
|
||||||
# It runs with the PostProcessingPlugin which is released under the terms of the AGPLv3 or higher.
|
# It runs with the PostProcessingPlugin which is released under the terms of the LGPLv3 or higher.
|
||||||
# This script is licensed under the Creative Commons - Attribution - Share Alike (CC BY-SA) terms
|
# This script is licensed under the Creative Commons - Attribution - Share Alike (CC BY-SA) terms
|
||||||
|
|
||||||
#Authors of the 2-1 ColorMix plug-in / script:
|
#Authors of the 2-1 ColorMix plug-in / script:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Copyright (c) 2023 Ultimaker B.V.
|
# Copyright (c) 2023 Ultimaker B.V.
|
||||||
# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.
|
# The PostProcessingPlugin is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
# Modification 06.09.2020
|
# Modification 06.09.2020
|
||||||
# add checkbox, now you can choose and use configuration from the firmware itself.
|
# add checkbox, now you can choose and use configuration from the firmware itself.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Copyright (c) 2023 UltiMaker B.V.
|
# Copyright (c) 2023 UltiMaker B.V.
|
||||||
# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.
|
# The PostProcessingPlugin is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from ..Script import Script
|
from ..Script import Script
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Copyright (c) 2017 Ghostkeeper
|
# Copyright (c) 2017 Ghostkeeper
|
||||||
# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.
|
# The PostProcessingPlugin is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
import re #To perform the search and replace.
|
import re #To perform the search and replace.
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# This PostProcessingPlugin script is released under the terms of the AGPLv3 or higher.
|
# This PostProcessingPlugin script is released under the terms of the LGPLv3 or higher.
|
||||||
"""
|
"""
|
||||||
Copyright (c) 2017 Christophe Baribaud 2017
|
Copyright (c) 2017 Christophe Baribaud 2017
|
||||||
Python implementation of https://github.com/electrocbd/post_stretch
|
Python implementation of https://github.com/electrocbd/post_stretch
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
|
@ -143,38 +144,44 @@ class RemovableDriveOutputDevice(OutputDevice):
|
||||||
|
|
||||||
def _onFinished(self, job):
|
def _onFinished(self, job):
|
||||||
if self._stream:
|
if self._stream:
|
||||||
# Explicitly closing the stream flushes the write-buffer
|
error = job.getError()
|
||||||
try:
|
try:
|
||||||
|
# Explicitly closing the stream flushes the write-buffer
|
||||||
self._stream.close()
|
self._stream.close()
|
||||||
self._stream = None
|
except Exception as e:
|
||||||
except:
|
if not error:
|
||||||
Logger.logException("w", "An exception occurred while trying to write to removable drive.")
|
# Only log new error if there was no previous one
|
||||||
message = Message(catalog.i18nc("@info:status", "Could not save to removable drive {0}: {1}").format(self.getName(),str(job.getError())),
|
error = e
|
||||||
title = catalog.i18nc("@info:title", "Error"),
|
|
||||||
message_type = Message.MessageType.ERROR)
|
|
||||||
message.show()
|
|
||||||
self.writeError.emit(self)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
self._stream = None
|
||||||
self._writing = False
|
self._writing = False
|
||||||
self.writeFinished.emit(self)
|
self.writeFinished.emit(self)
|
||||||
if job.getResult():
|
|
||||||
message = Message(catalog.i18nc("@info:status", "Saved to Removable Drive {0} as {1}").format(self.getName(), os.path.basename(job.getFileName())),
|
if not error:
|
||||||
title = catalog.i18nc("@info:title", "File Saved"),
|
message = Message(
|
||||||
message_type = Message.MessageType.POSITIVE)
|
catalog.i18nc("@info:status", "Saved to Removable Drive {0} as {1}").format(self.getName(),
|
||||||
message.addAction("eject", catalog.i18nc("@action:button", "Eject"), "eject", catalog.i18nc("@action", "Eject removable device {0}").format(self.getName()))
|
os.path.basename(
|
||||||
|
job.getFileName())),
|
||||||
|
title=catalog.i18nc("@info:title", "File Saved"),
|
||||||
|
message_type=Message.MessageType.POSITIVE)
|
||||||
|
message.addAction("eject", catalog.i18nc("@action:button", "Eject"), "eject",
|
||||||
|
catalog.i18nc("@action", "Eject removable device {0}").format(self.getName()))
|
||||||
message.actionTriggered.connect(self._onActionTriggered)
|
message.actionTriggered.connect(self._onActionTriggered)
|
||||||
message.show()
|
message.show()
|
||||||
self.writeSuccess.emit(self)
|
self.writeSuccess.emit(self)
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
|
os.remove(job.getFileName())
|
||||||
|
except Exception as e:
|
||||||
|
Logger.logException("e", "Exception when trying to remove incomplete exported file %s",
|
||||||
|
str(job.getFileName()))
|
||||||
message = Message(catalog.i18nc("@info:status",
|
message = Message(catalog.i18nc("@info:status",
|
||||||
"Could not save to removable drive {0}: {1}").format(self.getName(),
|
"Could not save to removable drive {0}: {1}").format(self.getName(),
|
||||||
str(job.getError())),
|
str(job.getError())),
|
||||||
title = catalog.i18nc("@info:title", "Error"),
|
title=catalog.i18nc("@info:title", "Error"),
|
||||||
message_type = Message.MessageType.ERROR)
|
message_type=Message.MessageType.ERROR)
|
||||||
message.show()
|
message.show()
|
||||||
self.writeError.emit(self)
|
self.writeError.emit(self)
|
||||||
job.getStream().close()
|
|
||||||
|
|
||||||
def _onActionTriggered(self, message, action):
|
def _onActionTriggered(self, message, action):
|
||||||
if action == "eject":
|
if action == "eject":
|
||||||
|
|
|
@ -37,24 +37,13 @@ class NewPrinterDetectedMessage(Message):
|
||||||
|
|
||||||
def finalize(self, new_devices_added, new_output_devices):
|
def finalize(self, new_devices_added, new_output_devices):
|
||||||
self.setProgress(None)
|
self.setProgress(None)
|
||||||
num_devices_added = len(new_devices_added)
|
|
||||||
max_disp_devices = 3
|
|
||||||
|
|
||||||
if num_devices_added > max_disp_devices:
|
|
||||||
num_hidden = num_devices_added - max_disp_devices
|
|
||||||
device_name_list = ["<li>{} ({})</li>".format(device.name, device.printerTypeName) for device in
|
|
||||||
new_output_devices[0: max_disp_devices]]
|
|
||||||
device_name_list.append(
|
|
||||||
"<li>" + self.i18n_catalog.i18ncp("info:{0} gets replaced by a number of printers", "... and {0} other",
|
|
||||||
"... and {0} others", num_hidden) + "</li>")
|
|
||||||
device_names = "".join(device_name_list)
|
|
||||||
else:
|
|
||||||
device_names = "".join(
|
|
||||||
["<li>{} ({})</li>".format(device.name, device.printerTypeName) for device in new_devices_added])
|
|
||||||
|
|
||||||
if new_devices_added:
|
if new_devices_added:
|
||||||
message_text = self.i18n_catalog.i18nc("info:status",
|
device_names = ""
|
||||||
"Printers added from Digital Factory:") + f"<ul>{device_names}</ul>"
|
for device in new_devices_added:
|
||||||
|
device_names = device_names + "<li>{} ({})</li>".format(device.name, device.printerTypeName)
|
||||||
|
message_title = self.i18n_catalog.i18nc("info:status", "Printers added from Digital Factory:")
|
||||||
|
message_text = f"{message_title}<ul>{device_names}</ul>"
|
||||||
self.setText(message_text)
|
self.setText(message_text)
|
||||||
else:
|
else:
|
||||||
self.hide()
|
self.hide()
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
"machine_width": { "default_value": 280 },
|
"machine_width": { "default_value": 280 },
|
||||||
"material_diameter": { "default_value": 1.75 },
|
"material_diameter": { "default_value": 1.75 },
|
||||||
"material_initial_print_temperature": { "value": "material_print_temperature" },
|
"material_initial_print_temperature": { "value": "material_print_temperature" },
|
||||||
"prime_tower_min_volume": { "value": "((reveOrValue('layer_height'))/2" },
|
"prime_tower_min_volume": { "value": "((resolveOrValue('layer_height'))/2" },
|
||||||
"prime_tower_position_x": { "value": "240" },
|
"prime_tower_position_x": { "value": "240" },
|
||||||
"prime_tower_position_y": { "value": "190" },
|
"prime_tower_position_y": { "value": "190" },
|
||||||
"prime_tower_size": { "value": "30" },
|
"prime_tower_size": { "value": "30" },
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
"material_print_temperature_layer_0": { "value": "210 if material_print_temperature < 210 else material_print_temperature" },
|
"material_print_temperature_layer_0": { "value": "210 if material_print_temperature < 210 else material_print_temperature" },
|
||||||
"min_infill_area": { "value": "5" },
|
"min_infill_area": { "value": "5" },
|
||||||
"minimum_interface_area": { "default_value": 10 },
|
"minimum_interface_area": { "default_value": 10 },
|
||||||
"minimum_support_area": { "default_value": 3 },
|
"minimum_support_area": { "value": "3 if support_structure == 'normal' else 0" },
|
||||||
"optimize_wall_printing_order": { "default_value": true },
|
"optimize_wall_printing_order": { "default_value": true },
|
||||||
"prime_tower_brim_enable": { "default_value": true },
|
"prime_tower_brim_enable": { "default_value": true },
|
||||||
"prime_tower_min_volume": { "value": "(layer_height) * (prime_tower_size / 2)**2 * 3 * 0.5 " },
|
"prime_tower_min_volume": { "value": "(layer_height) * (prime_tower_size / 2)**2 * 3 * 0.5 " },
|
||||||
|
|
|
@ -1664,17 +1664,27 @@
|
||||||
"small_skin_width":
|
"small_skin_width":
|
||||||
{
|
{
|
||||||
"label": "Small Top/Bottom Width",
|
"label": "Small Top/Bottom Width",
|
||||||
"description": "Small top/bottom regions are filled with walls instead of the default top/bottom pattern. This helps to avoids jerky motions.",
|
"description": "Small top/bottom regions are filled with walls instead of the default top/bottom pattern. This helps to avoids jerky motions. Off for the topmost (air-exposed) layer by default (see 'Small Top/Bottom On Surface').",
|
||||||
"value": "0",
|
"value": "skin_line_width * 2",
|
||||||
"default_value": 0,
|
"default_value": 1,
|
||||||
"minimum_value": "0",
|
"minimum_value": "0",
|
||||||
"maximum_value_warning": "skin_line_width * 10",
|
"maximum_value_warning": "skin_line_width * 3",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"enabled": false,
|
"enabled": "(top_layers > 0 or bottom_layers > 0) and top_bottom_pattern != 'concentric'",
|
||||||
"limit_to_extruder": "top_bottom_extruder_nr",
|
"limit_to_extruder": "top_bottom_extruder_nr",
|
||||||
"settable_per_mesh": true,
|
"settable_per_mesh": true,
|
||||||
"unit": "mm",
|
"unit": "mm"
|
||||||
"comment": "Disabled for 5.4.x, as we're worried about micro-segments in the infill. Also disabled in the engine, so forcing this > 0 will not do anything at the moment."
|
},
|
||||||
|
"small_skin_on_surface":
|
||||||
|
{
|
||||||
|
"label": "Small Top/Bottom On Surface",
|
||||||
|
"description": "Enable small (up to 'Small Top/Bottom Width') regions on the topmost skinned layer (exposed to air) to be filled with walls instead of the default pattern.",
|
||||||
|
"value": "False",
|
||||||
|
"default_value": false,
|
||||||
|
"type": "bool",
|
||||||
|
"enabled": "small_skin_width > 0 and top_layers > 0",
|
||||||
|
"limit_to_extruder": "top_bottom_extruder_nr",
|
||||||
|
"settable_per_mesh": true
|
||||||
},
|
},
|
||||||
"skin_no_small_gaps_heuristic":
|
"skin_no_small_gaps_heuristic":
|
||||||
{
|
{
|
||||||
|
@ -4490,7 +4500,7 @@
|
||||||
"type": "extruder",
|
"type": "extruder",
|
||||||
"default_value": "0",
|
"default_value": "0",
|
||||||
"enabled": "(support_enable or support_meshes_present) and extruders_enabled_count > 1",
|
"enabled": "(support_enable or support_meshes_present) and extruders_enabled_count > 1",
|
||||||
"value": "int(defaultExtruderPosition())",
|
"value": "int(anyExtruderWithMaterial('material_is_support_material'))",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"children":
|
"children":
|
||||||
|
@ -4570,6 +4580,7 @@
|
||||||
},
|
},
|
||||||
"enabled": "support_enable",
|
"enabled": "support_enable",
|
||||||
"default_value": "normal",
|
"default_value": "normal",
|
||||||
|
"resolve": "extruderValue(support_extruder_nr, 'support_structure')",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false
|
"settable_per_extruder": false
|
||||||
},
|
},
|
||||||
|
@ -5504,7 +5515,9 @@
|
||||||
"unit": "mm",
|
"unit": "mm",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 0.0,
|
"default_value": 0.0,
|
||||||
"maximum_value": "extruderValue(support_extruder_nr, 'support_offset')",
|
"maximum_value": "extruderValue(support_extruder_nr, 'support_offset') if support_structure == 'normal' else None",
|
||||||
|
"minimum_value_warning": "-1 * machine_nozzle_size",
|
||||||
|
"maximum_value_warning": "10 * machine_nozzle_size",
|
||||||
"limit_to_extruder": "support_interface_extruder_nr",
|
"limit_to_extruder": "support_interface_extruder_nr",
|
||||||
"enabled": "support_interface_enable and (support_enable or support_meshes_present)",
|
"enabled": "support_interface_enable and (support_enable or support_meshes_present)",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
|
@ -5519,7 +5532,9 @@
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 0.0,
|
"default_value": 0.0,
|
||||||
"value": "extruderValue(support_roof_extruder_nr, 'support_interface_offset')",
|
"value": "extruderValue(support_roof_extruder_nr, 'support_interface_offset')",
|
||||||
"maximum_value": "extruderValue(support_extruder_nr, 'support_offset')",
|
"maximum_value": "extruderValue(support_extruder_nr, 'support_offset') if support_structure == 'normal' else None",
|
||||||
|
"minimum_value_warning": "-1 * machine_nozzle_size",
|
||||||
|
"maximum_value_warning": "10 * machine_nozzle_size",
|
||||||
"limit_to_extruder": "support_roof_extruder_nr",
|
"limit_to_extruder": "support_roof_extruder_nr",
|
||||||
"enabled": "support_roof_enable and (support_enable or support_meshes_present)",
|
"enabled": "support_roof_enable and (support_enable or support_meshes_present)",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
|
@ -5533,7 +5548,9 @@
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 0.0,
|
"default_value": 0.0,
|
||||||
"value": "extruderValue(support_bottom_extruder_nr, 'support_interface_offset')",
|
"value": "extruderValue(support_bottom_extruder_nr, 'support_interface_offset')",
|
||||||
"maximum_value": "extruderValue(support_extruder_nr, 'support_offset')",
|
"maximum_value": "extruderValue(support_extruder_nr, 'support_offset') if support_structure == 'normal' else None",
|
||||||
|
"minimum_value_warning": "-1 * machine_nozzle_size",
|
||||||
|
"maximum_value_warning": "10 * machine_nozzle_size",
|
||||||
"limit_to_extruder": "support_bottom_extruder_nr",
|
"limit_to_extruder": "support_bottom_extruder_nr",
|
||||||
"enabled": "support_bottom_enable and (support_enable or support_meshes_present)",
|
"enabled": "support_bottom_enable and (support_enable or support_meshes_present)",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
|
@ -6805,6 +6822,48 @@
|
||||||
"minimum_value_warning": "500",
|
"minimum_value_warning": "500",
|
||||||
"maximum_value_warning": "100000",
|
"maximum_value_warning": "100000",
|
||||||
"settable_per_mesh": true
|
"settable_per_mesh": true
|
||||||
|
},
|
||||||
|
"meshfix_fluid_motion_enabled":
|
||||||
|
{
|
||||||
|
"label": "Enable Fluid Motion",
|
||||||
|
"description": "When enabled tool paths are corrected for printers with smooth motion planners. Small movements that deviate from the general tool path direction are smoothed to improve fluid motions.",
|
||||||
|
"type": "bool",
|
||||||
|
"default_value": true
|
||||||
|
},
|
||||||
|
"meshfix_fluid_motion_shift_distance":
|
||||||
|
{
|
||||||
|
"label": "Fluid Motion Shift Distance",
|
||||||
|
"description": "Distance points are shifted to smooth the path",
|
||||||
|
"enabled": "meshfix_fluid_motion_enabled",
|
||||||
|
"type": "float",
|
||||||
|
"unit": "mm",
|
||||||
|
"default_value": 0.1,
|
||||||
|
"minimum_value": "0.01",
|
||||||
|
"maximum_value": "1"
|
||||||
|
},
|
||||||
|
"meshfix_fluid_motion_small_distance":
|
||||||
|
{
|
||||||
|
"label": "Fluid Motion Small Distance",
|
||||||
|
"description": "Distance points are shifted to smooth the path",
|
||||||
|
"enabled": "meshfix_fluid_motion_enabled",
|
||||||
|
"unit": "mm",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 0.01,
|
||||||
|
"minimum_value": "0.01",
|
||||||
|
"maximum_value": "0.1"
|
||||||
|
},
|
||||||
|
"meshfix_fluid_motion_angle":
|
||||||
|
{
|
||||||
|
"label": "Fluid Motion Angle",
|
||||||
|
"description": "If a toolpath-segment deviates more than this angle from the general motion it is smoothed.",
|
||||||
|
"enabled": "meshfix_fluid_motion_enabled",
|
||||||
|
"type": "float",
|
||||||
|
"unit": "\u00b0",
|
||||||
|
"default_value": 15,
|
||||||
|
"maximum_value": "90",
|
||||||
|
"minimum_value": "0",
|
||||||
|
"minimum_value_warning": "1",
|
||||||
|
"maximum_value_warning": "35"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,13 +5,14 @@
|
||||||
"metadata":
|
"metadata":
|
||||||
{
|
{
|
||||||
"visible": true,
|
"visible": true,
|
||||||
|
"author": "willuhmjs",
|
||||||
"platform": "kingroon_kp3s.stl",
|
"platform": "kingroon_kp3s.stl",
|
||||||
"quality_definition": "kingroon_base",
|
"quality_definition": "kingroon_base"
|
||||||
"author": "willuhmjs"
|
|
||||||
},
|
},
|
||||||
"overrides":
|
"overrides":
|
||||||
{
|
{
|
||||||
"machine_acceleration": { "value": 1000 },
|
"machine_acceleration": { "value": 1000 },
|
||||||
|
"machine_depth": { "default_value": 200 },
|
||||||
"machine_height": { "default_value": 200 },
|
"machine_height": { "default_value": 200 },
|
||||||
"machine_max_acceleration_e": { "value": 1000 },
|
"machine_max_acceleration_e": { "value": 1000 },
|
||||||
"machine_max_acceleration_x": { "value": 1000 },
|
"machine_max_acceleration_x": { "value": 1000 },
|
||||||
|
@ -23,7 +24,7 @@
|
||||||
"machine_max_feedrate_z": { "value": 4 },
|
"machine_max_feedrate_z": { "value": 4 },
|
||||||
"machine_max_jerk_xy": { "value": 15 },
|
"machine_max_jerk_xy": { "value": 15 },
|
||||||
"machine_max_jerk_z": { "value": 0.4 },
|
"machine_max_jerk_z": { "value": 0.4 },
|
||||||
"machine_name": { "default_value": "Kingroon KP3S" },
|
"machine_name": { "default_value": "Kingroon KP3S Pro" },
|
||||||
"machine_steps_per_mm_e": { "value": 764 },
|
"machine_steps_per_mm_e": { "value": 764 },
|
||||||
"machine_steps_per_mm_x": { "value": 160 },
|
"machine_steps_per_mm_x": { "value": 160 },
|
||||||
"machine_steps_per_mm_y": { "value": 160 },
|
"machine_steps_per_mm_y": { "value": 160 },
|
||||||
|
|
60
resources/definitions/matterhackers_pulsexe_e444m.def.json
Normal file
60
resources/definitions/matterhackers_pulsexe_e444m.def.json
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Pulse XE E-444M",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"visible": true,
|
||||||
|
"author": "Zwitch Guitars",
|
||||||
|
"manufacturer": "MatterHackers",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"first_start_actions": [ "MachineSettingsAction" ],
|
||||||
|
"has_machine_quality": false,
|
||||||
|
"has_materials": true,
|
||||||
|
"has_variants": false,
|
||||||
|
"machine_extruder_trains": { "0": "matterhackers_extruder" },
|
||||||
|
"preferred_material": "generic_pla",
|
||||||
|
"preferred_quality_type": "normal"
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"adhesion_type": { "value": "skirt" },
|
||||||
|
"cool_fan_full_at_height": { "value": "layer_height_0 + 2 * layer_height" },
|
||||||
|
"cool_min_layer_time": { "value": 10 },
|
||||||
|
"gantry_height": { "value": 23 },
|
||||||
|
"machine_acceleration": { "value": 1300 },
|
||||||
|
"machine_depth": { "default_value": 220 },
|
||||||
|
"machine_end_gcode": { "default_value": "M104 S0 ; turn off extruder\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y{machine_depth}; home X axis and push Y forward\nG28 Z0\nM84 ; disable motors" },
|
||||||
|
"machine_gcode_flavor": { "default_value": "Marlin" },
|
||||||
|
"machine_head_with_fans_polygon":
|
||||||
|
{
|
||||||
|
"default_value": [
|
||||||
|
[-28, 45],
|
||||||
|
[-28, -18],
|
||||||
|
[40, 45],
|
||||||
|
[40, -18]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"machine_heated_bed": { "default_value": true },
|
||||||
|
"machine_height": { "default_value": 215 },
|
||||||
|
"machine_max_feedrate_e": { "value": 75 },
|
||||||
|
"machine_max_feedrate_x": { "value": 300 },
|
||||||
|
"machine_max_feedrate_y": { "value": 300 },
|
||||||
|
"machine_max_feedrate_z": { "value": 30 },
|
||||||
|
"machine_name": { "default_value": "Pulse XE E-444M" },
|
||||||
|
"machine_start_gcode": { "default_value": "G21 ; set units to millimeters\nG90 ; use absolute positioning\nM82 ; absolute extrusion mode\nG28 ; home axes\nM104 S{material_print_temperature_layer_0} ; set extruder temp\nM140 S{material_bed_temperature_layer_0} ; set bed temp\nM190 S{material_bed_temperature_layer_0} ; wait for bed temp\nM109 S{material_print_temperature_layer_0} ; wait for extruder temp\nG29 ; mesh bed leveling\n\nG92 E0\nG1 X5 Y5 Z0.8 F1800\nG1 X100 Z0.3 E25 F900\nG92 E0\nG1 E-2 F2400" },
|
||||||
|
"machine_steps_per_mm_e": { "value": 415 },
|
||||||
|
"machine_steps_per_mm_x": { "value": 80 },
|
||||||
|
"machine_steps_per_mm_y": { "value": 80 },
|
||||||
|
"machine_steps_per_mm_z": { "value": 400 },
|
||||||
|
"machine_width": { "default_value": 250 },
|
||||||
|
"material_diameter": { "value": 1.75 },
|
||||||
|
"optimize_wall_printing_order": { "value": true },
|
||||||
|
"speed_layer_0": { "value": 20.0 },
|
||||||
|
"speed_print": { "value": 50 },
|
||||||
|
"top_bottom_thickness": { "value": "layer_height_0 + layer_height * 3" },
|
||||||
|
"travel_retract_before_outer_wall": { "value": true },
|
||||||
|
"wall_thickness": { "value": "line_width * 2" },
|
||||||
|
"z_seam_type": { "value": "back" }
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,7 +57,7 @@
|
||||||
[25, 49],
|
[25, 49],
|
||||||
[25, -49],
|
[25, -49],
|
||||||
[-25, -49],
|
[-25, -49],
|
||||||
[25, 49]
|
[-25, 49]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"machine_heated_bed": { "default_value": true },
|
"machine_heated_bed": { "default_value": true },
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
[25, 49],
|
[25, 49],
|
||||||
[25, -49],
|
[25, -49],
|
||||||
[-25, -49],
|
[-25, -49],
|
||||||
[25, 49]
|
[-25, 49]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"machine_heated_bed": { "default_value": true },
|
"machine_heated_bed": { "default_value": true },
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
[25, 49],
|
[25, 49],
|
||||||
[25, -49],
|
[25, -49],
|
||||||
[-25, -49],
|
[-25, -49],
|
||||||
[25, 49]
|
[-25, 49]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"machine_heated_bed": { "default_value": true },
|
"machine_heated_bed": { "default_value": true },
|
||||||
|
|
|
@ -111,7 +111,7 @@
|
||||||
"skin_angles": { "value": "[] if infill_pattern not in ['cross', 'cross_3d'] else [20, 110]" },
|
"skin_angles": { "value": "[] if infill_pattern not in ['cross', 'cross_3d'] else [20, 110]" },
|
||||||
"skin_edge_support_thickness": { "value": "4 * layer_height if infill_sparse_density < 30 else 0" },
|
"skin_edge_support_thickness": { "value": "4 * layer_height if infill_sparse_density < 30 else 0" },
|
||||||
"skin_material_flow": { "value": "0.95 * material_flow" },
|
"skin_material_flow": { "value": "0.95 * material_flow" },
|
||||||
"skin_material_flow_layer_0": { "value": "0.9 * material_flow_layer_0" },
|
"skin_material_flow_layer_0": { "value": "95" },
|
||||||
"skin_monotonic": { "value": "roofing_layer_count == 0" },
|
"skin_monotonic": { "value": "roofing_layer_count == 0" },
|
||||||
"skin_overlap": { "value": "20" },
|
"skin_overlap": { "value": "20" },
|
||||||
"speed_equalize_flow_width_factor": { "value": "110.0" },
|
"speed_equalize_flow_width_factor": { "value": "110.0" },
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
"platform_texture": "UltimakerS3backplate.png",
|
"platform_texture": "UltimakerS3backplate.png",
|
||||||
"preferred_quality_type": "fast",
|
"preferred_quality_type": "draft",
|
||||||
"preferred_variant_name": "AA 0.4",
|
"preferred_variant_name": "AA 0.4",
|
||||||
"supported_actions": [ "DiscoverUM3Action" ],
|
"supported_actions": [ "DiscoverUM3Action" ],
|
||||||
"supports_material_export": true,
|
"supports_material_export": true,
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
-10
|
-10
|
||||||
],
|
],
|
||||||
"platform_texture": "UltimakerS5backplate.png",
|
"platform_texture": "UltimakerS5backplate.png",
|
||||||
"preferred_quality_type": "fast",
|
"preferred_quality_type": "draft",
|
||||||
"preferred_variant_buildplate_name": "Glass",
|
"preferred_variant_buildplate_name": "Glass",
|
||||||
"preferred_variant_name": "AA 0.4",
|
"preferred_variant_name": "AA 0.4",
|
||||||
"supported_actions": [ "DiscoverUM3Action" ],
|
"supported_actions": [ "DiscoverUM3Action" ],
|
||||||
|
|
16
resources/extruders/matterhackers_extruder.def.json
Normal file
16
resources/extruders/matterhackers_extruder.def.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 1",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"machine": "matterhackers_pulsexe_e444m",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"extruder_nr": { "default_value": 0 },
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = high
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
speed_infill = 50
|
||||||
|
top_bottom_thickness = 1.05
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = fast
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles'
|
||||||
|
infill_sparse_density = 20
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 35
|
||||||
|
speed_roofing = =speed_topbottom
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = fast
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
acceleration_print = 2500
|
||||||
|
acceleration_wall_0 = 1000
|
||||||
|
inset_direction = inside_out
|
||||||
|
jerk_wall_0 = 20
|
||||||
|
speed_print = 50
|
||||||
|
speed_roofing = =math.ceil(speed_wall*(35/50))
|
||||||
|
speed_wall_0 = =math.ceil(speed_wall*(25/50))
|
||||||
|
top_bottom_thickness = =max(1.2 , layer_height * 6)
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = normal
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 30
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = normal
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
speed_infill = 50
|
||||||
|
top_bottom_thickness = 1.05
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles'
|
||||||
|
infill_sparse_density = 20
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 35
|
||||||
|
speed_roofing = =speed_topbottom
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Quick
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = quick
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__gradual_flow_enabled = False
|
||||||
|
acceleration_wall_0 = 2000
|
||||||
|
gradual_infill_step_height = =4 * layer_height
|
||||||
|
gradual_infill_steps = 3
|
||||||
|
infill_sparse_density = 40
|
||||||
|
jerk_print = 30
|
||||||
|
jerk_wall_0 = 30
|
||||||
|
speed_print = 150
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = 40
|
||||||
|
top_bottom_thickness = = 4 * layer_height
|
||||||
|
wall_thickness = =2 * line_width
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
acceleration_print = 2500
|
||||||
|
acceleration_wall_0 = 1000
|
||||||
|
inset_direction = inside_out
|
||||||
|
jerk_wall_0 = 20
|
||||||
|
speed_print = 50
|
||||||
|
speed_roofing = =math.ceil(speed_wall*(35/50))
|
||||||
|
speed_wall_0 = =math.ceil(speed_wall*(25/50))
|
||||||
|
top_bottom_thickness = =max(1.2 , layer_height * 6)
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_petg
|
||||||
|
quality_type = fast
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles'
|
||||||
|
infill_sparse_density = 20
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 35
|
||||||
|
speed_roofing = =speed_topbottom
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_petg
|
||||||
|
quality_type = normal
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 30
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_petg
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles'
|
||||||
|
infill_sparse_density = 20
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 35
|
||||||
|
speed_roofing = =speed_topbottom
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Quick
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = quick
|
||||||
|
material = ultimaker_petg
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__gradual_flow_enabled = False
|
||||||
|
acceleration_wall_0 = 2000
|
||||||
|
gradual_infill_step_height = =4 * layer_height
|
||||||
|
gradual_infill_steps = 3
|
||||||
|
infill_sparse_density = 40
|
||||||
|
jerk_print = 30
|
||||||
|
jerk_wall_0 = 30
|
||||||
|
speed_print = 150
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = 40
|
||||||
|
top_bottom_thickness = = 4 * layer_height
|
||||||
|
wall_thickness = =2 * line_width
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_petg
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
acceleration_print = 2500
|
||||||
|
acceleration_wall_0 = 1000
|
||||||
|
inset_direction = inside_out
|
||||||
|
jerk_wall_0 = 20
|
||||||
|
speed_print = 50
|
||||||
|
speed_roofing = =math.ceil(speed_wall*(35/50))
|
||||||
|
speed_wall_0 = =math.ceil(speed_wall*(25/50))
|
||||||
|
top_bottom_thickness = =max(1.2 , layer_height * 6)
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_pla
|
||||||
|
quality_type = high
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
speed_infill = 50
|
||||||
|
top_bottom_thickness = 1.05
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_pla
|
||||||
|
quality_type = fast
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles'
|
||||||
|
infill_sparse_density = 20
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 35
|
||||||
|
speed_roofing = =speed_topbottom
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_pla
|
||||||
|
quality_type = fast
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
acceleration_print = 2500
|
||||||
|
acceleration_wall_0 = 1000
|
||||||
|
inset_direction = inside_out
|
||||||
|
jerk_wall_0 = 20
|
||||||
|
speed_print = 50
|
||||||
|
speed_roofing = =math.ceil(speed_wall*(35/50))
|
||||||
|
speed_wall_0 = =math.ceil(speed_wall*(25/50))
|
||||||
|
top_bottom_thickness = =max(1.2 , layer_height * 6)
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_pla
|
||||||
|
quality_type = normal
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 30
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_pla
|
||||||
|
quality_type = normal
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
speed_infill = 50
|
||||||
|
top_bottom_thickness = 1.05
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_pla
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles'
|
||||||
|
infill_sparse_density = 20
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 35
|
||||||
|
speed_roofing = =speed_topbottom
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Quick
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = quick
|
||||||
|
material = ultimaker_pla
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__gradual_flow_enabled = False
|
||||||
|
acceleration_wall_0 = 2000
|
||||||
|
gradual_infill_step_height = =4 * layer_height
|
||||||
|
gradual_infill_steps = 3
|
||||||
|
infill_sparse_density = 40
|
||||||
|
jerk_print = 30
|
||||||
|
jerk_wall_0 = 30
|
||||||
|
speed_print = 150
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = 40
|
||||||
|
top_bottom_thickness = = 4 * layer_height
|
||||||
|
wall_thickness = =2 * line_width
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_pla
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
acceleration_print = 2500
|
||||||
|
acceleration_wall_0 = 1000
|
||||||
|
inset_direction = inside_out
|
||||||
|
jerk_wall_0 = 20
|
||||||
|
speed_print = 50
|
||||||
|
speed_roofing = =math.ceil(speed_wall*(35/50))
|
||||||
|
speed_wall_0 = =math.ceil(speed_wall*(25/50))
|
||||||
|
top_bottom_thickness = =max(1.2 , layer_height * 6)
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Quick
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = quick
|
||||||
|
is_experimental = True
|
||||||
|
material = ultimaker_pla
|
||||||
|
quality_type = verydraft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__gradual_flow_enabled = False
|
||||||
|
acceleration_wall_0 = 2000
|
||||||
|
gradual_infill_step_height = =4 * layer_height
|
||||||
|
gradual_infill_steps = 3
|
||||||
|
infill_sparse_density = 40
|
||||||
|
jerk_print = 30
|
||||||
|
jerk_wall_0 = 30
|
||||||
|
speed_print = 150
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = 40
|
||||||
|
top_bottom_thickness = = 4 * layer_height
|
||||||
|
wall_thickness = =2 * line_width
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_tough_pla
|
||||||
|
quality_type = high
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
speed_infill = 50
|
||||||
|
top_bottom_thickness = 1.05
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_tough_pla
|
||||||
|
quality_type = fast
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles'
|
||||||
|
infill_sparse_density = 20
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 35
|
||||||
|
speed_roofing = =speed_topbottom
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_tough_pla
|
||||||
|
quality_type = fast
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
acceleration_print = 2500
|
||||||
|
acceleration_wall_0 = 1000
|
||||||
|
inset_direction = inside_out
|
||||||
|
jerk_wall_0 = 20
|
||||||
|
speed_print = 50
|
||||||
|
speed_roofing = =math.ceil(speed_wall*(35/50))
|
||||||
|
speed_wall_0 = =math.ceil(speed_wall*(25/50))
|
||||||
|
top_bottom_thickness = =max(1.2 , layer_height * 6)
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_tough_pla
|
||||||
|
quality_type = normal
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 30
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_tough_pla
|
||||||
|
quality_type = normal
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
speed_infill = 50
|
||||||
|
top_bottom_thickness = 1.05
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_tough_pla
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles'
|
||||||
|
infill_sparse_density = 20
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 35
|
||||||
|
speed_roofing = =speed_topbottom
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Quick
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = quick
|
||||||
|
material = ultimaker_tough_pla
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__gradual_flow_enabled = False
|
||||||
|
acceleration_wall_0 = 2000
|
||||||
|
gradual_infill_step_height = =4 * layer_height
|
||||||
|
gradual_infill_steps = 3
|
||||||
|
infill_sparse_density = 40
|
||||||
|
jerk_print = 30
|
||||||
|
jerk_wall_0 = 30
|
||||||
|
speed_print = 150
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = 40
|
||||||
|
top_bottom_thickness = = 4 * layer_height
|
||||||
|
wall_thickness = =2 * line_width
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_tough_pla
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
acceleration_print = 2500
|
||||||
|
acceleration_wall_0 = 1000
|
||||||
|
inset_direction = inside_out
|
||||||
|
jerk_wall_0 = 20
|
||||||
|
speed_print = 50
|
||||||
|
speed_roofing = =math.ceil(speed_wall*(35/50))
|
||||||
|
speed_wall_0 = =math.ceil(speed_wall*(25/50))
|
||||||
|
top_bottom_thickness = =max(1.2 , layer_height * 6)
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Quick
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = quick
|
||||||
|
is_experimental = True
|
||||||
|
material = ultimaker_tough_pla
|
||||||
|
quality_type = verydraft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__gradual_flow_enabled = False
|
||||||
|
acceleration_wall_0 = 2000
|
||||||
|
gradual_infill_step_height = =4 * layer_height
|
||||||
|
gradual_infill_steps = 3
|
||||||
|
infill_sparse_density = 40
|
||||||
|
jerk_print = 30
|
||||||
|
jerk_wall_0 = 30
|
||||||
|
speed_print = 150
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = 40
|
||||||
|
top_bottom_thickness = = 4 * layer_height
|
||||||
|
wall_thickness = =2 * line_width
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.8
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles'
|
||||||
|
infill_sparse_density = 20
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 35
|
||||||
|
speed_roofing = =speed_topbottom
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Quick
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = quick
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.8
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__gradual_flow_enabled = False
|
||||||
|
acceleration_wall_0 = 2000
|
||||||
|
gradual_infill_step_height = =4 * layer_height
|
||||||
|
gradual_infill_steps = 3
|
||||||
|
infill_sparse_density = 40
|
||||||
|
jerk_print = 30
|
||||||
|
jerk_wall_0 = 30
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = 40
|
||||||
|
top_bottom_thickness = = 4 * layer_height
|
||||||
|
wall_thickness = =wall_line_width_0
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.8
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
acceleration_print = 2500
|
||||||
|
acceleration_wall_0 = 1000
|
||||||
|
inset_direction = inside_out
|
||||||
|
jerk_wall_0 = 20
|
||||||
|
speed_print = 50
|
||||||
|
speed_roofing = =math.ceil(speed_wall*(35/50))
|
||||||
|
speed_wall_0 = =math.ceil(speed_wall*(25/50))
|
||||||
|
top_bottom_thickness = =max(1.2 , layer_height * 6)
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_petg
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.8
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles'
|
||||||
|
infill_sparse_density = 20
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 35
|
||||||
|
speed_roofing = =speed_topbottom
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Quick
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = quick
|
||||||
|
material = ultimaker_petg
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.8
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__gradual_flow_enabled = False
|
||||||
|
acceleration_wall_0 = 2000
|
||||||
|
gradual_infill_step_height = =4 * layer_height
|
||||||
|
gradual_infill_steps = 3
|
||||||
|
infill_sparse_density = 40
|
||||||
|
jerk_print = 30
|
||||||
|
jerk_wall_0 = 30
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = 40
|
||||||
|
top_bottom_thickness = = 4 * layer_height
|
||||||
|
wall_thickness = =wall_line_width_0
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_petg
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.8
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
acceleration_print = 2500
|
||||||
|
acceleration_wall_0 = 1000
|
||||||
|
inset_direction = inside_out
|
||||||
|
jerk_wall_0 = 20
|
||||||
|
speed_print = 50
|
||||||
|
speed_roofing = =math.ceil(speed_wall*(35/50))
|
||||||
|
speed_wall_0 = =math.ceil(speed_wall*(25/50))
|
||||||
|
top_bottom_thickness = =max(1.2 , layer_height * 6)
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_pla
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.8
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles'
|
||||||
|
infill_sparse_density = 20
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 35
|
||||||
|
speed_roofing = =speed_topbottom
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Quick
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = quick
|
||||||
|
material = ultimaker_pla
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.8
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__gradual_flow_enabled = False
|
||||||
|
acceleration_wall_0 = 2000
|
||||||
|
gradual_infill_step_height = =4 * layer_height
|
||||||
|
gradual_infill_steps = 3
|
||||||
|
infill_sparse_density = 40
|
||||||
|
jerk_print = 30
|
||||||
|
jerk_wall_0 = 30
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = 40
|
||||||
|
top_bottom_thickness = = 4 * layer_height
|
||||||
|
wall_thickness = =wall_line_width_0
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_pla
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.8
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
acceleration_print = 2500
|
||||||
|
acceleration_wall_0 = 1000
|
||||||
|
inset_direction = inside_out
|
||||||
|
jerk_wall_0 = 20
|
||||||
|
speed_print = 50
|
||||||
|
speed_roofing = =math.ceil(speed_wall*(35/50))
|
||||||
|
speed_wall_0 = =math.ceil(speed_wall*(25/50))
|
||||||
|
top_bottom_thickness = =max(1.2 , layer_height * 6)
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_tough_pla
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.8
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles'
|
||||||
|
infill_sparse_density = 20
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 35
|
||||||
|
speed_roofing = =speed_topbottom
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Quick
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = quick
|
||||||
|
material = ultimaker_tough_pla
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.8
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__gradual_flow_enabled = False
|
||||||
|
acceleration_wall_0 = 2000
|
||||||
|
gradual_infill_step_height = =4 * layer_height
|
||||||
|
gradual_infill_steps = 3
|
||||||
|
infill_sparse_density = 40
|
||||||
|
jerk_print = 30
|
||||||
|
jerk_wall_0 = 30
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = 40
|
||||||
|
top_bottom_thickness = = 4 * layer_height
|
||||||
|
wall_thickness = =wall_line_width_0
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s3
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_tough_pla
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.8
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
acceleration_print = 2500
|
||||||
|
acceleration_wall_0 = 1000
|
||||||
|
inset_direction = inside_out
|
||||||
|
jerk_wall_0 = 20
|
||||||
|
speed_print = 50
|
||||||
|
speed_roofing = =math.ceil(speed_wall*(35/50))
|
||||||
|
speed_wall_0 = =math.ceil(speed_wall*(25/50))
|
||||||
|
top_bottom_thickness = =max(1.2 , layer_height * 6)
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s5
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = high
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
speed_infill = 50
|
||||||
|
top_bottom_thickness = 1.05
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s5
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = fast
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles'
|
||||||
|
infill_sparse_density = 20
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 35
|
||||||
|
speed_roofing = =speed_topbottom
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s5
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = fast
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
acceleration_print = 2500
|
||||||
|
acceleration_wall_0 = 1000
|
||||||
|
inset_direction = inside_out
|
||||||
|
jerk_wall_0 = 20
|
||||||
|
speed_print = 50
|
||||||
|
speed_roofing = =math.ceil(speed_wall*(35/50))
|
||||||
|
speed_wall_0 = =math.ceil(speed_wall*(25/50))
|
||||||
|
top_bottom_thickness = =max(1.2 , layer_height * 6)
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s5
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = normal
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 30
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s5
|
||||||
|
name = Visual
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = visual
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = normal
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
speed_infill = 50
|
||||||
|
top_bottom_thickness = 1.05
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[general]
|
||||||
|
definition = ultimaker_s5
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
material = ultimaker_abs
|
||||||
|
quality_type = draft
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = AA 0.4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 1
|
||||||
|
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles'
|
||||||
|
infill_sparse_density = 20
|
||||||
|
jerk_print = 30
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 35
|
||||||
|
speed_roofing = =speed_topbottom
|
||||||
|
speed_topbottom = =speed_print
|
||||||
|
speed_wall = =speed_print
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue